| Index: services/shell/service_manager.cc
|
| diff --git a/services/shell/service_manager.cc b/services/shell/service_manager.cc
|
| deleted file mode 100644
|
| index c93b23dff047f9d8e485532e7a1a4df79f344c4a..0000000000000000000000000000000000000000
|
| --- a/services/shell/service_manager.cc
|
| +++ /dev/null
|
| @@ -1,883 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "services/shell/service_manager.h"
|
| -
|
| -#include <stdint.h>
|
| -
|
| -#include <utility>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/command_line.h"
|
| -#include "base/debug/alias.h"
|
| -#include "base/guid.h"
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/process/process.h"
|
| -#include "base/process/process_handle.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/trace_event/trace_event.h"
|
| -#include "mojo/public/cpp/bindings/binding.h"
|
| -#include "mojo/public/cpp/bindings/binding_set.h"
|
| -#include "services/shell/connect_util.h"
|
| -#include "services/shell/public/cpp/connector.h"
|
| -#include "services/shell/public/cpp/names.h"
|
| -#include "services/shell/public/cpp/service_context.h"
|
| -#include "services/shell/public/interfaces/connector.mojom.h"
|
| -#include "services/shell/public/interfaces/service.mojom.h"
|
| -#include "services/shell/public/interfaces/service_manager.mojom.h"
|
| -
|
| -namespace shell {
|
| -
|
| -namespace {
|
| -
|
| -const char kCatalogName[] = "service:catalog";
|
| -const char kServiceManagerName[] = "service:shell";
|
| -const char kCapabilityClass_UserID[] = "shell:user_id";
|
| -const char kCapabilityClass_ClientProcess[] = "shell:client_process";
|
| -const char kCapabilityClass_InstanceName[] = "shell:instance_name";
|
| -const char kCapabilityClass_AllUsers[] = "shell:all_users";
|
| -const char kCapabilityClass_ExplicitClass[] = "shell:explicit_class";
|
| -const char kCapabilityClass_ServiceManager[] = "shell:service_manager";
|
| -
|
| -} // namespace
|
| -
|
| -Identity CreateServiceManagerIdentity() {
|
| - return Identity(kServiceManagerName, mojom::kRootUserID);
|
| -}
|
| -
|
| -Identity CreateCatalogIdentity() {
|
| - return Identity(kCatalogName, mojom::kRootUserID);
|
| -}
|
| -
|
| -CapabilitySpec GetPermissiveCapabilities() {
|
| - CapabilitySpec capabilities;
|
| - Interfaces interfaces;
|
| - interfaces.insert("*");
|
| - capabilities.required["*"] = interfaces;
|
| - return capabilities;
|
| -}
|
| -
|
| -Classes GetRequestedClasses(const CapabilitySpec& source_spec,
|
| - const Identity& target) {
|
| - Classes classes;
|
| -
|
| - // Start by looking for specs specific to the supplied identity.
|
| - auto it = source_spec.required.find(target.name());
|
| - if (it != source_spec.required.end()) {
|
| - std::copy(it->second.begin(), it->second.end(),
|
| - std::inserter(classes, classes.begin()));
|
| - }
|
| -
|
| - // Apply wild card rules too.
|
| - it = source_spec.required.find("*");
|
| - if (it != source_spec.required.end()) {
|
| - std::copy(it->second.begin(), it->second.end(),
|
| - std::inserter(classes, classes.begin()));
|
| - }
|
| - return classes;
|
| -}
|
| -
|
| -void GetClassesAndInterfacesForConnection(
|
| - const CapabilitySpec& source_spec,
|
| - const Identity& target,
|
| - const CapabilitySpec& target_spec,
|
| - Classes* classes,
|
| - Interfaces* interfaces) {
|
| - DCHECK(classes && interfaces);
|
| - *classes = GetRequestedClasses(source_spec, target);
|
| - // Flatten all interfaces from classes requested by the source into the
|
| - // allowed interface set in the request.
|
| - for (const auto& class_name : *classes) {
|
| - auto it = target_spec.provided.find(class_name);
|
| - if (it != target_spec.provided.end()) {
|
| - for (const auto& interface_name : it->second)
|
| - interfaces->insert(interface_name);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool HasClass(const CapabilitySpec& spec, const std::string& class_name) {
|
| - auto it = spec.required.find(kServiceManagerName);
|
| - if (it == spec.required.end())
|
| - return false;
|
| - return it->second.find(class_name) != it->second.end();
|
| -}
|
| -
|
| -// Encapsulates a connection to an instance of a service, tracked by the
|
| -// Service Manager.
|
| -class ServiceManager::Instance
|
| - : public mojom::Connector,
|
| - public mojom::PIDReceiver,
|
| - public Service,
|
| - public InterfaceFactory<mojom::ServiceManager>,
|
| - public mojom::ServiceManager {
|
| - public:
|
| - Instance(shell::ServiceManager* service_manager,
|
| - const Identity& identity,
|
| - const CapabilitySpec& capability_spec)
|
| - : service_manager_(service_manager),
|
| - id_(GenerateUniqueID()),
|
| - identity_(identity),
|
| - capability_spec_(capability_spec),
|
| - allow_any_application_(capability_spec.required.count("*") == 1),
|
| - pid_receiver_binding_(this),
|
| - weak_factory_(this) {
|
| - if (identity_.name() == kServiceManagerName ||
|
| - identity_.name() == kCatalogName) {
|
| - pid_ = base::Process::Current().Pid();
|
| - }
|
| - DCHECK_NE(mojom::kInvalidInstanceID, id_);
|
| - }
|
| -
|
| - ~Instance() override {
|
| - // Shutdown all bindings before we close the runner. This way the process
|
| - // should see the pipes closed and exit, as well as waking up any potential
|
| - // sync/WaitForIncomingResponse().
|
| - service_.reset();
|
| - if (pid_receiver_binding_.is_bound())
|
| - pid_receiver_binding_.Close();
|
| - connectors_.CloseAllBindings();
|
| - service_manager_bindings_.CloseAllBindings();
|
| -
|
| - // Notify the ServiceManager that this Instance is really going away.
|
| - service_manager_->OnInstanceStopped(identity_);
|
| -
|
| - // Release |runner_| so that if we are called back to OnRunnerCompleted()
|
| - // we know we're in the destructor.
|
| - std::unique_ptr<NativeRunner> runner = std::move(runner_);
|
| - runner.reset();
|
| - }
|
| -
|
| - Instance* parent() { return parent_; }
|
| -
|
| - void AddChild(std::unique_ptr<Instance> child) {
|
| - child->parent_ = this;
|
| - children_.insert(std::make_pair(child.get(), std::move(child)));
|
| - }
|
| -
|
| - void RemoveChild(Instance* child) {
|
| - auto it = children_.find(child);
|
| - DCHECK(it != children_.end());
|
| -
|
| - // Deletes |child|.
|
| - children_.erase(it);
|
| - }
|
| -
|
| - bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) {
|
| - if (!service_.is_bound())
|
| - 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());
|
| - }
|
| -
|
| - Classes classes;
|
| - Interfaces interfaces;
|
| - Instance* source = service_manager_->GetExistingInstance(params->source());
|
| - if (source) {
|
| - GetClassesAndInterfacesForConnection(source->capability_spec_,
|
| - identity_, capability_spec_,
|
| - &classes, &interfaces);
|
| - } else {
|
| - interfaces.insert("*");
|
| - }
|
| -
|
| - // The target has specified that sources must request one of its provided
|
| - // classes instead of specifying a wild-card for interfaces.
|
| - if (HasClass(capability_spec_, kCapabilityClass_ExplicitClass) &&
|
| - (interfaces.count("*") != 0)) {
|
| - interfaces.erase("*");
|
| - }
|
| -
|
| - service_->OnConnect(params->source(), params->TakeRemoteInterfaces(),
|
| - interfaces, classes);
|
| - return true;
|
| - }
|
| -
|
| - void StartWithService(mojom::ServicePtr service) {
|
| - CHECK(!service_);
|
| - service_ = std::move(service);
|
| - service_.set_connection_error_handler(
|
| - base::Bind(&Instance::OnServiceLost, base::Unretained(this),
|
| - service_manager_->GetWeakPtr()));
|
| - service_->OnStart(identity_,
|
| - base::Bind(&Instance::OnInitializeResponse,
|
| - base::Unretained(this)));
|
| - }
|
| -
|
| - void StartWithClientProcessConnection(
|
| - mojom::ClientProcessConnectionPtr client_process_connection) {
|
| - mojom::ServicePtr service;
|
| - service.Bind(mojom::ServicePtrInfo(
|
| - std::move(client_process_connection->service), 0));
|
| - pid_receiver_binding_.Bind(
|
| - std::move(client_process_connection->pid_receiver_request));
|
| - StartWithService(std::move(service));
|
| - }
|
| -
|
| - void StartWithFilePath(const base::FilePath& path) {
|
| - CHECK(!service_);
|
| - runner_ = service_manager_->native_runner_factory_->Create(path);
|
| - bool start_sandboxed = false;
|
| - mojom::ServicePtr service = runner_->Start(
|
| - path, identity_, start_sandboxed,
|
| - base::Bind(&Instance::PIDAvailable, weak_factory_.GetWeakPtr()),
|
| - base::Bind(&Instance::OnRunnerCompleted, weak_factory_.GetWeakPtr()));
|
| - StartWithService(std::move(service));
|
| - }
|
| -
|
| - mojom::ServiceInfoPtr CreateServiceInfo() const {
|
| - mojom::ServiceInfoPtr info(mojom::ServiceInfo::New());
|
| - info->id = id_;
|
| - info->identity = identity_;
|
| - info->pid = pid_;
|
| - return info;
|
| - }
|
| -
|
| - const CapabilitySpec& capability_spec() const {
|
| - return capability_spec_;
|
| - }
|
| - const Identity& identity() const { return identity_; }
|
| - uint32_t id() const { return id_; }
|
| -
|
| - // Service:
|
| - bool OnConnect(const Identity& remote_identity,
|
| - InterfaceRegistry* registry) override {
|
| - Instance* source = service_manager_->GetExistingInstance(remote_identity);
|
| - DCHECK(source);
|
| - if (HasClass(source->capability_spec_, kCapabilityClass_ServiceManager)) {
|
| - registry->AddInterface<mojom::ServiceManager>(this);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - private:
|
| - // mojom::Connector implementation:
|
| - void Connect(const shell::Identity& in_target,
|
| - mojom::InterfaceProviderRequest remote_interfaces,
|
| - mojom::ClientProcessConnectionPtr client_process_connection,
|
| - const ConnectCallback& callback) override {
|
| - Identity target = in_target;
|
| - if (target.user_id() == mojom::kInheritUserID)
|
| - target.set_user_id(identity_.user_id());
|
| -
|
| - if (!ValidateIdentity(target, callback))
|
| - return;
|
| - if (!ValidateClientProcessConnection(&client_process_connection, target,
|
| - callback)) {
|
| - return;
|
| - }
|
| - if (!ValidateCapabilities(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_connection(std::move(client_process_connection));
|
| - params->set_connect_callback(callback);
|
| - service_manager_->Connect(
|
| - std::move(params), nullptr, weak_factory_.GetWeakPtr());
|
| - }
|
| -
|
| - void Clone(mojom::ConnectorRequest request) override {
|
| - connectors_.AddBinding(this, std::move(request));
|
| - }
|
| -
|
| - // mojom::PIDReceiver:
|
| - void SetPID(uint32_t pid) override {
|
| - PIDAvailable(pid);
|
| - }
|
| -
|
| - // InterfaceFactory<mojom::ServiceManager>:
|
| - void Create(const Identity& remote_identity,
|
| - mojom::ServiceManagerRequest request) override {
|
| - service_manager_bindings_.AddBinding(this, std::move(request));
|
| - }
|
| -
|
| - // mojom::ServiceManager implementation:
|
| - void AddListener(mojom::ServiceManagerListenerPtr listener) override {
|
| - // TODO(beng): this should only track the instances matching this user, and
|
| - // root.
|
| - service_manager_->AddListener(std::move(listener));
|
| - }
|
| -
|
| - bool ValidateIdentity(const Identity& identity,
|
| - const ConnectCallback& callback) {
|
| - if (!IsValidName(identity.name())) {
|
| - LOG(ERROR) << "Error: invalid Name: " << identity.name();
|
| - callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
|
| - mojom::kInheritUserID);
|
| - return false;
|
| - }
|
| - 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 true;
|
| - }
|
| -
|
| - bool ValidateClientProcessConnection(
|
| - mojom::ClientProcessConnectionPtr* client_process_connection,
|
| - const Identity& target,
|
| - const ConnectCallback& callback) {
|
| - if (!client_process_connection->is_null()) {
|
| - if (!HasClass(capability_spec_, kCapabilityClass_ClientProcess)) {
|
| - LOG(ERROR) << "Instance: " << identity_.name() << " attempting "
|
| - << "to register an instance for a process it created for "
|
| - << "target: " << target.name() << " without the "
|
| - << "service:shell{client_process} capability class.";
|
| - callback.Run(mojom::ConnectResult::ACCESS_DENIED,
|
| - mojom::kInheritUserID);
|
| - return false;
|
| - }
|
| -
|
| - if (!(*client_process_connection)->service.is_valid() ||
|
| - !(*client_process_connection)->pid_receiver_request.is_valid()) {
|
| - LOG(ERROR) << "Must supply both service AND "
|
| - << "pid_receiver_request when sending "
|
| - << "client_process_connection.";
|
| - callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
|
| - mojom::kInheritUserID);
|
| - return false;
|
| - }
|
| - 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 true;
|
| - }
|
| -
|
| - bool ValidateCapabilities(const Identity& target,
|
| - const ConnectCallback& callback) {
|
| - // TODO(beng): Need to do the following additional policy validation of
|
| - // whether this instance is allowed to connect using:
|
| - // - a non-null client_process_connection.
|
| - if (target.user_id() != identity_.user_id() &&
|
| - target.user_id() != mojom::kRootUserID &&
|
| - !HasClass(capability_spec_, kCapabilityClass_UserID)) {
|
| - LOG(ERROR) << "Instance: " << identity_.name() << " running as: "
|
| - << identity_.user_id() << " attempting to connect to: "
|
| - << target.name() << " as: " << target.user_id() << " without "
|
| - << " the service:shell{user_id} capability class.";
|
| - callback.Run(mojom::ConnectResult::ACCESS_DENIED,
|
| - mojom::kInheritUserID);
|
| - return false;
|
| - }
|
| - if (!target.instance().empty() &&
|
| - target.instance() != GetNamePath(target.name()) &&
|
| - !HasClass(capability_spec_, kCapabilityClass_InstanceName)) {
|
| - LOG(ERROR) << "Instance: " << identity_.name() << " attempting to "
|
| - << "connect to " << target.name() << " using Instance name: "
|
| - << target.instance() << " without the "
|
| - << "service:shell{instance_name} capability class.";
|
| - callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID);
|
| - return false;
|
| -
|
| - }
|
| -
|
| - if (allow_any_application_ ||
|
| - capability_spec_.required.find(target.name()) !=
|
| - capability_spec_.required.end()) {
|
| - return true;
|
| - }
|
| - LOG(ERROR) << "Capabilities prevented connection from: " <<
|
| - identity_.name() << " to: " << target.name();
|
| - callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID);
|
| - return false;
|
| - }
|
| -
|
| - uint32_t GenerateUniqueID() const {
|
| - static uint32_t id = mojom::kInvalidInstanceID;
|
| - ++id;
|
| - CHECK_NE(mojom::kInvalidInstanceID, id);
|
| - return id;
|
| - }
|
| -
|
| - void PIDAvailable(base::ProcessId pid) {
|
| - if (pid == base::kNullProcessId) {
|
| - service_manager_->OnInstanceError(this);
|
| - return;
|
| - }
|
| - pid_ = pid;
|
| - service_manager_->NotifyPIDAvailable(identity_, pid_);
|
| - }
|
| -
|
| - void OnServiceLost(base::WeakPtr<shell::ServiceManager> service_manager) {
|
| - service_.reset();
|
| - OnConnectionLost(service_manager);
|
| - }
|
| -
|
| - void OnConnectionLost(base::WeakPtr<shell::ServiceManager> service_manager) {
|
| - // Any time a Connector is lost or we lose the Service connection, it
|
| - // may have been the last pipe using this Instance. If so, clean up.
|
| - if (service_manager && !service_) {
|
| - if (connectors_.empty())
|
| - service_manager->OnInstanceError(this);
|
| - else
|
| - service_manager->OnInstanceUnreachable(this);
|
| - }
|
| - }
|
| -
|
| - void OnInitializeResponse(mojom::ConnectorRequest connector_request) {
|
| - if (connector_request.is_pending()) {
|
| - connectors_.AddBinding(this, std::move(connector_request));
|
| - connectors_.set_connection_error_handler(
|
| - base::Bind(&Instance::OnConnectionLost, base::Unretained(this),
|
| - service_manager_->GetWeakPtr()));
|
| - }
|
| - }
|
| -
|
| - // Callback when NativeRunner completes.
|
| - void OnRunnerCompleted() {
|
| - if (!runner_.get())
|
| - return; // We're in the destructor.
|
| -
|
| - service_manager_->OnInstanceError(this);
|
| - }
|
| -
|
| - shell::ServiceManager* const service_manager_;
|
| -
|
| - // An id that identifies this instance. Distinct from pid, as a single process
|
| - // may vend multiple application instances, and this object may exist before a
|
| - // process is launched.
|
| - const uint32_t id_;
|
| - const Identity identity_;
|
| - const CapabilitySpec capability_spec_;
|
| - const bool allow_any_application_;
|
| - std::unique_ptr<NativeRunner> runner_;
|
| - mojom::ServicePtr service_;
|
| - mojo::Binding<mojom::PIDReceiver> pid_receiver_binding_;
|
| - mojo::BindingSet<mojom::Connector> connectors_;
|
| - mojo::BindingSet<mojom::ServiceManager> service_manager_bindings_;
|
| - base::ProcessId pid_ = base::kNullProcessId;
|
| - Instance* parent_ = nullptr;
|
| - InstanceMap children_;
|
| - base::WeakPtrFactory<Instance> weak_factory_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Instance);
|
| -};
|
| -
|
| -// static
|
| -ServiceManager::TestAPI::TestAPI(ServiceManager* service_manager)
|
| - : service_manager_(service_manager) {}
|
| -ServiceManager::TestAPI::~TestAPI() {}
|
| -
|
| -bool ServiceManager::TestAPI::HasRunningInstanceForName(
|
| - const std::string& name) const {
|
| - for (const auto& entry : service_manager_->identity_to_instance_) {
|
| - if (entry.first.name() == name)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// ServiceManager, public:
|
| -
|
| -ServiceManager::ServiceManager(
|
| - std::unique_ptr<NativeRunnerFactory> native_runner_factory,
|
| - mojom::ServicePtr catalog)
|
| - : native_runner_factory_(std::move(native_runner_factory)),
|
| - weak_ptr_factory_(this) {
|
| - mojom::ServicePtr service;
|
| - mojom::ServiceRequest request = mojo::GetProxy(&service);
|
| -
|
| - CapabilitySpec spec;
|
| - spec.provided[kCapabilityClass_ServiceManager].insert(
|
| - "shell::mojom::ServiceManager");
|
| - spec.required["*"].insert("shell:service_factory");
|
| - spec.required["service:catalog"].insert("shell:resolver");
|
| -
|
| - service_manager_instance_ =
|
| - CreateInstance(Identity(), CreateServiceManagerIdentity(), spec);
|
| - service_manager_instance_->StartWithService(std::move(service));
|
| - singletons_.insert(kServiceManagerName);
|
| - service_context_.reset(new ServiceContext(this, std::move(request)));
|
| -
|
| - if (catalog)
|
| - InitCatalog(std::move(catalog));
|
| -}
|
| -
|
| -ServiceManager::~ServiceManager() {
|
| - // Ensure we tear down the ServiceManager instance last. This is to avoid
|
| - // hitting bindings DCHECKs, since the ServiceManager or Catalog may at any
|
| - // given time own in-flight responders for Instances' Connector requests.
|
| - std::unique_ptr<Instance> service_manager_instance;
|
| - auto iter = root_instances_.find(service_manager_instance_);
|
| - DCHECK(iter != root_instances_.end());
|
| - service_manager_instance = std::move(iter->second);
|
| -
|
| - root_instances_.clear();
|
| -}
|
| -
|
| -void ServiceManager::SetServiceOverrides(
|
| - std::unique_ptr<ServiceOverrides> overrides) {
|
| - service_overrides_ = std::move(overrides);
|
| -}
|
| -
|
| -void ServiceManager::SetInstanceQuitCallback(
|
| - base::Callback<void(const Identity&)> callback) {
|
| - instance_quit_callback_ = callback;
|
| -}
|
| -
|
| -void ServiceManager::Connect(std::unique_ptr<ConnectParams> params) {
|
| - Connect(std::move(params), nullptr, nullptr);
|
| -}
|
| -
|
| -mojom::ServiceRequest ServiceManager::StartEmbedderService(
|
| - const std::string& name) {
|
| - std::unique_ptr<ConnectParams> params(new ConnectParams);
|
| -
|
| - Identity embedder_identity(name, mojom::kRootUserID);
|
| - params->set_source(embedder_identity);
|
| - params->set_target(embedder_identity);
|
| -
|
| - mojom::ServicePtr service;
|
| - mojom::ServiceRequest request = mojo::GetProxy(&service);
|
| - Connect(std::move(params), std::move(service), nullptr);
|
| -
|
| - return request;
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// ServiceManager, Service implementation:
|
| -
|
| -bool ServiceManager::OnConnect(const Identity& remote_identity,
|
| - InterfaceRegistry* registry) {
|
| - // The only interface we expose is mojom::ServiceManager, and access to this
|
| - // interface is brokered by a policy specific to each caller, managed by the
|
| - // caller's instance. Here we look to see who's calling, and forward to the
|
| - // caller's instance to continue.
|
| - Instance* instance = nullptr;
|
| - for (const auto& entry : identity_to_instance_) {
|
| - if (entry.first == remote_identity) {
|
| - instance = entry.second;
|
| - break;
|
| - }
|
| - }
|
| - DCHECK(instance);
|
| - return instance->OnConnect(remote_identity, registry);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// ServiceManager, private:
|
| -
|
| -void ServiceManager::InitCatalog(mojom::ServicePtr catalog) {
|
| - // TODO(beng): It'd be great to build this from the manifest, however there's
|
| - // a bit of a chicken-and-egg problem.
|
| - CapabilitySpec spec;
|
| - spec.provided["app"].insert("filesystem::mojom::Directory");
|
| - spec.provided["catalog:catalog"].insert("catalog::mojom::Catalog");
|
| - spec.provided["shell:resolver"].insert("shell::mojom::Resolver");
|
| - spec.provided["control"].insert("catalog::mojom::CatalogControl");
|
| - Instance* instance = CreateInstance(
|
| - CreateServiceManagerIdentity(), CreateCatalogIdentity(), spec);
|
| - singletons_.insert(kCatalogName);
|
| - instance->StartWithService(std::move(catalog));
|
| -}
|
| -
|
| -mojom::Resolver* ServiceManager::GetResolver(const Identity& identity) {
|
| - auto iter = identity_to_resolver_.find(identity);
|
| - if (iter != identity_to_resolver_.end())
|
| - return iter->second.get();
|
| -
|
| - mojom::ResolverPtr resolver_ptr;
|
| - ConnectToInterface(this, identity, CreateCatalogIdentity(), &resolver_ptr);
|
| - mojom::Resolver* resolver = resolver_ptr.get();
|
| - identity_to_resolver_[identity] = std::move(resolver_ptr);
|
| - return resolver;
|
| -}
|
| -
|
| -void ServiceManager::OnInstanceError(Instance* instance) {
|
| - // We never clean up the ServiceManager's own instance.
|
| - if (instance == service_manager_instance_)
|
| - return;
|
| -
|
| - const Identity identity = instance->identity();
|
| - identity_to_instance_.erase(identity);
|
| -
|
| - if (instance->parent()) {
|
| - // Deletes |instance|.
|
| - instance->parent()->RemoveChild(instance);
|
| - } else {
|
| - auto it = root_instances_.find(instance);
|
| - DCHECK(it != root_instances_.end());
|
| -
|
| - // Deletes |instance|.
|
| - root_instances_.erase(it);
|
| - }
|
| -}
|
| -
|
| -void ServiceManager::OnInstanceUnreachable(Instance* instance) {
|
| - // If an Instance becomes unreachable, new connection requests for this
|
| - // identity will elicit a new Instance instantiation. The unreachable instance
|
| - // remains alive.
|
| - identity_to_instance_.erase(instance->identity());
|
| -}
|
| -
|
| -void ServiceManager::OnInstanceStopped(const Identity& identity) {
|
| - listeners_.ForAllPtrs([identity](mojom::ServiceManagerListener* listener) {
|
| - listener->OnServiceStopped(identity);
|
| - });
|
| - if (!instance_quit_callback_.is_null())
|
| - instance_quit_callback_.Run(identity);
|
| -}
|
| -
|
| -void ServiceManager::Connect(std::unique_ptr<ConnectParams> params,
|
| - mojom::ServicePtr service,
|
| - base::WeakPtr<Instance> source_instance) {
|
| - TRACE_EVENT_INSTANT1("mojo_shell", "ServiceManager::Connect",
|
| - TRACE_EVENT_SCOPE_THREAD, "original_name",
|
| - params->target().name());
|
| - DCHECK(IsValidName(params->target().name()));
|
| - DCHECK(base::IsValidGUID(params->target().user_id()));
|
| - DCHECK_NE(mojom::kInheritUserID, params->target().user_id());
|
| - DCHECK(!service.is_bound() || !identity_to_instance_.count(params->target()));
|
| -
|
| - // Connect to an existing matching instance, if possible.
|
| - if (!service.is_bound() && ConnectToExistingInstance(¶ms))
|
| - return;
|
| -
|
| - // The catalog needs to see the source identity as that of the originating
|
| - // app so it loads the correct store. Since the catalog is itself run as root
|
| - // when this re-enters Connect() it'll be handled by
|
| - // ConnectToExistingInstance().
|
| - mojom::Resolver* resolver =
|
| - GetResolver(Identity(kServiceManagerName, params->target().user_id()));
|
| -
|
| - std::string name = params->target().name();
|
| - resolver->ResolveMojoName(
|
| - name, base::Bind(&shell::ServiceManager::OnGotResolvedName,
|
| - weak_ptr_factory_.GetWeakPtr(), base::Passed(¶ms),
|
| - base::Passed(&service), !!source_instance,
|
| - source_instance));
|
| -}
|
| -
|
| -ServiceManager::Instance* ServiceManager::GetExistingInstance(
|
| - const Identity& identity) const {
|
| - const auto& it = identity_to_instance_.find(identity);
|
| - Instance* instance = it != identity_to_instance_.end() ? it->second : nullptr;
|
| - if (instance)
|
| - return instance;
|
| -
|
| - if (singletons_.find(identity.name()) != singletons_.end()) {
|
| - for (auto entry : identity_to_instance_) {
|
| - if (entry.first.name() == identity.name() &&
|
| - entry.first.instance() == identity.instance()) {
|
| - return entry.second;
|
| - }
|
| - }
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -void ServiceManager::NotifyPIDAvailable(const Identity& identity,
|
| - base::ProcessId pid) {
|
| - listeners_.ForAllPtrs(
|
| - [identity, pid](mojom::ServiceManagerListener* listener) {
|
| - listener->OnServiceStarted(identity, pid);
|
| - });
|
| -}
|
| -
|
| -bool ServiceManager::ConnectToExistingInstance(
|
| - std::unique_ptr<ConnectParams>* params) {
|
| - Instance* instance = GetExistingInstance((*params)->target());
|
| - return instance && instance->ConnectToService(params);
|
| -}
|
| -
|
| -ServiceManager::Instance* ServiceManager::CreateInstance(
|
| - const Identity& source,
|
| - const Identity& target,
|
| - const CapabilitySpec& spec) {
|
| - CHECK(target.user_id() != mojom::kInheritUserID);
|
| -
|
| - std::unique_ptr<Instance> instance(new Instance(this, target, spec));
|
| - Instance* raw_instance = instance.get();
|
| -
|
| - Instance* source_instance = GetExistingInstance(source);
|
| - if (source_instance)
|
| - source_instance->AddChild(std::move(instance));
|
| - else
|
| - root_instances_.insert(std::make_pair(raw_instance, std::move(instance)));
|
| -
|
| - // NOTE: |instance| has been passed elsewhere. Use |raw_instance| from this
|
| - // point forward. It's safe for the extent of this method.
|
| -
|
| - auto result =
|
| - identity_to_instance_.insert(std::make_pair(target, raw_instance));
|
| - DCHECK(result.second);
|
| -
|
| - mojom::ServiceInfoPtr info = raw_instance->CreateServiceInfo();
|
| - listeners_.ForAllPtrs([&info](mojom::ServiceManagerListener* listener) {
|
| - listener->OnServiceCreated(info.Clone());
|
| - });
|
| -
|
| - return raw_instance;
|
| -}
|
| -
|
| -void ServiceManager::AddListener(mojom::ServiceManagerListenerPtr listener) {
|
| - // TODO(beng): filter instances provided by those visible to this service.
|
| - std::vector<mojom::ServiceInfoPtr> instances;
|
| - instances.reserve(identity_to_instance_.size());
|
| - for (auto& instance : identity_to_instance_)
|
| - instances.push_back(instance.second->CreateServiceInfo());
|
| - listener->OnInit(std::move(instances));
|
| -
|
| - listeners_.AddPtr(std::move(listener));
|
| -}
|
| -
|
| -void ServiceManager::CreateServiceWithFactory(const Identity& service_factory,
|
| - const std::string& name,
|
| - mojom::ServiceRequest request) {
|
| - mojom::ServiceFactory* factory = GetServiceFactory(service_factory);
|
| - factory->CreateService(std::move(request), name);
|
| -}
|
| -
|
| -mojom::ServiceFactory* ServiceManager::GetServiceFactory(
|
| - const Identity& service_factory_identity) {
|
| - auto it = service_factories_.find(service_factory_identity);
|
| - if (it != service_factories_.end())
|
| - return it->second.get();
|
| -
|
| - Identity source_identity(kServiceManagerName, mojom::kInheritUserID);
|
| - mojom::ServiceFactoryPtr factory;
|
| - ConnectToInterface(this, source_identity, service_factory_identity,
|
| - &factory);
|
| - mojom::ServiceFactory* factory_interface = factory.get();
|
| - factory.set_connection_error_handler(base::Bind(
|
| - &shell::ServiceManager::OnServiceFactoryLost,
|
| - weak_ptr_factory_.GetWeakPtr(), service_factory_identity));
|
| - service_factories_[service_factory_identity] = std::move(factory);
|
| - return factory_interface;
|
| -}
|
| -
|
| -void ServiceManager::OnServiceFactoryLost(const Identity& which) {
|
| - // Remove the mapping.
|
| - auto it = service_factories_.find(which);
|
| - DCHECK(it != service_factories_.end());
|
| - service_factories_.erase(it);
|
| -}
|
| -
|
| -void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
|
| - mojom::ServicePtr service,
|
| - bool has_source_instance,
|
| - base::WeakPtr<Instance> source_instance,
|
| - mojom::ResolveResultPtr result) {
|
| - // If this request was originated by a specific Instance and that Instance is
|
| - // no longer around, we ignore this response.
|
| - if (has_source_instance && !source_instance)
|
| - return;
|
| -
|
| - std::string instance_name = params->target().instance();
|
| - if (instance_name == GetNamePath(params->target().name()) &&
|
| - result->qualifier != GetNamePath(result->resolved_name)) {
|
| - instance_name = result->qualifier;
|
| - }
|
| - // |result->capabilities| can be null when there is no manifest, e.g. for URL
|
| - // types not resolvable by the resolver.
|
| - CapabilitySpec capabilities = GetPermissiveCapabilities();
|
| - if (result->capabilities.has_value())
|
| - capabilities = result->capabilities.value();
|
| -
|
| - const std::string user_id = HasClass(capabilities, kCapabilityClass_AllUsers)
|
| - ? base::GenerateGUID()
|
| - : params->target().user_id();
|
| - const Identity target(params->target().name(), user_id, instance_name);
|
| - params->set_target(target);
|
| -
|
| - // It's possible that when this manifest request was issued, another one was
|
| - // already in-progress and completed by the time this one did, and so the
|
| - // requested application may already be running.
|
| - if (ConnectToExistingInstance(¶ms))
|
| - return;
|
| -
|
| - Identity source = params->source();
|
| -
|
| - // Services that request "all_users" class from the Service Manager are
|
| - // allowed to field connection requests from any user. They also run with a
|
| - // synthetic user id generated here. The user id provided via Connect() is
|
| - // ignored. Additionally services with the "all_users" class are not tied to
|
| - // the lifetime of the service that started them, instead they are owned by
|
| - // the Service Manager.
|
| - Identity source_identity_for_creation;
|
| - if (HasClass(capabilities, kCapabilityClass_AllUsers)) {
|
| - singletons_.insert(target.name());
|
| - source_identity_for_creation = CreateServiceManagerIdentity();
|
| - } else {
|
| - source_identity_for_creation = params->source();
|
| - }
|
| -
|
| - mojom::ClientProcessConnectionPtr client_process_connection =
|
| - params->TakeClientProcessConnection();
|
| - Instance* instance = CreateInstance(source_identity_for_creation,
|
| - target, capabilities);
|
| -
|
| - // Below are various paths through which a new Instance can be bound to a
|
| - // Service proxy.
|
| - if (service.is_bound()) {
|
| - // If a ServicePtr was provided, there's no more work to do: someone
|
| - // is already holding a corresponding ServiceRequest.
|
| - instance->StartWithService(std::move(service));
|
| - } else if (!client_process_connection.is_null()) {
|
| - // Likewise if a ClientProcessConnection was given via Connect(), it
|
| - // provides the Service proxy to use.
|
| - instance->StartWithClientProcessConnection(
|
| - std::move(client_process_connection));
|
| - } else {
|
| - // Otherwise we create a new Service pipe.
|
| - mojom::ServiceRequest request = GetProxy(&service);
|
| - CHECK(!result->package_path.empty() && result->capabilities.has_value());
|
| -
|
| - if (target.name() != result->resolved_name) {
|
| - instance->StartWithService(std::move(service));
|
| - Identity factory(result->resolved_name, target.user_id(),
|
| - instance_name);
|
| - CreateServiceWithFactory(factory, target.name(), std::move(request));
|
| - } else {
|
| - base::FilePath package_path;
|
| - if (!service_overrides_ || !service_overrides_->GetExecutablePathOverride(
|
| - target.name(), &package_path)) {
|
| - package_path = result->package_path;
|
| - }
|
| -
|
| - Identity source_instance_identity;
|
| - base::debug::Alias(&has_source_instance);
|
| - base::debug::Alias(&package_path);
|
| - base::debug::Alias(&source);
|
| - base::debug::Alias(&target);
|
| - if (source_instance)
|
| - source_instance_identity = source_instance->identity();
|
| - base::debug::Alias(&source_instance_identity);
|
| -#if defined(GOOGLE_CHROME_BUILD)
|
| - // We do not currently want to hit this code path in production, but it's
|
| - // happening somehow. https://crbug.com/649673.
|
| - CHECK(false);
|
| -#endif
|
| - instance->StartWithFilePath(package_path);
|
| - }
|
| - }
|
| -
|
| - // Now that the instance has a Service, we can connect to it.
|
| - bool connected = instance->ConnectToService(¶ms);
|
| - DCHECK(connected);
|
| -}
|
| -
|
| -base::WeakPtr<ServiceManager> ServiceManager::GetWeakPtr() {
|
| - return weak_ptr_factory_.GetWeakPtr();
|
| -}
|
| -
|
| -} // namespace shell
|
|
|