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

content / browser / gpu / gpu_process_host.h [blame]

// Copyright 2012 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_BROWSER_GPU_GPU_PROCESS_HOST_H_
#define CONTENT_BROWSER_GPU_GPU_PROCESS_HOST_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <set>
#include <string>

#include "base/atomicops.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/viz/host/gpu_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_child_process_host_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/shm_count.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/gpu_mode.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
#include "services/viz/privileged/mojom/gl/gpu_host.mojom.h"
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
#include "services/viz/privileged/mojom/viz_main.mojom.h"
#include "ui/gfx/gpu_extra_info.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_WIN)
#include "services/viz/privileged/mojom/gl/info_collection_gpu_service.mojom.h"
#endif

namespace base {
class Thread;
}

namespace content {
class BrowserChildProcessHostImpl;

#if BUILDFLAG(IS_MAC)
class BrowserChildProcessBackgroundedBridge;
class CATransactionGPUCoordinator;
#endif

class GpuProcessHost : public BrowserChildProcessHostDelegate,
                       public viz::GpuHostImpl::Delegate {
 public:
  static int GetGpuCrashCount();

  // Creates a new GpuProcessHost (if |force_create| is turned on) or gets an
  // existing one, resulting in the launching of a GPU process if required.
  // Returns null on failure. It is not safe to store the pointer once control
  // has returned to the message loop as it can be destroyed. Instead store the
  // associated GPU host ID.  This could return NULL if GPU access is not
  // allowed (blocklisted).
  CONTENT_EXPORT static GpuProcessHost* Get(
      GpuProcessKind kind = GPU_PROCESS_KIND_SANDBOXED,
      bool force_create = true);

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

  // Returns whether there is an active GPU process or not.
  static void GetHasGpuProcess(base::OnceCallback<void(bool)> callback);

  // Helper function to run a callback on the UI thread. The callback receives
  // the appropriate GpuProcessHost instance. Note that the callback can be
  // called with a null host (e.g. when |force_create| is false, and no
  // GpuProcessHost instance exists).
  CONTENT_EXPORT static void CallOnUI(
      const base::Location& location,
      GpuProcessKind kind,
      bool force_create,
      base::OnceCallback<void(GpuProcessHost*)> callback);

  // Get the GPU process host for the GPU process with the given ID. Returns
  // null if the process no longer exists.
  static GpuProcessHost* FromID(int host_id);
  int host_id() const { return host_id_; }
  base::ProcessId process_id() const { return process_id_; }

  // What kind of GPU process, e.g. sandboxed or unsandboxed.
  GpuProcessKind kind();

  // Forcefully terminates the GPU process.
  void ForceShutdown();

  // Dumps the stack of the child process without crashing it.
  // Only implemented on Android.
  void DumpProcessStack();

  // Asks the GPU process to run a service instance corresponding to the
  // specific interface receiver type carried by |receiver|. The interface must
  // have the [ServiceSandbox=sandbox.mojom.Sandbox.kGpu] mojom attribute.
  template <typename Interface>
  void RunService(mojo::PendingReceiver<Interface> receiver) {
    // Note: consult chrome-security before changing these asserts.
    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).");
    static_assert(Interface::kServiceSandbox == sandbox::mojom::Sandbox::kGpu,
                  "This interface must have [ServiceSandbox=kGpu].");
    return RunServiceImpl(std::move(receiver));
  }

  CONTENT_EXPORT viz::mojom::GpuService* gpu_service();

#if BUILDFLAG(IS_WIN)
  CONTENT_EXPORT viz::mojom::InfoCollectionGpuService*
  info_collection_gpu_service();
#endif

  CONTENT_EXPORT int GetIDForTesting() const;

  viz::GpuHostImpl* gpu_host() { return gpu_host_.get(); }

#if BUILDFLAG(IS_MAC)
  BrowserChildProcessBackgroundedBridge*
  browser_child_process_backgrounded_bridge_for_testing() {
    return browser_child_process_backgrounded_bridge_.get();
  }
#endif

 private:
  enum class GpuTerminationOrigin {
    kUnknownOrigin = 0,
    kOzoneWaylandProxy = 1,
    kMax = 2,
  };

  static bool ValidateHost(GpuProcessHost* host);

  // Increments |recent_crash_count_| by one. Before incrementing, remove one
  // old crash for each forgiveness interval that has passed since the previous
  // crash. If |gpu_mode| doesn't match |last_crash_mode_|, first reset the
  // crash count.
  static void IncrementCrashCount(gpu::GpuMode gpu_mode);

  GpuProcessHost(int host_id, GpuProcessKind kind);
  ~GpuProcessHost() override;

  bool Init();

  // BrowserChildProcessHostDelegate implementation.
  void OnProcessLaunched() override;
  void OnProcessLaunchFailed(int error_code) override;
  void OnProcessCrashed(int exit_code) override;

  // viz::GpuHostImpl::Delegate:
  gpu::GPUInfo GetGPUInfo() const override;
  gpu::GpuFeatureInfo GetGpuFeatureInfo() const override;
  void DidInitialize(
      const gpu::GPUInfo& gpu_info,
      const gpu::GpuFeatureInfo& gpu_feature_info,
      const std::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
      const std::optional<gpu::GpuFeatureInfo>&
          gpu_feature_info_for_hardware_gpu,
      const gfx::GpuExtraInfo& gpu_extra_info) override;
  void DidFailInitialize() override;
  void DidCreateContextSuccessfully() override;
  void MaybeShutdownGpuProcess() override;
  void DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) override;
#if BUILDFLAG(IS_WIN)
  void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
  void DidUpdateDXGIInfo(gfx::mojom::DXGIInfoPtr dxgi_info) override;
#endif
  std::string GetIsolationKey(
      int32_t process_id,
      const blink::WebGPUExecutionContextToken& token) override;
  void BlockDomainsFrom3DAPIs(const std::set<GURL>& urls,
                              gpu::DomainGuilt guilt) override;
  void DisableGpuCompositing() override;
  bool GpuAccessAllowed() const override;
  gpu::GpuDiskCacheFactory* GetGpuDiskCacheFactory() override;
  void RecordLogMessage(int32_t severity,
                        const std::string& header,
                        const std::string& message) override;
  void BindDiscardableMemoryReceiver(
      mojo::PendingReceiver<
          discardable_memory::mojom::DiscardableSharedMemoryManager> receiver)
      override;
  void BindInterface(const std::string& interface_name,
                     mojo::ScopedMessagePipeHandle interface_pipe) override;
  void BindHostReceiver(mojo::GenericPendingReceiver generic_receiver) override;
#if BUILDFLAG(IS_OZONE)
  void TerminateGpuProcess(const std::string& message) override;
#endif

  bool LaunchGpuProcess();

  void SendOutstandingReplies();

  void BlockLiveOffscreenContexts();

  // Update GPU crash counters.  Disable GPU if crash limit is reached.
  void RecordProcessCrash();
  int GetFallbackCrashLimit() const;

  void RunServiceImpl(mojo::GenericPendingReceiver receiver);

#if !BUILDFLAG(IS_ANDROID)
  // Memory pressure handler, called by |memory_pressure_listener_|.
  void OnMemoryPressure(
      base::MemoryPressureListener::MemoryPressureLevel level);
#endif

  // The serial number of the GpuProcessHost.
  int host_id_;

  // GPU process id in case GPU is not in-process.
  base::ProcessId process_id_ = base::kNullProcessId;

  // Whether the GPU process is valid, set to false after Send() failed.
  bool valid_;

  // Whether we are running a GPU thread inside the browser process instead
  // of a separate GPU process.
  bool in_process_;

  GpuProcessKind kind_;

  gpu::GpuMode mode_ = gpu::GpuMode::UNKNOWN;

  // Whether we actually launched a GPU process.
  bool process_launched_;

  GpuTerminationOrigin termination_origin_ =
      GpuTerminationOrigin::kUnknownOrigin;

  // Time Init started.  Used to log total GPU process startup time to UMA.
  base::TimeTicks init_start_time_;

  // The GPU process reported failure to initialize.
  bool did_fail_initialize_ = false;

  // The total number of GPU process crashes.
  static base::subtle::Atomic32 gpu_crash_count_;
  static bool crashed_before_;
  static int recent_crash_count_;
  static gpu::GpuMode last_crash_mode_;

  // Here the bottom-up destruction order matters:
  // The GPU thread depends on its host so stop the host last.
  // Otherwise, under rare timings when the thread is still in Init(),
  // it could crash as it fails to find a message pipe to the host.
  std::unique_ptr<BrowserChildProcessHostImpl> process_;
  std::unique_ptr<base::Thread> in_process_gpu_thread_;

#if BUILDFLAG(IS_MAC)
  scoped_refptr<CATransactionGPUCoordinator> ca_transaction_gpu_coordinator_;

  // Ensures the backgrounded state of the GPU process mirrors the backgrounded
  // state of the browser process.
  std::unique_ptr<BrowserChildProcessBackgroundedBridge>
      browser_child_process_backgrounded_bridge_;
#endif

  // Track the URLs of the pages which have live offscreen contexts,
  // assumed to be associated with untrusted content such as WebGL.
  // For best robustness, when any context lost notification is
  // received, assume all of these URLs are guilty, and block
  // automatic execution of 3D content from those domains.
  std::multiset<GURL> urls_with_live_offscreen_contexts_;

#if !BUILDFLAG(IS_ANDROID)
  // Responsible for forwarding the memory pressure notifications from the
  // browser process to the GPU process.
  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
#endif

  std::unique_ptr<viz::GpuHostImpl> gpu_host_;

  base::WeakPtrFactory<GpuProcessHost> weak_ptr_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_GPU_GPU_PROCESS_HOST_H_