Commit 6d56c5ad authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Reland "[service-manager] Simplify connection logic"

This is a reland of 18526eed

Diff PS3->PS4 is fix for breakage.

Original change's description:
> [service-manager] Simplify connection logic
>
> This reduces the complexity of Service Manager's logic for handling
> interconnection between service instances. Much of the complexity was
> due to connection operations once upon a time being highly
> asynchronous within SM, but that hasn't been the case for a while.
>
> Rather than having ServiceManager::Connect do way too much stuff, it's
> replaced with a simpler and more straightforward
> FindOrCreateMatchingTargetInstance, which does only what the name says.
> Previous work done by Connect() in various edge cases has been moved out
> to its prior call sites, now replaced with calls to FOCMTI.
>
> Bug: 904240
> Change-Id: Ia276f6fa61477ddc141724d30484237498eef070
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1593722
> Reviewed-by: Oksana Zhuravlova <oksamyt@chromium.org>
> Commit-Queue: Ken Rockot <rockot@google.com>
> Cr-Commit-Position: refs/heads/master@{#657401}

Bug: 904240
Change-Id: If07ff20dd8886901013f214f8b51a9e447224189
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1600453Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#657746}
parent ae8ee33c
...@@ -220,7 +220,7 @@ void ServiceInstance::StartWithRemote( ...@@ -220,7 +220,7 @@ void ServiceInstance::StartWithRemote(
base::BindOnce(&ServiceInstance::OnStartCompleted, base::BindOnce(&ServiceInstance::OnStartCompleted,
base::Unretained(this))); base::Unretained(this)));
service_manager_->NotifyServiceCreated(this); service_manager_->NotifyServiceCreated(*this);
} }
bool ServiceInstance::StartWithExecutablePath(const base::FilePath& path, bool ServiceInstance::StartWithExecutablePath(const base::FilePath& path,
...@@ -246,30 +246,24 @@ bool ServiceInstance::StartWithExecutablePath(const base::FilePath& path, ...@@ -246,30 +246,24 @@ bool ServiceInstance::StartWithExecutablePath(const base::FilePath& path,
#endif #endif
} }
void ServiceInstance::AuthorizeAndForwardConnectionRequestFromOtherService( bool ServiceInstance::MaybeAcceptConnectionRequest(
const Identity& source_identity, const ServiceInstance& source_instance,
const std::string& interface_name, const std::string& interface_name,
mojo::ScopedMessagePipeHandle receiving_pipe, mojo::ScopedMessagePipeHandle receiving_pipe,
mojom::BindInterfacePriority priority, mojom::BindInterfacePriority priority) {
mojom::Connector::BindInterfaceCallback callback) { if (state_ == mojom::InstanceState::kUnreachable)
ServiceInstance* const source = return false;
service_manager_->GetExistingInstance(source_identity);
if (!source || state_ == mojom::InstanceState::kUnreachable) {
std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, identity_);
return;
}
const Manifest& source_manifest = source->manifest(); const Manifest& source_manifest = source_instance.manifest();
const bool bindable_on_any_service = base::ContainsKey( const bool bindable_on_any_service = base::ContainsKey(
source_manifest.interfaces_bindable_on_any_service, interface_name); source_manifest.interfaces_bindable_on_any_service, interface_name);
const bool allowed_by_capabilities = const bool allowed_by_capabilities =
AllowsInterface(source_manifest.required_capabilities, identity_.name(), AllowsInterface(source_manifest.required_capabilities, identity_.name(),
manifest_.exposed_capabilities, interface_name); manifest_.exposed_capabilities, interface_name);
if (!bindable_on_any_service && !allowed_by_capabilities) { if (!bindable_on_any_service && !allowed_by_capabilities) {
ReportBlockedInterface(source_identity.name(), identity_.name(), ReportBlockedInterface(source_instance.identity().name(), identity_.name(),
interface_name); interface_name);
std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, identity_); return false;
return;
} }
base::OnceClosure on_bind_interface_complete; base::OnceClosure on_bind_interface_complete;
...@@ -280,13 +274,14 @@ void ServiceInstance::AuthorizeAndForwardConnectionRequestFromOtherService( ...@@ -280,13 +274,14 @@ void ServiceInstance::AuthorizeAndForwardConnectionRequestFromOtherService(
} }
service_remote_->OnBindInterface( service_remote_->OnBindInterface(
BindSourceInfo(source_identity, GetRequiredCapabilities( BindSourceInfo(
source_manifest.required_capabilities, source_instance.identity(),
GetRequiredCapabilities(source_manifest.required_capabilities,
identity_.name())), identity_.name())),
interface_name, std::move(receiving_pipe), interface_name, std::move(receiving_pipe),
std::move(on_bind_interface_complete)); std::move(on_bind_interface_complete));
std::move(callback).Run(mojom::ConnectResult::SUCCEEDED, identity_); return true;
} }
void ServiceInstance::Stop() { void ServiceInstance::Stop() {
...@@ -379,12 +374,12 @@ void ServiceInstance::HandleServiceOrConnectorDisconnection() { ...@@ -379,12 +374,12 @@ void ServiceInstance::HandleServiceOrConnectorDisconnection() {
} }
} }
mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService( bool ServiceInstance::CanConnectToOtherInstance(
const ServiceFilter& target_filter, const ServiceFilter& target_filter,
const base::Optional<std::string>& target_interface_name) { const base::Optional<std::string>& target_interface_name) {
if (target_filter.service_name().empty()) { if (target_filter.service_name().empty()) {
DLOG(ERROR) << "ServiceFilter has no service name."; DLOG(ERROR) << "ServiceFilter has no service name.";
return mojom::ConnectResult::INVALID_ARGUMENT; return false;
} }
bool skip_instance_group_check = bool skip_instance_group_check =
...@@ -402,7 +397,7 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService( ...@@ -402,7 +397,7 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService(
<< "group " << target_filter.instance_group()->ToString() << "group " << target_filter.instance_group()->ToString()
<< " without |can_connect_to_instances_in_any_group| set to " << " without |can_connect_to_instances_in_any_group| set to "
<< "|true|."; << "|true|.";
return mojom::ConnectResult::ACCESS_DENIED; return false;
} }
if (target_filter.instance_id() && !target_filter.instance_id()->is_zero() && if (target_filter.instance_id() && !target_filter.instance_id()->is_zero() &&
!manifest_.options.can_connect_to_instances_with_any_id) { !manifest_.options.can_connect_to_instances_with_any_id) {
...@@ -411,14 +406,14 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService( ...@@ -411,14 +406,14 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService(
<< " with instance ID " << " with instance ID "
<< target_filter.instance_id()->ToString() << " without " << target_filter.instance_id()->ToString() << " without "
<< "|can_connect_to_instances_with_any_id| set to |true|."; << "|can_connect_to_instances_with_any_id| set to |true|.";
return mojom::ConnectResult::ACCESS_DENIED; return false;
} }
if (can_contact_all_services_ || if (can_contact_all_services_ ||
!manifest_.interfaces_bindable_on_any_service.empty() || !manifest_.interfaces_bindable_on_any_service.empty() ||
manifest_.required_capabilities.find(target_filter.service_name()) != manifest_.required_capabilities.find(target_filter.service_name()) !=
manifest_.required_capabilities.end()) { manifest_.required_capabilities.end()) {
return mojom::ConnectResult::SUCCEEDED; return true;
} }
if (target_interface_name) { if (target_interface_name) {
...@@ -428,7 +423,7 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService( ...@@ -428,7 +423,7 @@ mojom::ConnectResult ServiceInstance::ValidateConnectionRequestToOtherService(
ReportBlockedStartService(identity_.name(), target_filter.service_name()); ReportBlockedStartService(identity_.name(), target_filter.service_name());
} }
return mojom::ConnectResult::ACCESS_DENIED; return false;
} }
void ServiceInstance::BindInterface( void ServiceInstance::BindInterface(
...@@ -437,16 +432,25 @@ void ServiceInstance::BindInterface( ...@@ -437,16 +432,25 @@ void ServiceInstance::BindInterface(
mojo::ScopedMessagePipeHandle receiving_pipe, mojo::ScopedMessagePipeHandle receiving_pipe,
mojom::BindInterfacePriority priority, mojom::BindInterfacePriority priority,
BindInterfaceCallback callback) { BindInterfaceCallback callback) {
mojom::ConnectResult result = if (!CanConnectToOtherInstance(target_filter, interface_name)) {
ValidateConnectionRequestToOtherService(target_filter, interface_name); std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, base::nullopt);
if (result != mojom::ConnectResult::SUCCEEDED) { return;
std::move(callback).Run(result, base::nullopt); }
ServiceInstance* target_instance =
service_manager_->FindOrCreateMatchingTargetInstance(*this,
target_filter);
bool allowed =
target_instance &&
target_instance->MaybeAcceptConnectionRequest(
*this, interface_name, std::move(receiving_pipe), priority);
if (!allowed) {
std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, base::nullopt);
return; return;
} }
service_manager_->Connect(target_filter, identity_, interface_name, std::move(callback).Run(mojom::ConnectResult::SUCCEEDED,
std::move(receiving_pipe), priority, target_instance->identity());
std::move(callback));
} }
void ServiceInstance::QueryService(const std::string& service_name, void ServiceInstance::QueryService(const std::string& service_name,
...@@ -462,14 +466,22 @@ void ServiceInstance::QueryService(const std::string& service_name, ...@@ -462,14 +466,22 @@ void ServiceInstance::QueryService(const std::string& service_name,
void ServiceInstance::WarmService(const ServiceFilter& target_filter, void ServiceInstance::WarmService(const ServiceFilter& target_filter,
WarmServiceCallback callback) { WarmServiceCallback callback) {
mojom::ConnectResult result = ValidateConnectionRequestToOtherService( if (!CanConnectToOtherInstance(target_filter,
target_filter, base::nullopt /* interface_name */); base::nullopt /* interface_name */)) {
if (result != mojom::ConnectResult::SUCCEEDED) { std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, base::nullopt);
std::move(callback).Run(result, base::nullopt);
return; return;
} }
service_manager_->Connect(target_filter, identity_, std::move(callback)); ServiceInstance* target_instance =
service_manager_->FindOrCreateMatchingTargetInstance(*this,
target_filter);
if (!target_instance) {
std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED, base::nullopt);
return;
}
std::move(callback).Run(mojom::ConnectResult::SUCCEEDED,
target_instance->identity());
} }
void ServiceInstance::RegisterServiceInstance( void ServiceInstance::RegisterServiceInstance(
...@@ -477,6 +489,13 @@ void ServiceInstance::RegisterServiceInstance( ...@@ -477,6 +489,13 @@ void ServiceInstance::RegisterServiceInstance(
mojo::ScopedMessagePipeHandle service_remote_handle, mojo::ScopedMessagePipeHandle service_remote_handle,
mojom::PIDReceiverRequest pid_receiver_request, mojom::PIDReceiverRequest pid_receiver_request,
RegisterServiceInstanceCallback callback) { RegisterServiceInstanceCallback callback) {
auto target_filter = ServiceFilter::ForExactIdentity(identity);
if (!CanConnectToOtherInstance(target_filter,
base::nullopt /* interface_name */)) {
std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED);
return;
}
mojo::PendingRemote<mojom::Service> service_remote( mojo::PendingRemote<mojom::Service> service_remote(
std::move(service_remote_handle), 0); std::move(service_remote_handle), 0);
...@@ -495,23 +514,13 @@ void ServiceInstance::RegisterServiceInstance( ...@@ -495,23 +514,13 @@ void ServiceInstance::RegisterServiceInstance(
return; return;
} }
auto target_filter = ServiceFilter::ForExactIdentity(identity); mojom::ServicePtr service(std::move(service_remote));
mojom::ConnectResult result = ValidateConnectionRequestToOtherService( if (!service_manager_->RegisterService(identity, std::move(service),
target_filter, base::nullopt /* interface_name */); std::move(pid_receiver_request))) {
if (result != mojom::ConnectResult::SUCCEEDED) { std::move(callback).Run(mojom::ConnectResult::ACCESS_DENIED);
std::move(callback).Run(result);
return;
} }
service_manager_->Connect(target_filter, identity_, std::move(service_remote), std::move(callback).Run(mojom::ConnectResult::SUCCEEDED);
std::move(pid_receiver_request),
base::BindOnce(
[](RegisterServiceInstanceCallback callback,
mojom::ConnectResult result,
const base::Optional<Identity>& identity) {
std::move(callback).Run(result);
},
std::move(callback)));
} }
void ServiceInstance::Clone(mojom::ConnectorRequest request) { void ServiceInstance::Clone(mojom::ConnectorRequest request) {
......
...@@ -73,14 +73,14 @@ class ServiceInstance : public mojom::Connector, ...@@ -73,14 +73,14 @@ class ServiceInstance : public mojom::Connector,
bool StartWithExecutablePath(const base::FilePath& path, bool StartWithExecutablePath(const base::FilePath& path,
SandboxType sandbox_type); SandboxType sandbox_type);
// Forwards a BindInterface request to the service instance, iff it should be // Forwards a BindInterface request from |source_instance| to this instance,
// allowed based on manifest constraints. // iff it should be allowed based on manifest constraints. Returns |true| if
void AuthorizeAndForwardConnectionRequestFromOtherService( // the request was allowed, or |false| otherwise.
const Identity& source_identity, bool MaybeAcceptConnectionRequest(
const ServiceInstance& source_instance,
const std::string& interface_name, const std::string& interface_name,
mojo::ScopedMessagePipeHandle receiving_pipe, mojo::ScopedMessagePipeHandle receiving_pipe,
mojom::BindInterfacePriority priority, mojom::BindInterfacePriority priority);
mojom::Connector::BindInterfaceCallback callback);
// Stops receiving any new messages from the service instance and renders the // Stops receiving any new messages from the service instance and renders the
// instance permanently unreachable. Note that this does NOT make any attempt // instance permanently unreachable. Note that this does NOT make any attempt
...@@ -112,10 +112,11 @@ class ServiceInstance : public mojom::Connector, ...@@ -112,10 +112,11 @@ class ServiceInstance : public mojom::Connector,
// Examines an interface connection request coming from this service instance // Examines an interface connection request coming from this service instance
// and determines whether it should be allowed to reach any designated target // and determines whether it should be allowed to reach any designated target
// instance. A return value of |mojom::ConnectResult::SUCCESS| indicates that // instance. Returns |true| if so, or |false| otherwise.
// the request can be processed further. Any other result means the request //
// should be rejected. // If |target_interface_name| is null, it is sufficient for this (the source)
mojom::ConnectResult ValidateConnectionRequestToOtherService( // service to have access to *any* arbitrary interface on the target service.
bool CanConnectToOtherInstance(
const ServiceFilter& target_filter, const ServiceFilter& target_filter,
const base::Optional<std::string>& target_interface_name); const base::Optional<std::string>& target_interface_name);
......
This diff is collapsed.
...@@ -64,7 +64,9 @@ class ServiceManager : public Service { ...@@ -64,7 +64,9 @@ class ServiceManager : public Service {
// //
// |pid_receiver_request| may be null, in which case the service manager // |pid_receiver_request| may be null, in which case the service manager
// assumes the new service is running in this process. // assumes the new service is running in this process.
void RegisterService(const Identity& identity, //
// Returns |true| if registration succeeded, or |false| otherwise.
bool RegisterService(const Identity& identity,
mojom::ServicePtr service, mojom::ServicePtr service,
mojom::PIDReceiverRequest pid_receiver_request); mojom::PIDReceiverRequest pid_receiver_request);
...@@ -74,40 +76,17 @@ class ServiceManager : public Service { ...@@ -74,40 +76,17 @@ class ServiceManager : public Service {
const base::Token& instance_group, const base::Token& instance_group,
std::string* sandbox_type); std::string* sandbox_type);
// Completes a connection between a source and target application as defined // Attempts to locate a ServiceInstance as a target for a connection request
// by |params|. If no existing instance of the target service is running, one // from |source_instance| by matching against |partial_target_filter|. If
// will be loaded. // a suitable instance exists it is returned, otherwise the Service Manager
void Connect(const ServiceFilter& partial_target_filter, // attempts to create a new suitable instance.
const Identity& source_identity, //
const base::Optional<std::string>& interface_name, // Returns null if a matching instance did not exist and could not be created,
mojo::ScopedMessagePipeHandle receiving_pipe, // otherwise returns a valid ServiceInstance which matches
mojo::PendingRemote<mojom::Service> service_remote, // |partial_target_filter| from |source_instance|'s perspective.
mojo::PendingReceiver<mojom::PIDReceiver> pid_receiver, ServiceInstance* FindOrCreateMatchingTargetInstance(
mojom::BindInterfacePriority priority, const ServiceInstance& source_instance,
mojom::Connector::BindInterfaceCallback callback); const ServiceFilter& partial_target_filter);
// Variant of the above when no Service remote or PIDReceiver is provided by
// the caller.
void Connect(const ServiceFilter& partial_target_filter,
const Identity& source_identity,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle receiving_pipe,
mojom::BindInterfacePriority priority,
mojom::Connector::BindInterfaceCallback callback);
// Variant of the above where no interface name, receiving pipe, Service
// remote, or PIDReceiver is provided by the caller.
void Connect(const ServiceFilter& partial_target_filter,
const Identity& source_identity,
mojom::Connector::BindInterfaceCallback callback);
// Variant of the above where no interface name or receiving pipe is provided
// by the caller, but a Service remote and PIDReceiver are provided.
void Connect(const ServiceFilter& partial_target_filter,
const Identity& source_identity,
mojo::PendingRemote<mojom::Service> service_remote,
mojo::PendingReceiver<mojom::PIDReceiver> pid_receiver,
mojom::Connector::BindInterfaceCallback callback);
private: private:
friend class ServiceInstance; friend class ServiceInstance;
...@@ -129,7 +108,7 @@ class ServiceManager : public Service { ...@@ -129,7 +108,7 @@ class ServiceManager : public Service {
// Returns a running instance identified by |identity|. // Returns a running instance identified by |identity|.
ServiceInstance* GetExistingInstance(const Identity& identity) const; ServiceInstance* GetExistingInstance(const Identity& identity) const;
void NotifyServiceCreated(ServiceInstance* instance); void NotifyServiceCreated(const ServiceInstance& instance);
void NotifyServiceStarted(const Identity& identity, base::ProcessId pid); void NotifyServiceStarted(const Identity& identity, base::ProcessId pid);
void NotifyServiceFailedToStart(const Identity& identity); void NotifyServiceFailedToStart(const Identity& identity);
...@@ -141,11 +120,6 @@ class ServiceManager : public Service { ...@@ -141,11 +120,6 @@ class ServiceManager : public Service {
// Called from the instance implementing mojom::ServiceManager. // Called from the instance implementing mojom::ServiceManager.
void AddListener(mojom::ServiceManagerListenerPtr listener); void AddListener(mojom::ServiceManagerListenerPtr listener);
void CreateServiceWithFactory(const ServiceFilter& service_factory_filter,
const std::string& name,
mojom::ServiceRequest request,
mojom::PIDReceiverPtr pid_receiver);
// Returns a running ServiceFactory for |filter|. If there is not one running, // Returns a running ServiceFactory for |filter|. If there is not one running,
// one is started. // one is started.
mojom::ServiceFactory* GetServiceFactory(const ServiceFilter& filter); mojom::ServiceFactory* GetServiceFactory(const ServiceFilter& filter);
......
...@@ -558,15 +558,16 @@ TEST_F(ConnectTest, MAYBE_PackagedApp_BlockedInterface) { ...@@ -558,15 +558,16 @@ TEST_F(ConnectTest, MAYBE_PackagedApp_BlockedInterface) {
// Connection to another application provided by the same package, blocked // Connection to another application provided by the same package, blocked
// because it's not in the capability filter whitelist. // because it's not in the capability filter whitelist.
TEST_F(ConnectTest, MAYBE_BlockedPackagedApplication) { TEST_F(ConnectTest, MAYBE_BlockedPackagedApplication) {
mojom::ConnectResult result;
base::RunLoop run_loop; base::RunLoop run_loop;
test::mojom::ConnectTestServicePtr service_b; test::mojom::ConnectTestServicePtr service_b;
connector()->BindInterface( connector()->BindInterface(
ServiceFilter::ByName(kTestAppBName), mojo::MakeRequest(&service_b), ServiceFilter::ByName(kTestAppBName), mojo::MakeRequest(&service_b),
base::BindOnce(&StartServiceResponse, nullptr, &result, nullptr)); base::BindLambdaForTesting([&](mojom::ConnectResult result,
service_b.set_connection_error_handler(run_loop.QuitClosure()); const base::Optional<Identity>& identity) {
run_loop.Run();
EXPECT_EQ(mojom::ConnectResult::ACCESS_DENIED, result); EXPECT_EQ(mojom::ConnectResult::ACCESS_DENIED, result);
run_loop.Quit();
}));
run_loop.Run();
} }
TEST_F(ConnectTest, CapabilityClasses) { TEST_F(ConnectTest, CapabilityClasses) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment