1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212

content / public / browser / service_process_host.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_H_
#define CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_H_

#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "base/command_line.h"
#include "base/functional/callback.h"
#include "base/observer_list_types.h"
#include "base/process/process_handle.h"
#include "content/common/content_export.h"
#include "content/public/browser/service_process_info.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_WIN)
#include "base/files/file_path.h"
#include "base/types/pass_key.h"
#endif  // BUILDFLAG(IS_WIN)

namespace base {
class Process;
}  // namespace base

namespace content {
// Passkeys for service process host Options.
class ServiceProcessHostGpuClient;
class ServiceProcessHostPreloadLibraries;

// Sandbox type for ServiceProcessHost::Launch<remote>() is found by
// template matching on |remote|. Consult security-dev@chromium.org and
// add a [ServiceSandbox=type] mojom attribute.
template <typename Interface>
inline sandbox::mojom::Sandbox GetServiceSandboxType() {
  using ProvidedSandboxType = decltype(Interface::kServiceSandbox);
  static_assert(
      std::is_same<ProvidedSandboxType, const sandbox::mojom::Sandbox>::value,
      "This interface does not declare a proper ServiceSandbox attribute. See "
      "//docs/mojo_and_services.md (Specifying a sandbox).");

  return Interface::kServiceSandbox;
}

// ServiceProcessHost is used to launch new service processes given basic
// parameters like sandbox type, as well as a primordial Mojo interface to drive
// the service's behavior. See |Launch()| methods below for more details.
//
// Typical usage might look something like:
//
//   constexpr auto kFooServiceIdleTimeout = base::Seconds(5);
//   auto foo_service = ServiceProcessHost::Launch<foo::mojom::FooService>(
//       ServiceProcessHost::Options()
//           .WithDisplayName(IDS_FOO_SERVICE_DISPLAY_NAME)
//           .Pass());
//   foo_service.set_idle_handler(
//       kFooServiceIdleTimeout,
//       base::BindRepeating(
//           /* Something to reset |foo_service|,  killing the process. */));
//   foo_service->DoWork();
//
class CONTENT_EXPORT ServiceProcessHost {
 public:
  struct CONTENT_EXPORT Options {
    Options();
    ~Options();

    Options(Options&&);

    // Specifies the display name of the service process. This should generally
    // be a human readable and meaningful application or service name and will
    // appear in places like the system task viewer.
    Options& WithDisplayName(const std::string& name);
    Options& WithDisplayName(const std::u16string& name);
    Options& WithDisplayName(int resource_id);

    // Specifies the site associated with the service process, only needed for
    // per-site service processes.
    Options& WithSite(const GURL& url);

    // Specifies additional flags to configure the launched process. See
    // ChildProcessHost for flag definitions.
    Options& WithChildFlags(int flags);

    // Specifies extra command line switches to append before launch.
    Options& WithExtraCommandLineSwitches(std::vector<std::string> switches);

    // Specifies a callback to be invoked with service process once it's
    // launched. Will be on UI thread.
    Options& WithProcessCallback(
        base::OnceCallback<void(const base::Process&)>);

#if BUILDFLAG(IS_WIN)
    // Specifies libraries to preload before the sandbox is locked down. Paths
    // should be absolute paths. Libraries will be preloaded before sandbox
    // lockdown. They should later be "loaded" in the utility process using the
    // same paths after lockdown.
    // Note that preloading does not occur with --no-sandbox - hence the need to
    // load in the utility with the full path - this api exists to make the
    // libraries available for later loading in the sandbox.
    Options& WithPreloadedLibraries(
        std::vector<base::FilePath> preload_libraries,
        base::PassKey<ServiceProcessHostPreloadLibraries> passkey);
#endif  // BUILDFLAG(IS_WIN)

    // Allows the viz.mojom.Gpu client to be bound via the process host on
    // platforms where that is supported. This option will be removed in future.
    // Prefer to avoid setting this option and instead bind the client directly
    // by passing a `pending_receiver<viz.mojom.Gpu>` to the service via mojo.
    Options& WithGpuClient(base::PassKey<ServiceProcessHostGpuClient> passkey);

    // Passes the contents of this Options object to a newly returned Options
    // value. This must be called when moving a built Options object into a call
    // to |Launch()|.
    Options Pass();

    std::u16string display_name;
    std::optional<GURL> site;
    std::optional<int> child_flags;
    std::vector<std::string> extra_switches;
    base::OnceCallback<void(const base::Process&)> process_callback;
#if BUILDFLAG(IS_WIN)
    std::vector<base::FilePath> preload_libraries;
#endif  // BUILDFLAG(IS_WIN)
    std::optional<bool> allow_gpu_client;
  };

  // An interface which can be implemented and registered/unregistered with
  // |Add/RemoveObserver()| below to watch for all service process creation and
  // and termination events globally. Methods are always called from the UI
  // UI thread.
  class CONTENT_EXPORT Observer : public base::CheckedObserver {
   public:
    ~Observer() override {}

    virtual void OnServiceProcessLaunched(const ServiceProcessInfo& info) {}
    virtual void OnServiceProcessTerminatedNormally(
        const ServiceProcessInfo& info) {}
    virtual void OnServiceProcessCrashed(const ServiceProcessInfo& info) {}
  };

  // Launches a new service process for asks it to bind the given interface
  // receiver. |Interface| must be a service interface known to utility process
  // code. See content/utility/services.cc and/or
  // ContentUtilityClient::Run{Main,IO}ThreadService() methods.
  //
  // The launched process will (disregarding crashes) stay alive until either
  // end of the |Interface| pipe is closed. Typically services are designed to
  // never close their end of this pipe, and it's up to the browser to
  // explicitly reset its corresponding Remote in order to induce service
  // process termination.
  //
  // The launched process will be sandboxed using the default utility process
  // sandbox unless a specialized GetServiceSandboxType<Interface> is available.
  // To add a new specialization, consult with security-dev@chromium.org.
  //
  // NOTE: The |Interface| type can be inferred from from the |receiver|
  // argument's type.
  //
  // May be called from any thread.
  template <typename Interface>
  static void Launch(mojo::PendingReceiver<Interface> receiver,
                     Options options = {}) {
    Launch(mojo::GenericPendingReceiver(std::move(receiver)),
           std::move(options), content::GetServiceSandboxType<Interface>());
  }

  // Same as above but creates a new |Interface| pipe on the caller's behalf and
  // returns its Remote endpoint.
  //
  // May be called from any thread.
  template <typename Interface>
  static mojo::Remote<Interface> Launch(Options options = {}) {
    mojo::Remote<Interface> remote;
    Launch(remote.BindNewPipeAndPassReceiver(), std::move(options),
           content::GetServiceSandboxType<Interface>());
    return remote;
  }

  // Yields information about currently active service processes. Must be called
  // from the UI Thread only.
  static std::vector<ServiceProcessInfo> GetRunningProcessInfo();

  // Registers a global observer of all service process lifetimes. Must be
  // removed before destruction. Must be called from the UI thread only.
  static void AddObserver(Observer* observer);

  // Removes a registered observer. This must be called some time before
  // |*observer| is destroyed and must be called from the UI thread only.
  static void RemoveObserver(Observer* observer);

 private:
  // Launches a new service process and asks it to bind a receiver for the
  // service interface endpoint carried by |receiver|, which should be connected
  // to a Remote of the same interface type.
  static void Launch(mojo::GenericPendingReceiver receiver,
                     Options options,
                     sandbox::mojom::Sandbox sandbox);
};

}  // namespace content

#endif  // CONTENT_PUBLIC_BROWSER_SERVICE_PROCESS_HOST_H_