Index: services/service_manager/service_manager.cc |
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc |
index 63a0d7c487a7b22bf06e1f7708fed8e498a9d791..a7e11851647d31f8ea7a2ab724549b60a3edaaa8 100644 |
--- a/services/service_manager/service_manager.cc |
+++ b/services/service_manager/service_manager.cc |
@@ -47,6 +47,34 @@ const char kCapability_InstancePerChild[] = |
"service_manager:instance_per_child"; |
const char kCapability_ServiceManager[] = "service_manager:service_manager"; |
+bool Succeeded(mojom::ConnectResult result) { |
+ return result == mojom::ConnectResult::SUCCEEDED; |
+} |
+ |
+bool RunConnectCallback(ConnectParams* params, |
+ mojom::ConnectResult result, |
+ const std::string& user_id) { |
+ if (!params->connect_callback().is_null()) { |
+ params->connect_callback().Run(result, user_id); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+void RunBindInterfaceCallback(ConnectParams* params, |
+ mojom::ConnectResult result, |
+ const std::string& user_id) { |
+ if (!params->bind_interface_callback().is_null()) |
+ params->bind_interface_callback().Run(result, user_id); |
+} |
+ |
+void RunCallback(ConnectParams* params, |
+ mojom::ConnectResult result, |
+ const std::string& user_id) { |
+ if (!RunConnectCallback(params, result, user_id)) |
+ RunBindInterfaceCallback(params, result, user_id); |
+} |
+ |
} // namespace |
Identity CreateServiceManagerIdentity() { |
@@ -125,18 +153,20 @@ class ServiceManager::Instance |
Stop(); |
} |
- bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) { |
- if (!service_.is_bound()) |
+ bool OnConnect(std::unique_ptr<ConnectParams>* in_params) { |
+ if (!service_.is_bound()) { |
+ RunConnectCallback(in_params->get(), mojom::ConnectResult::ACCESS_DENIED, |
+ identity_.user_id()); |
return false; |
- |
- std::unique_ptr<ConnectParams> params(std::move(*connect_params)); |
- if (!params->connect_callback().is_null()) { |
- params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED, |
- identity_.user_id()); |
} |
+ std::unique_ptr<ConnectParams> params(std::move(*in_params)); |
+ RunConnectCallback(params.get(), mojom::ConnectResult::SUCCEEDED, |
+ identity_.user_id()); |
+ |
InterfaceProviderSpecMap specs; |
- Instance* source = service_manager_->GetExistingInstance(params->source()); |
+ Instance* source = |
+ service_manager_->GetExistingInstance(params->source()); |
if (source) |
specs = source->interface_provider_specs_; |
@@ -148,6 +178,52 @@ class ServiceManager::Instance |
return true; |
} |
+ bool OnBindInterface(std::unique_ptr<ConnectParams>* in_params) { |
+ if (!service_.is_bound()) { |
+ RunBindInterfaceCallback(in_params->get(), |
+ mojom::ConnectResult::ACCESS_DENIED, |
+ identity_.user_id()); |
+ return false; |
+ } |
+ |
+ std::unique_ptr<ConnectParams> params(std::move(*in_params)); |
+ InterfaceProviderSpecMap source_specs; |
+ InterfaceProviderSpec source_connection_spec; |
+ Instance* source = |
+ service_manager_->GetExistingInstance(params->source()); |
+ if (source) { |
+ source_specs = source->interface_provider_specs_; |
+ source_connection_spec = source->GetConnectionSpec(); |
+ } |
+ |
+ InterfaceSet exposed = GetInterfacesToExpose(source_connection_spec, |
+ identity_, |
+ GetConnectionSpec()); |
+ bool allowed = (exposed.size() == 1 && exposed.count("*") == 1) || |
+ exposed.count(params->interface_name()) > 0; |
+ if (!allowed) { |
+ std::stringstream ss; |
+ ss << "Connection InterfaceProviderSpec prevented service: " |
+ << params->source().name() << " from binding interface: " |
+ << params->interface_name() << " exposed by: " << identity_.name(); |
+ LOG(ERROR) << ss.str(); |
+ params->bind_interface_callback().Run(mojom::ConnectResult::ACCESS_DENIED, |
+ identity_.user_id()); |
+ return false; |
+ } |
+ |
+ params->bind_interface_callback().Run(mojom::ConnectResult::SUCCEEDED, |
+ identity_.user_id()); |
+ |
+ pending_service_connections_++; |
+ service_->OnBindInterface( |
+ ServiceInfo(params->source(), source_specs), |
+ params->interface_name(), |
+ params->TakeInterfaceRequestPipe(), |
+ base::Bind(&Instance::OnConnectComplete, base::Unretained(this))); |
+ return true; |
+ } |
+ |
void OnConnectComplete() { |
DCHECK_GT(pending_service_connections_, 0); |
pending_service_connections_--; |
@@ -229,72 +305,65 @@ class ServiceManager::Instance |
// mojom::Connector implementation: |
void StartService( |
- const Identity& target, |
+ const Identity& in_target, |
mojo::ScopedMessagePipeHandle service_handle, |
mojom::PIDReceiverRequest pid_receiver_request) override { |
+ Identity target = in_target; |
+ mojom::ConnectResult result = |
+ ValidateConnectParams(&target, nullptr, nullptr); |
+ if (!Succeeded(result)) |
+ return; |
+ |
+ std::unique_ptr<ConnectParams> params(new ConnectParams); |
+ params->set_source(identity_); |
+ params->set_target(target); |
+ |
mojom::ServicePtr service; |
service.Bind(mojom::ServicePtrInfo(std::move(service_handle), 0)); |
- ConnectImpl( |
- target, |
- mojom::InterfaceProviderRequest(), |
- std::move(service), |
- std::move(pid_receiver_request), |
- base::Bind( |
- &service_manager::ServiceManager::Instance::EmptyConnectCallback, |
- weak_factory_.GetWeakPtr())); |
+ params->set_client_process_info(std::move(service), |
+ std::move(pid_receiver_request)); |
+ service_manager_->Connect( |
+ std::move(params), nullptr, weak_factory_.GetWeakPtr()); |
} |
- void Connect(const service_manager::Identity& target, |
+ void Connect(const service_manager::Identity& in_target, |
mojom::InterfaceProviderRequest remote_interfaces, |
const ConnectCallback& callback) override { |
- ConnectImpl(target, std::move(remote_interfaces), mojom::ServicePtr(), |
- mojom::PIDReceiverRequest(), callback); |
+ Identity target = in_target; |
+ mojom::ConnectResult result = |
+ ValidateConnectParams(&target, nullptr, nullptr); |
+ if (!Succeeded(result)) { |
+ callback.Run(result, mojom::kInheritUserID); |
+ return; |
+ } |
+ |
+ std::unique_ptr<ConnectParams> params(new ConnectParams); |
+ params->set_source(identity_); |
+ params->set_target(target); |
+ params->set_remote_interfaces(std::move(remote_interfaces)); |
+ params->set_connect_callback(callback); |
+ service_manager_->Connect( |
+ std::move(params), nullptr, weak_factory_.GetWeakPtr()); |
} |
- void BindInterface(const service_manager::Identity& target, |
+ void BindInterface(const service_manager::Identity& in_target, |
const std::string& interface_name, |
mojo::ScopedMessagePipeHandle interface_pipe, |
const BindInterfaceCallback& callback) override { |
- mojom::InterfaceProviderPtr remote_interfaces; |
- ConnectImpl( |
- target, |
- MakeRequest(&remote_interfaces), |
- mojom::ServicePtr(), |
- mojom::PIDReceiverRequest(), |
- base::Bind( |
- &service_manager::ServiceManager::Instance::BindCallbackWrapper, |
- weak_factory_.GetWeakPtr(), |
- callback)); |
- remote_interfaces->GetInterface(interface_name, std::move(interface_pipe)); |
- // TODO(beng): Rather than just forwarding thru to InterfaceProvider, do |
- // manifest policy intersection here. |
- } |
- |
- void ConnectImpl(const service_manager::Identity& in_target, |
- mojom::InterfaceProviderRequest remote_interfaces, |
- mojom::ServicePtr service, |
- mojom::PIDReceiverRequest pid_receiver_request, |
- const ConnectCallback& callback) { |
Identity target = in_target; |
- if (target.user_id() == mojom::kInheritUserID) |
- target.set_user_id(identity_.user_id()); |
- |
- if (!ValidateIdentity(target, callback)) |
- return; |
- if (!ValidateClientProcessInfo(&service, &pid_receiver_request, target, |
- callback)) { |
+ mojom::ConnectResult result = |
+ ValidateConnectParams(&target, nullptr, nullptr); |
+ if (!Succeeded(result)) { |
+ callback.Run(result, mojom::kInheritUserID); |
return; |
} |
- if (!ValidateConnectionSpec(target, callback)) |
- return; |
std::unique_ptr<ConnectParams> params(new ConnectParams); |
params->set_source(identity_); |
params->set_target(target); |
- params->set_remote_interfaces(std::move(remote_interfaces)); |
- params->set_client_process_info(std::move(service), |
- std::move(pid_receiver_request)); |
- params->set_connect_callback(callback); |
+ params->set_interface_request_info(interface_name, |
+ std::move(interface_pipe)); |
+ params->set_bind_interface_callback(callback); |
service_manager_->Connect( |
std::move(params), nullptr, weak_factory_.GetWeakPtr()); |
} |
@@ -321,61 +390,66 @@ class ServiceManager::Instance |
service_manager_->AddListener(std::move(listener)); |
} |
- bool ValidateIdentity(const Identity& identity, |
- const ConnectCallback& callback) { |
+ mojom::ConnectResult ValidateConnectParams( |
+ Identity* target, |
+ mojom::ServicePtr* service, |
+ mojom::PIDReceiverRequest* pid_receiver_request) { |
+ if (target->user_id() == mojom::kInheritUserID) |
+ target->set_user_id(identity_.user_id()); |
+ |
+ mojom::ConnectResult result = ValidateIdentity(*target); |
+ if (!Succeeded(result)) |
+ return result; |
+ |
+ result = ValidateClientProcessInfo(service, pid_receiver_request, *target); |
+ if (!Succeeded(result)) |
+ return result; |
+ return ValidateConnectionSpec(*target); |
+ } |
+ |
+ mojom::ConnectResult ValidateIdentity(const Identity& identity) { |
if (identity.name().empty()) { |
LOG(ERROR) << "Error: empty service name."; |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::INVALID_ARGUMENT; |
} |
if (!base::IsValidGUID(identity.user_id())) { |
LOG(ERROR) << "Error: invalid user_id: " << identity.user_id(); |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::INVALID_ARGUMENT; |
} |
- return true; |
+ return mojom::ConnectResult::SUCCEEDED; |
} |
- bool ValidateClientProcessInfo( |
+ mojom::ConnectResult ValidateClientProcessInfo( |
mojom::ServicePtr* service, |
mojom::PIDReceiverRequest* pid_receiver_request, |
- const Identity& target, |
- const ConnectCallback& callback) { |
- if (service->is_bound() || pid_receiver_request->is_pending()) { |
+ const Identity& target) { |
+ if (service && pid_receiver_request && |
+ (service->is_bound() || pid_receiver_request->is_pending())) { |
if (!HasCapability(GetConnectionSpec(), kCapability_ClientProcess)) { |
LOG(ERROR) << "Instance: " << identity_.name() << " attempting " |
<< "to register an instance for a process it created for " |
<< "target: " << target.name() << " without the " |
<< "service_manager{client_process} capability " |
<< "class."; |
- callback.Run(mojom::ConnectResult::ACCESS_DENIED, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::ACCESS_DENIED; |
} |
if (!service->is_bound() || !pid_receiver_request->is_pending()) { |
LOG(ERROR) << "Must supply both service AND " |
<< "pid_receiver_request when sending client process info"; |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::INVALID_ARGUMENT; |
} |
if (service_manager_->GetExistingInstance(target)) { |
LOG(ERROR) << "Cannot client process matching existing identity:" |
<< "Name: " << target.name() << " User: " |
<< target.user_id() << " Instance: " << target.instance(); |
- callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::INVALID_ARGUMENT; |
} |
} |
- return true; |
+ return mojom::ConnectResult::SUCCEEDED; |
} |
- bool ValidateConnectionSpec(const Identity& target, |
- const ConnectCallback& callback) { |
+ mojom::ConnectResult ValidateConnectionSpec(const Identity& target) { |
InterfaceProviderSpec connection_spec = GetConnectionSpec(); |
// TODO(beng): Need to do the following additional policy validation of |
// whether this instance is allowed to connect using: |
@@ -388,9 +462,7 @@ class ServiceManager::Instance |
<< " attempting to connect to: " << target.name() |
<< " as: " << target.user_id() << " without " |
<< " the service:service_manager{user_id} capability."; |
- callback.Run(mojom::ConnectResult::ACCESS_DENIED, |
- mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::ACCESS_DENIED; |
} |
if (!target.instance().empty() && |
target.instance() != target.name() && |
@@ -400,19 +472,17 @@ class ServiceManager::Instance |
<< " using Instance name: " << target.instance() |
<< " without the " |
<< "service_manager{instance_name} capability."; |
- callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::ACCESS_DENIED; |
} |
if (allow_any_application_ || |
connection_spec.requires.find(target.name()) != |
connection_spec.requires.end()) { |
- return true; |
+ return mojom::ConnectResult::SUCCEEDED; |
} |
LOG(ERROR) << "InterfaceProviderSpec prevented connection from: " |
<< identity_.name() << " to: " << target.name(); |
- callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID); |
- return false; |
+ return mojom::ConnectResult::ACCESS_DENIED; |
} |
uint32_t GenerateUniqueID() const { |
@@ -782,7 +852,14 @@ void ServiceManager::NotifyServiceFailedToStart(const Identity& identity) { |
bool ServiceManager::ConnectToExistingInstance( |
std::unique_ptr<ConnectParams>* params) { |
Instance* instance = GetExistingInstance((*params)->target()); |
- return instance && instance->ConnectToService(params); |
+ if (instance) { |
+ if ((*params)->HasInterfaceRequestInfo()) { |
+ instance->OnBindInterface(params); |
+ return true; |
+ } |
+ return instance->OnConnect(params); |
+ } |
+ return false; |
} |
ServiceManager::Instance* ServiceManager::CreateInstance( |
@@ -868,10 +945,7 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params, |
// If name resolution failed, we drop the connection. |
if (!result) { |
LOG(ERROR) << "Failed to resolve service name: " << params->target().name(); |
- if (!params->connect_callback().is_null()) { |
- params->connect_callback().Run( |
- mojom::ConnectResult::INVALID_ARGUMENT, ""); |
- } |
+ RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, ""); |
return; |
} |
@@ -941,8 +1015,7 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params, |
LOG(ERROR) |
<< "Error: The catalog was unable to read a manifest for service \"" |
<< result->name << "\"."; |
- if (!params->connect_callback().is_null()) |
- params->connect_callback().Run(mojom::ConnectResult::ACCESS_DENIED, ""); |
+ RunCallback(params.get(), mojom::ConnectResult::ACCESS_DENIED, ""); |
return; |
} |
@@ -980,18 +1053,19 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params, |
if (!instance->StartWithFilePath(package_path)) { |
OnInstanceError(instance); |
- if (!params->connect_callback().is_null()) { |
- params->connect_callback().Run( |
- mojom::ConnectResult::INVALID_ARGUMENT, ""); |
- } |
+ RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, ""); |
return; |
} |
} |
} |
// Now that the instance has a Service, we can connect to it. |
- bool connected = instance->ConnectToService(¶ms); |
- DCHECK(connected); |
+ if (params->HasInterfaceRequestInfo()) { |
+ instance->OnBindInterface(¶ms); |
+ } else { |
+ bool connected = instance->OnConnect(¶ms); |
+ DCHECK(connected); |
+ } |
} |
base::WeakPtr<ServiceManager> ServiceManager::GetWeakPtr() { |