910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "services/service_manager/service_manager.h"

#include <utility>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/token.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/constants.h"
#include "services/service_manager/public/cpp/manifest_builder.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/service_manager/public/mojom/service.mojom.h"
#include "services/service_manager/public/mojom/service_control.mojom.h"
#include "services/service_manager/public/mojom/service_manager.mojom.h"
#include "services/service_manager/service_instance.h"
#include "services/service_manager/service_process_host.h"

#if !BUILDFLAG(IS_IOS)
#include "services/service_manager/service_process_launcher.h"
#endif

namespace service_manager {

namespace {

const char kCapability_ServiceManager[] = "service_manager:service_manager";

#if BUILDFLAG(IS_WIN)
const char kServiceExecutableExtension[] = ".service.exe";
#elif !BUILDFLAG(IS_IOS)
const char kServiceExecutableExtension[] = ".service";
#endif

base::ProcessId GetCurrentPid() {
#if BUILDFLAG(IS_IOS)
  // iOS does not support base::Process.
  return 0;
#else
  return base::Process::Current().Pid();
#endif
}

const Identity& GetServiceManagerInstanceIdentity() {
  static base::NoDestructor<Identity> id{service_manager::mojom::kServiceName,
                                         kSystemInstanceGroup, base::Token{},
                                         base::Token::CreateRandom()};
  return *id;
}

// Default ServiceProcessHost implementation. This launches a service process
// from a standalone executable only.
class DefaultServiceProcessHost : public ServiceProcessHost {
 public:
  explicit DefaultServiceProcessHost(const base::FilePath& executable_path)
#if !BUILDFLAG(IS_IOS)
      : launcher_(nullptr, executable_path)
#endif
  {
  }

  DefaultServiceProcessHost(const DefaultServiceProcessHost&) = delete;
  DefaultServiceProcessHost& operator=(const DefaultServiceProcessHost&) =
      delete;

  ~DefaultServiceProcessHost() override = default;

  mojo::PendingRemote<mojom::Service> Launch(
      const Identity& identity,
      sandbox::mojom::Sandbox sandbox_type,
      const std::u16string& display_name,
      LaunchCallback callback) override {
#if BUILDFLAG(IS_IOS)
    return mojo::NullRemote();
#else
    // TODO(crbug.com/41353434): Support sandboxing.
    CHECK_EQ(sandbox_type, sandbox::mojom::Sandbox::kNoSandbox);
    return launcher_.Start(identity, sandbox::mojom::Sandbox::kNoSandbox,
                           std::move(callback));
#endif  // BUILDFLAG(IS_IOS)
  }

 private:
#if !BUILDFLAG(IS_IOS)
  ServiceProcessLauncher launcher_;
#endif
};

// Default ServiceManager::Delegate implementation. This supports launching only
// standalone service executables.
//
// TODO(crbug.com/41353434): Migrate all service process support into this
// implementation and merge it into ServiceProcessHost.
class DefaultServiceManagerDelegate : public ServiceManager::Delegate {
 public:
  explicit DefaultServiceManagerDelegate(
      ServiceManager::ServiceExecutablePolicy service_executable_policy)
      : service_executable_policy_(service_executable_policy) {}

  DefaultServiceManagerDelegate(const DefaultServiceManagerDelegate&) = delete;
  DefaultServiceManagerDelegate& operator=(
      const DefaultServiceManagerDelegate&) = delete;

  ~DefaultServiceManagerDelegate() override = default;

  bool RunBuiltinServiceInstanceInCurrentProcess(
      const Identity& identity,
      mojo::PendingReceiver<mojom::Service> receiver) override {
    return false;
  }

  std::unique_ptr<ServiceProcessHost>
  CreateProcessHostForBuiltinServiceInstance(
      const Identity& identity) override {
    return nullptr;
  }

  std::unique_ptr<ServiceProcessHost> CreateProcessHostForServiceExecutable(
      const base::FilePath& executable_path) override {
    if (service_executable_policy_ ==
        ServiceManager::ServiceExecutablePolicy::kNotSupported) {
      return nullptr;
    }

    DCHECK_EQ(ServiceManager::ServiceExecutablePolicy::kSupported,
              service_executable_policy_);
    return std::make_unique<DefaultServiceProcessHost>(executable_path);
  }

 private:
  const ServiceManager::ServiceExecutablePolicy service_executable_policy_;
};

}  // namespace

ServiceManager::ServiceManager(const std::vector<Manifest>& manifests,
                               std::unique_ptr<Delegate> delegate)
    : delegate_(std::move(delegate)), catalog_(manifests) {
  Manifest service_manager_manifest =
      ManifestBuilder()
          .WithOptions(ManifestOptionsBuilder()
                           .WithInstanceSharingPolicy(
                               Manifest::InstanceSharingPolicy::kSingleton)
                           .Build())
          .ExposeCapability(kCapability_ServiceManager,
                            Manifest::InterfaceList<mojom::ServiceManager>())
          .Build();
  service_manager_instance_ = CreateServiceInstance(
      GetServiceManagerInstanceIdentity(), service_manager_manifest);
  service_manager_instance_->SetPID(GetCurrentPid());

  mojo::PendingRemote<mojom::Service> remote;
  service_receiver_.Bind(remote.InitWithNewPipeAndPassReceiver());
  service_manager_instance_->StartWithRemote(std::move(remote));
}

ServiceManager::ServiceManager(
    const std::vector<Manifest>& manifests,
    ServiceExecutablePolicy service_executable_policy)
    : ServiceManager(manifests,
                     std::make_unique<DefaultServiceManagerDelegate>(
                         service_executable_policy)) {}

ServiceManager::~ServiceManager() {
  // Stop all of the instances before destroying any of them. This ensures that
  // all Services will receive connection errors and avoids possible deadlock in
  // the case where one ServiceInstance's destructor blocks waiting for its
  // Runner to quit, while that Runner's corresponding Service blocks its
  // shutdown on a distinct Service receiving a connection error.
  //
  // Also 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.
  for (auto& instance : instances_) {
    if (instance.get() != service_manager_instance_)
      instance->Stop();
  }
  service_manager_instance_->Stop();
  instances_.clear();
}

ServiceInstance* ServiceManager::FindOrCreateMatchingTargetInstance(
    const ServiceInstance& source_instance,
    const ServiceFilter& partial_target_filter) {
  TRACE_EVENT_INSTANT1("service_manager", "ServiceManager::Connect",
                       TRACE_EVENT_SCOPE_THREAD, "original_name",
                       partial_target_filter.service_name());
  if (partial_target_filter.service_name() == mojom::kServiceName)
    return service_manager_instance_;

  const service_manager::Manifest* manifest =
      catalog_.GetManifest(partial_target_filter.service_name());
  if (!manifest) {
    LOG(ERROR) << "Failed to resolve service name: "
               << partial_target_filter.service_name();
    return nullptr;
  }

  service_manager::ServiceFilter target_filter = partial_target_filter;
  if (!target_filter.instance_group()) {
    // Inherit the source instance's group if none was specified by the
    // caller's provided filter.
    target_filter.set_instance_group(
        source_instance.identity().instance_group());
  }
  if (!target_filter.instance_id()) {
    // Assume the default (zero) instance ID if none was specified by the
    // caller's provided filter.
    target_filter.set_instance_id(base::Token());
  }

  // Use an existing instance if possible.
  ServiceInstance* target_instance =
      instance_registry_.FindMatching(target_filter);
  if (target_instance)
    return target_instance;

  // If there was no existing instance but the caller is requesting a specific
  // globally unique ID for the target, ignore the request. That instance is
  // obviously no longer running, and globally unique IDs are never reused.
  if (target_filter.globally_unique_id())
    return nullptr;

  const service_manager::Manifest* parent_manifest =
      catalog_.GetParentManifest(manifest->service_name);

  // New instances to be shared globally or across instance groups are assigned
  // their own random instance group. Packaged service instances also retain
  // the target filter group regardless of sharing policy.
  const base::Token target_group =
      manifest->options.instance_sharing_policy ==
                  Manifest::InstanceSharingPolicy::kNoSharing ||
              parent_manifest
          ? *target_filter.instance_group()
          : base::Token::CreateRandom();

  // New singleton instances are always forced to instance ID zero.
  const base::Token target_instance_id =
      manifest->options.instance_sharing_policy ==
              Manifest::InstanceSharingPolicy::kSingleton
          ? base::Token()
          : *target_filter.instance_id();

  DCHECK(!target_instance);
  target_instance = CreateServiceInstance(
      Identity(target_filter.service_name(), target_group, target_instance_id,
               target_filter.globally_unique_id().value_or(
                   base::Token::CreateRandom())),
      *manifest);

  if (parent_manifest) {
    // This service is provided by another service, as indicated by the
    // providing service's manifest. Get an instance of that service first, and
    // ask it to create an instance of this one.
    auto factory_filter = ServiceFilter::ByNameWithIdInGroup(
        parent_manifest->service_name, *target_filter.instance_id(),
        *target_filter.instance_group());
    ServiceInstance* factory_instance = FindOrCreateMatchingTargetInstance(
        *service_manager_instance_, factory_filter);

    mojo::PendingRemote<mojom::ProcessMetadata> metadata;
    auto metadata_receiver = metadata.InitWithNewPipeAndPassReceiver();
    mojo::PendingRemote<mojom::Service> remote;
    bool created =
        factory_instance &&
        factory_instance->CreatePackagedServiceInstance(
            target_instance->identity(),
            remote.InitWithNewPipeAndPassReceiver(), std::move(metadata));
    if (!created) {
      DestroyInstance(target_instance);
      return nullptr;
    }

    target_instance->BindProcessMetadataReceiver(std::move(metadata_receiver));
    target_instance->StartWithRemote(std::move(remote));
    return target_instance;
  }

  switch (manifest->options.execution_mode) {
    case Manifest::ExecutionMode::kInProcessBuiltin: {
      mojo::PendingRemote<mojom::Service> remote;
      if (!delegate_->RunBuiltinServiceInstanceInCurrentProcess(
              target_instance->identity(),
              remote.InitWithNewPipeAndPassReceiver())) {
        DestroyInstance(target_instance);
        return nullptr;
      }
      target_instance->StartWithRemote(std::move(remote));
      break;
    }

#if !BUILDFLAG(IS_IOS)
    case Manifest::ExecutionMode::kOutOfProcessBuiltin: {
      auto process_host = delegate_->CreateProcessHostForBuiltinServiceInstance(
          target_instance->identity());
      if (!process_host || !target_instance->StartWithProcessHost(
                               std::move(process_host),
                               sandbox::policy::UtilitySandboxTypeFromString(
                                   manifest->options.sandbox_type))) {
        DestroyInstance(target_instance);
        return nullptr;
      }
      break;
    }

    case Manifest::ExecutionMode::kStandaloneExecutable: {
      base::FilePath service_exe_root;
      CHECK(base::PathService::Get(base::DIR_ASSETS, &service_exe_root));
      auto process_host = delegate_->CreateProcessHostForServiceExecutable(
          service_exe_root.AppendASCII(manifest->service_name +
                                       kServiceExecutableExtension));
      if (!process_host || !target_instance->StartWithProcessHost(
                               std::move(process_host),
                               sandbox::policy::UtilitySandboxTypeFromString(
                                   manifest->options.sandbox_type))) {
        DestroyInstance(target_instance);
        return nullptr;
      }
      break;
    }
#else   // !BUILDFLAG(IS_IOS)
    default:
      NOTREACHED();
#endif  // !BUILDFLAG(IS_IOS)
  }

  return target_instance;
}

void ServiceManager::StartService(const std::string& service_name) {
  FindOrCreateMatchingTargetInstance(
      *service_manager_instance_,
      ServiceFilter::ByNameInGroup(service_name, kSystemInstanceGroup));
}

bool ServiceManager::QueryCatalog(const std::string& service_name,
                                  const base::Token& instance_group,
                                  std::string* sandbox_type) {
  const Manifest* manifest = catalog_.GetManifest(service_name);
  if (!manifest)
    return false;
  *sandbox_type = manifest->options.sandbox_type;
  return true;
}

bool ServiceManager::RegisterService(
    const Identity& identity,
    mojo::PendingRemote<mojom::Service> service,
    mojo::PendingReceiver<mojom::ProcessMetadata> metadata_receiver) {
  if (!identity.IsValid())
    return false;

  const service_manager::Manifest* manifest =
      catalog_.GetManifest(identity.name());
  if (!manifest) {
    LOG(ERROR) << "Failed to resolve service name: " << identity.name();
    return false;
  }

  ServiceInstance* instance = CreateServiceInstance(identity, *manifest);
  if (metadata_receiver)
    instance->BindProcessMetadataReceiver(std::move(metadata_receiver));
  else
    instance->SetPID(GetCurrentPid());
  instance->StartWithRemote(std::move(service));
  return true;
}

void ServiceManager::MakeInstanceUnreachable(ServiceInstance* instance) {
  instance_registry_.Unregister(instance);
}

void ServiceManager::DestroyInstance(ServiceInstance* instance) {
  // We never clean up the ServiceManager's own instance.
  if (instance == service_manager_instance_)
    return;

  MakeInstanceUnreachable(instance);
  auto it = instances_.find(instance);
  CHECK(it != instances_.end());

  // Deletes |instance|.
  instances_.erase(it);
}

void ServiceManager::OnInstanceStopped(const Identity& identity) {
  for (auto& listener : listeners_) {
    listener->OnServiceStopped(identity);
  }
}

ServiceInstance* ServiceManager::GetExistingInstance(
    const Identity& identity) const {
  return instance_registry_.FindMatching(
      ServiceFilter::ForExactIdentity(identity));
}

void ServiceManager::NotifyServiceCreated(const ServiceInstance& instance) {
  mojom::RunningServiceInfoPtr info = instance.CreateRunningServiceInfo();
  for (auto& listener : listeners_) {
    listener->OnServiceCreated(info.Clone());
  }
}

void ServiceManager::NotifyServiceStarted(const Identity& identity,
                                          base::ProcessId pid) {
  for (auto& listener : listeners_) {
    listener->OnServiceStarted(identity, pid);
  }
}

void ServiceManager::NotifyServiceFailedToStart(const Identity& identity) {
  for (auto& listener : listeners_) {
    listener->OnServiceFailedToStart(identity);
  }
}

void ServiceManager::NotifyServicePIDReceived(const Identity& identity,
                                              base::ProcessId pid) {
  for (auto& listener : listeners_) {
    listener->OnServicePIDReceived(identity, pid);
  }
}

ServiceInstance* ServiceManager::CreateServiceInstance(
    const Identity& identity,
    const Manifest& manifest) {
  DCHECK(identity.IsValid());

  auto instance = std::make_unique<ServiceInstance>(this, identity, manifest);
  auto* raw_instance = instance.get();

  instances_.insert(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.

  instance_registry_.Register(raw_instance);

  return raw_instance;
}

void ServiceManager::AddListener(
    mojo::PendingRemote<mojom::ServiceManagerListener> listener) {
  std::vector<mojom::RunningServiceInfoPtr> infos;
  for (auto& instance : instances_)
    infos.push_back(instance->CreateRunningServiceInfo());

  mojo::Remote<mojom::ServiceManagerListener> listener_remote;
  listener_remote.Bind(std::move(listener));
  listener_remote->OnInit(std::move(infos));
  listeners_.Add(std::move(listener_remote));
}

void ServiceManager::OnBindInterface(
    const BindSourceInfo& source_info,
    const std::string& interface_name,
    mojo::ScopedMessagePipeHandle receiving_pipe) {
  ServiceInstance* instance = GetExistingInstance(source_info.identity);
  DCHECK(instance);
  if (interface_name == mojom::ServiceManager::Name_) {
    instance->BindServiceManagerReceiver(
        mojo::PendingReceiver<mojom::ServiceManager>(
            std::move(receiving_pipe)));
  }
}

}  // namespace service_manager