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
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360
  361
  362
  363
  364
  365
  366
  367
  368
  369
  370
  371
  372
  373
  374
  375
  376
  377

base / process / process.h [blame]

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

#ifndef BASE_PROCESS_PROCESS_H_
#define BASE_PROCESS_PROCESS_H_

#include <string_view>

#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "build/blink_buildflags.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_handle.h"
#endif

#if BUILDFLAG(IS_FUCHSIA)
#include <lib/zx/process.h>
#endif

#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#include "base/feature_list.h"
#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_APPLE)
#include "base/process/port_provider_mac.h"
#endif  // BUILDFLAG(IS_APPLE)

namespace base {

#if BUILDFLAG(IS_CHROMEOS)
// OneGroupPerRenderer feature places each foreground renderer process into
// its own cgroup. This will cause the scheduler to use the aggregate runtime
// of all threads in the process when deciding on the next thread to schedule.
// It will help guarantee fairness between renderers.
BASE_EXPORT BASE_DECLARE_FEATURE(kOneGroupPerRenderer);

// Set all threads of a background process as backgrounded, which changes the
// thread attributes including c-group, latency sensitivity. But the nice value
// is unchanged, since background process is under the spell of the background
// CPU c-group (via cgroup.procs).
BASE_EXPORT BASE_DECLARE_FEATURE(kSetThreadBgForBgProcess);

class ProcessPriorityDelegate;
#endif

// Provides a move-only encapsulation of a process.
//
// This object is not tied to the lifetime of the underlying process: the
// process may be killed and this object may still around, and it will still
// claim to be valid. The actual behavior in that case is OS dependent like so:
//
// Windows: The underlying ProcessHandle will be valid after the process dies
// and can be used to gather some information about that process, but most
// methods will obviously fail.
//
// POSIX: The underlying ProcessHandle is not guaranteed to remain valid after
// the process dies, and it may be reused by the system, which means that it may
// end up pointing to the wrong process.
class BASE_EXPORT Process {
 public:
  // On Windows, this takes ownership of |handle|. On POSIX, this does not take
  // ownership of |handle|.
  explicit Process(ProcessHandle handle = kNullProcessHandle);

  Process(Process&& other);

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

  // The destructor does not terminate the process.
  ~Process();

  Process& operator=(Process&& other);

  // Returns an object for the current process.
  static Process Current();

  // Returns a Process for the given |pid|.
  static Process Open(ProcessId pid);

  // Returns a Process for the given |pid|. On Windows the handle is opened
  // with more access rights and must only be used by trusted code (can read the
  // address space and duplicate handles).
  static Process OpenWithExtraPrivileges(ProcessId pid);

#if BUILDFLAG(IS_WIN)
  // Returns a Process for the given |pid|, using some |desired_access|.
  // See ::OpenProcess documentation for valid |desired_access|.
  static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
#endif

  // Returns true if changing the priority of processes through `SetPriority()`
  // is possible.
  static bool CanSetPriority();

  // Terminates the current process immediately with |exit_code|.
  [[noreturn]] static void TerminateCurrentProcessImmediately(int exit_code);

  // Returns true if this objects represents a valid process.
  bool IsValid() const;

  // Returns a handle for this process. There is no guarantee about when that
  // handle becomes invalid because this object retains ownership.
  ProcessHandle Handle() const;

  // Returns a second object that represents this process.
  Process Duplicate() const;

  // Relinquishes ownership of the handle and sets this to kNullProcessHandle.
  // The result may be a pseudo-handle, depending on the OS and value stored in
  // this.
  [[nodiscard]] ProcessHandle Release();

  // Get the PID for this process.
  ProcessId Pid() const;

  // Get the creation time for this process. Since the Pid can be reused after a
  // process dies, it is useful to use both the Pid and the creation time to
  // uniquely identify a process.
  //
  // On Android, works only if |this| is the current process, as security
  // features prevent an application from getting data about other processes,
  // even if they belong to us. Otherwise, returns Time().
  Time CreationTime() const;

  // Returns true if this process is the current process.
  bool is_current() const;

#if BUILDFLAG(IS_CHROMEOS)
  // A unique token generated for each process, this is used to create a unique
  // cgroup for each renderer.
  const std::string& unique_token() const LIFETIME_BOUND {
    return unique_token_;
  }
#endif

  // Close the process handle. This will not terminate the process.
  void Close();

  // Returns true if this process is still running. This is only safe on Windows
  // (and maybe Fuchsia?), because the ProcessHandle will keep the zombie
  // process information available until itself has been released. But on Posix,
  // the OS may reuse the ProcessId.
#if BUILDFLAG(IS_WIN)
  bool IsRunning() const {
    return !WaitForExitWithTimeout(base::TimeDelta(), nullptr);
  }
#endif

  // Terminates the process with extreme prejudice. The given |exit_code| will
  // be the exit code of the process. If |wait| is true, this method will wait
  // for up to one minute for the process to actually terminate.
  // Returns true if the process terminates within the allowed time.
  // NOTE: |exit_code| is only used on OS_WIN.
  bool Terminate(int exit_code, bool wait) const;

#if BUILDFLAG(IS_WIN)
  enum class WaitExitStatus {
    PROCESS_EXITED,
    STOP_EVENT_SIGNALED,
    FAILED,
  };

  // Waits for the process to exit, or the specified |stop_event_handle| to be
  // set. Returns value indicating which event was set. The given |exit_code|
  // will be the exit code of the process.
  WaitExitStatus WaitForExitOrEvent(
      const base::win::ScopedHandle& stop_event_handle,
      int* exit_code) const;
#endif  // BUILDFLAG(IS_WIN)

  // Waits for the process to exit. Returns true on success.
  // On POSIX, if the process has been signaled then |exit_code| is set to -1.
  // On Linux this must be a child process, however on Mac and Windows it can be
  // any process.
  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code is
  // not required.
  bool WaitForExit(int* exit_code) const;

  // Same as WaitForExit() but only waits for up to |timeout|.
  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code
  // is not required.
  bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const;

  // Indicates that the process has exited with the specified |exit_code|.
  // This should be called if process exit is observed outside of this class.
  // (i.e. Not because Terminate or WaitForExit, above, was called.)
  // Note that nothing prevents this being called multiple times for a dead
  // process though that should be avoided.
  void Exited(int exit_code) const;

  // The different priorities that a process can have.
  // TODO(pmonette): Consider merging with base::TaskPriority when the API is
  //                 stable.
  enum class Priority {
    // The process does not contribute to content that is currently important
    // to the user. Lowest priority.
    kBestEffort,

    // The process contributes to content that is visible to the user, but the
    // work don't have significant performance or latency requirement, so it can
    // run in energy efficient manner. Moderate priority.
    kUserVisible,

    // The process contributes to content that is of the utmost importance to
    // the user, like producing audible content, or visible content in the
    // main frame. High priority.
    kUserBlocking,

    kMaxValue = kUserBlocking,
  };

#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK))
  // The Mac needs a Mach port in order to manipulate a process's priority,
  // and there's no good way to get that from base given the pid. These Mac
  // variants of the `GetPriority()` and `SetPriority()` API take a port
  // provider for this reason. See crbug.com/460102.

  // Retrieves the priority of the process. Defaults to Priority::kUserBlocking
  // if the priority could not be retrieved, or if `port_provider` is null.
  Priority GetPriority(PortProvider* port_provider) const;

  // Sets the priority of the process process. Returns true if the priority was
  // changed, false otherwise. If `port_provider` is null, this is a no-op and
  // it returns false.
  bool SetPriority(PortProvider* port_provider, Priority priority);
#else
  // Retrieves the priority of the process. Defaults to Priority::kUserBlocking
  // if the priority could not be retrieved.
  Priority GetPriority() const;

  // Sets the priority of the process process. Returns true if the priority was
  // changed, false otherwise.
  bool SetPriority(Priority priority);
#endif  // BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK))

  // Returns an integer representing the priority of a process. The meaning
  // of this value is OS dependent.
  int GetOSPriority() const;

#if BUILDFLAG(IS_CHROMEOS_ASH)
  // Get the PID in its PID namespace.
  // If the process is not in a PID namespace or /proc/<pid>/status does not
  // report NSpid, kNullProcessId is returned.
  ProcessId GetPidInNamespace() const;
#endif

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  // Returns true if the process has any seccomp policy applied.
  bool IsSeccompSandboxed();
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_CHROMEOS)
  // Sets a delegate which handles process priority changes. This
  // must be externally synchronized with any call to base::Process methods.
  static void SetProcessPriorityDelegate(ProcessPriorityDelegate* delegate);

  // Exposes OneGroupPerRendererEnabled() to unit tests.
  static bool OneGroupPerRendererEnabledForTesting();

  // If OneGroupPerRenderer is enabled, runs at process startup to clean up
  // any stale cgroups that were left behind from any unclean exits of the
  // browser process.
  static void CleanUpStaleProcessStates();

  // Initializes the process's priority.
  //
  // This should be called before SetPriority().
  //
  // If SchedQoSOnResourcedForChrome is enabled, this creates a cache entry for
  // the process priority. The returned `base::Process::PriorityEntry` should be
  // freed when the process is terminated so that the cached entry is freed from
  // the internal map.
  //
  // If OneGroupPerRenderer is enabled, it also creates a unique cgroup for the
  // process.
  // This is a no-op if the Process is not valid or if it has already been
  // called.
  void InitializePriority();

  // Clears the entities initialized by InitializePriority().
  //
  // This is no-op if SchedQoSOnResourcedForChrome is disabled.
  void ForgetPriority();
#endif  // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_APPLE)
  // Sets the priority of the current process to its default value.
  static void SetCurrentTaskDefaultRole();
#endif  // BUILDFLAG(IS_MAC)

#if BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK)
  using TerminateCallback = bool (*)(ProcessHandle handle);
  using WaitForExitCallback = bool (*)(ProcessHandle handle,
                                       int* exit_code,
                                       base::TimeDelta timeout);
  // Function ptrs to implement termination without polluting //base with
  // BrowserEngineKit APIs.
  static void SetTerminationHooks(TerminateCallback terminate_callback,
                                  WaitForExitCallback wait_callback);
#if TARGET_OS_SIMULATOR
  // Methods for supporting both "content processes" and traditional
  // forked processes. For non-simulator builds on iOS every process would
  // be a "content process" so we don't need the conditionals.
  void SetIsContentProcess();
  bool IsContentProcess() const;
#endif
#endif

 private:
#if BUILDFLAG(IS_CHROMEOS)
  // Cleans up process state. If OneGroupPerRenderer is enabled, it cleans up
  // the cgroup created by InitializePriority(). If the process has not
  // fully terminated yet, it will post a background task to try again.
  void CleanUpProcess(int remaining_retries) const;

  // Calls CleanUpProcess() on a background thread.
  void CleanUpProcessAsync() const;

  // Used to call CleanUpProcess() on a background thread because Process is not
  // refcounted.
  static void CleanUpProcessScheduled(Process process, int remaining_retries);
#endif  // BUILDFLAG(IS_CHROMEOS)

#if !BUILDFLAG(IS_IOS) || (BUILDFLAG(IS_IOS) && TARGET_OS_SIMULATOR)
  bool TerminateInternal(int exit_code, bool wait) const;
  bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
                                  int* exit_code,
                                  base::TimeDelta timeout) const;
#endif

#if BUILDFLAG(IS_WIN)
  win::ScopedHandle process_;
#elif BUILDFLAG(IS_FUCHSIA)
  zx::process process_;
#else
  ProcessHandle process_;
#endif

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA)
  bool is_current_process_;
#endif

#if BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK) && TARGET_OS_SIMULATOR
  // A flag indicating that this is a "content process". iOS does not support
  // generic process invocation but it does support some types of well defined
  // processes. These types of processes are defined at the //content layer so
  // for termination we defer to some globally initialized callbacks.
  bool content_process_ = false;
#endif

#if BUILDFLAG(IS_CHROMEOS)
  // A unique token per process not per class instance (`base::Process`). This
  // is similar to the PID of a process but should not be reused after the
  // process's termination. The token will be copied during Duplicate()
  // and move semantics as is the PID/ProcessHandle.
  std::string unique_token_;
#endif
};

#if BUILDFLAG(IS_CHROMEOS)
// Exposed for testing.
// Given the contents of the /proc/<pid>/cgroup file, determine whether the
// process is backgrounded or not.
BASE_EXPORT Process::Priority GetProcessPriorityCGroup(
    std::string_view cgroup_contents);
#endif  // BUILDFLAG(IS_CHROMEOS)

}  // namespace base

#endif  // BASE_PROCESS_PROCESS_H_