#include "content/browser/gpu/gpu_process_host.h"
#include <stddef.h>
#include <algorithm>
#include <array>
#include <list>
#include <memory>
#include <utility>
#include "ash/constants/ash_switches.h"
#include "arkweb/build/features/features.h"
#include "arkweb/chromium_ext/base/process/process_handle_posix_ex.h"
#include "arkweb/chromium_ext/content/browser/renderer_host/arkweb_render_process_host_impl_utils.h"
#if BUILDFLAG(ARKWEB_REPORT_SYS_EVENT)
#include "arkweb/chromium_ext/third_party/crashpad/crashpad/util/linux/crashpad_dfx.h"
#endif
#include "base/base64.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_pump_type.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "components/tracing/common/tracing_switches.h"
#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
#include "components/viz/host/persistent_cache_sandboxed_file_factory.h"
#include "content/browser/browser_child_process_host_impl.h"
#include "content/browser/child_process_host_impl.h"
#include "content/browser/child_process_launcher.h"
#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_disk_cache_factory.h"
#include "content/browser/gpu/gpu_main_thread_factory.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_host.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/worker_host/dedicated_worker_host.h"
#include "content/browser/worker_host/dedicated_worker_service_impl.h"
#include "content/browser/worker_host/shared_worker_host.h"
#include "content/browser/worker_host/shared_worker_service_impl.h"
#include "content/common/child_process.mojom.h"
#include "content/common/features.h"
#include "content/common/in_process_child_thread_params.h"
#include "content/public/browser/browser_child_process_host.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/gpu_utils.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "content/public/common/zygote/zygote_buildflags.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/config/gpu_driver_bug_list.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/common/result_codes.h"
#include "gpu/ipc/host/gpu_disk_cache.h"
#include "media/base/media_switches.h"
#include "media/media_buildflags.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/network_isolation_key.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "sandbox/policy/sandbox_type.h"
#include "sandbox/policy/switches.h"
#include "services/webnn/buildflags.h"
#include "services/webnn/webnn_switches.h"
#include "skia/buildflags.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display_switches.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_features.h"
#include "ui/gl/gl_switches.h"
#include "ui/latency/latency_info.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#else
#include "components/metrics/stability_metrics_helper.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "base/win/access_token.h"
#include "base/win/security_descriptor.h"
#include "base/win/win_util.h"
#include "components/app_launch_prefetch/app_launch_prefetch.h"
#include "sandbox/policy/win/sandbox_win.h"
#include "sandbox/win/src/sandbox_policy.h"
#include "sandbox/win/src/window.h"
#include "ui/gfx/win/rendering_window_manager.h"
#endif
#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/ozone_switches.h"
#endif
#if BUILDFLAG(USE_ZYGOTE)
#include "content/common/zygote/zygote_handle_impl_linux.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "content/browser/gpu/browser_child_process_backgrounded_bridge.h"
#include "content/browser/gpu/ca_transaction_gpu_coordinator.h"
#endif
#if BUILDFLAG(ARKWEB_OOP_GPU_PROCESS)
#include "content/browser/renderer_host/render_process_host_impl.h"
#endif
#if BUILDFLAG(ARKWEB_PERFORMANCE_SCHEDULING)
#include "third_party/ohos_ndk/includes/ohos_adapter/res_sched_client_adapter.h"
#endif
namespace content {
base::subtle::Atomic32 GpuProcessHost::gpu_crash_count_ = 0;
bool GpuProcessHost::crashed_before_ = false;
int GpuProcessHost::recent_crash_count_ = 0;
gpu::GpuMode GpuProcessHost::last_crash_mode_ = gpu::GpuMode::UNKNOWN;
static_assert(RESULT_CODE_HUNG == static_cast<int>(gpu::RESULT_CODE_HUNG),
"Please use the same enum value in both header files.");
namespace {
constexpr char kFallbackEventCause[] = "GPU.FallbackEventCause";
constexpr char kProcessLifetimeEventsHardwareAccelerated[] =
"GPU.ProcessLifetimeEvents.HardwareAccelerated";
constexpr char kProcessLifetimeEventsSwiftShader[] =
"GPU.ProcessLifetimeEvents.SwiftShader";
const char* GetProcessLifetimeUmaName(gpu::GpuMode gpu_mode) {
switch (gpu_mode) {
case gpu::GpuMode::UNKNOWN:
NOTREACHED();
case gpu::GpuMode::HARDWARE_GL:
case gpu::GpuMode::HARDWARE_GRAPHITE:
case gpu::GpuMode::HARDWARE_VULKAN:
return kProcessLifetimeEventsHardwareAccelerated;
case gpu::GpuMode::SOFTWARE_GL:
return kProcessLifetimeEventsSwiftShader;
case gpu::GpuMode::DISPLAY_COMPOSITOR:
return nullptr;
}
}
constexpr int kForgiveGpuCrashMinutes = 5;
constexpr int kForgiveDisplayCompositorCrashMinutes = 10;
int GetForgiveMinutes(gpu::GpuMode gpu_mode) {
return gpu_mode == gpu::GpuMode::DISPLAY_COMPOSITOR
? kForgiveDisplayCompositorCrashMinutes
: kForgiveGpuCrashMinutes;
}
enum class GpuTerminationStatus {
NORMAL_TERMINATION = 0,
ABNORMAL_TERMINATION = 1,
PROCESS_WAS_KILLED = 2,
PROCESS_CRASHED = 3,
STILL_RUNNING = 4,
PROCESS_WAS_KILLED_BY_OOM = 5,
OOM_PROTECTED = 6,
LAUNCH_FAILED = 7,
OOM = 8,
MAX_ENUM = 9,
};
GpuTerminationStatus ConvertToGpuTerminationStatus(
base::TerminationStatus status) {
switch (status) {
case base::TERMINATION_STATUS_NORMAL_TERMINATION:
return GpuTerminationStatus::NORMAL_TERMINATION;
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
return GpuTerminationStatus::ABNORMAL_TERMINATION;
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
return GpuTerminationStatus::PROCESS_WAS_KILLED;
case base::TERMINATION_STATUS_PROCESS_CRASHED:
#if BUILDFLAG(IS_WIN)
case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
#endif
return GpuTerminationStatus::PROCESS_CRASHED;
case base::TERMINATION_STATUS_STILL_RUNNING:
return GpuTerminationStatus::STILL_RUNNING;
#if BUILDFLAG(IS_CHROMEOS)
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
return GpuTerminationStatus::PROCESS_WAS_KILLED_BY_OOM;
#endif
#if BUILDFLAG(IS_ANDROID)
case base::TERMINATION_STATUS_OOM_PROTECTED:
return GpuTerminationStatus::OOM_PROTECTED;
#endif
case base::TERMINATION_STATUS_LAUNCH_FAILED:
return GpuTerminationStatus::LAUNCH_FAILED;
case base::TERMINATION_STATUS_OOM:
return GpuTerminationStatus::OOM;
case base::TERMINATION_STATUS_EVICTED_FOR_MEMORY:
return GpuTerminationStatus::OOM;
case base::TERMINATION_STATUS_MAX_ENUM:
NOTREACHED();
}
NOTREACHED();
}
static const char* const kSwitchNames[] = {
sandbox::policy::switches::kDisableSeccompFilterSandbox,
sandbox::policy::switches::kGpuSandboxAllowSysVShm,
sandbox::policy::switches::kGpuSandboxFailuresFatal,
sandbox::policy::switches::kDisableGpuSandbox,
sandbox::policy::switches::kDisableLandlockSandbox,
sandbox::policy::switches::kNoSandbox,
#if BUILDFLAG(IS_WIN)
sandbox::policy::switches::kAllowThirdPartyModules,
#endif
#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
switches::kDisableDevShmUsage,
#endif
#if BUILDFLAG(IS_WIN)
switches::kDisableHighResTimer,
switches::kRaiseTimerFrequency,
switches::kUseRedistributableDirectML,
#endif
#if BUILDFLAG(ARKWEB_OOP_GPU_PROCESS)
switches::kOhosEnableDrDc,
#endif
#if BUILDFLAG(ARKWEB_VULKAN)
switches::kOhosEnableVulkan,
#endif
switches::kBackgroundThreadPoolFieldTrial,
switches::kEnableANGLEFeatures,
switches::kDelegatedInkRenderer,
switches::kDisableANGLEFeatures,
switches::kDisableBreakpad,
switches::kDisableGpuRasterization,
switches::kDisableGLExtensions,
switches::kDisableMipmapGeneration,
switches::kDisableShaderNameHashing,
switches::kDisableSkiaRuntimeOpts,
switches::kDRMVirtualConnectorIsExternal,
switches::kDumpCompositorFrame,
switches::kEnableGpuMainTimeKeeperMetrics,
switches::kEnableGpuRasterization,
switches::kEnableSkiaGraphite,
switches::kEnableSkiaGraphitePrecompilation,
switches::kDoubleBufferCompositing,
switches::kHeadless,
switches::kEnableLowEndDeviceMode,
switches::kDisableSkiaGraphite,
switches::kDisableSkiaGraphitePrecompilation,
switches::kDisableLowEndDeviceMode,
switches::kProfilingAtStart,
switches::kProfilingFile,
switches::kProfilingFlush,
switches::kRunAllCompositorStagesBeforeDraw,
switches::kSkiaFontCacheLimitMb,
switches::kSkiaGraphiteBackend,
switches::kSkiaResourceCacheLimitMb,
switches::kTestGLLib,
switches::kUseAdapterLuid,
switches::kUseFakeMjpegDecodeAccelerator,
switches::kUseGpuInTests,
switches::kWebViewDrawFunctorUsesVulkan,
switches::kSuppressPerformanceLogs,
#if BUILDFLAG(IS_MAC)
sandbox::policy::switches::kEnableSandboxLogging,
sandbox::policy::switches::kDisableMetalShaderCache,
switches::kShowMacOverlayBorders,
#endif
#if BUILDFLAG(IS_OZONE)
switches::kOzonePlatform,
switches::kDisableExplicitDmaFences,
switches::kOzoneDumpFile,
switches::kEnableNativeGpuMemoryBuffers,
switches::kRenderNodeOverride,
#endif
#if BUILDFLAG(IS_LINUX)
switches::kX11Display,
switches::kNoXshm,
#endif
switches::kGpuBlocklistTestGroup,
switches::kGpuDriverBugListTestGroup,
switches::kGpuWatchdogTimeoutSeconds,
switches::kUseCmdDecoder,
switches::kForceVideoOverlays,
switches::kSkiaGraphiteBackend,
#if BUILDFLAG(IS_ANDROID)
switches::kDisableAdpf,
#endif
#if BUILDFLAG(IS_CHROMEOS)
ash::switches::kRevenBranding,
switches::kSchedulerBoostUrgent,
#endif
#if BUILDFLAG(USE_V4L2_CODEC)
switches::kHardwareVideoDecodeFrameRate,
#endif
};
enum class GPUFallbackEventCauseType {
kFailureToInit = 0,
kCrashLimit = 1,
kMaxValue = kCrashLimit,
};
enum GPUProcessLifetimeEvent {
LAUNCHED = 0,
DIED_FIRST_TIME = 1,
GPU_PROCESS_LIFETIME_EVENT_MAX = 100,
};
std::array<GpuProcessHost*, GPU_PROCESS_KIND_COUNT> g_gpu_process_hosts;
static void RunCallbackOnUI(
GpuProcessKind kind,
bool force_create,
base::OnceCallback<void(GpuProcessHost*)> callback) {
GpuProcessHost* host = GpuProcessHost::Get(kind, force_create);
std::move(callback).Run(host);
}
void OnGpuProcessHostDestroyedOnUI(int host_id, const std::string& message) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GpuDataManagerImpl::GetInstance()->AddLogMessage(logging::LOGGING_ERROR,
"GpuProcessHost", message);
#if BUILDFLAG(IS_OZONE)
ui::OzonePlatform::GetInstance()
->GetGpuPlatformSupportHost()
->OnChannelDestroyed(host_id);
#endif
}
class GpuSandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
public:
explicit GpuSandboxedProcessLauncherDelegate(
const base::CommandLine& cmd_line)
: cmd_line_(cmd_line) {}
~GpuSandboxedProcessLauncherDelegate() override = default;
#if BUILDFLAG(IS_WIN)
bool DisableDefaultPolicy() override { return true; }
std::string GetSandboxTag() override {
return sandbox::policy::SandboxWin::GetSandboxTagForDelegate(
"gpu", GetSandboxType());
}
bool InitializeConfig(sandbox::TargetConfig* config) override {
DCHECK(!config->IsConfigured());
sandbox::ResultCode result = config->SetTokenLevel(
sandbox::USER_RESTRICTED_SAME_ACCESS, sandbox::USER_LIMITED);
if (result != sandbox::SBOX_ALL_OK) {
return false;
}
result = sandbox::policy::SandboxWin::SetJobLevel(
sandbox::mojom::Sandbox::kGpu, sandbox::JobLevel::kLimitedUser,
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_DESKTOP |
JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS,
config);
if (result != sandbox::SBOX_ALL_OK) {
return false;
}
if (ShouldSetDelayedIntegrity()) {
config->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
} else {
result = config->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
if (result != sandbox::SBOX_ALL_OK)
return false;
}
config->AddDllToUnload(L"cmsetac.dll");
return true;
}
#endif
#if BUILDFLAG(USE_ZYGOTE)
ZygoteCommunication* GetZygote() override {
if (sandbox::policy::IsUnsandboxedSandboxType(GetSandboxType()))
return nullptr;
return GetUnsandboxedZygote();
}
#endif
sandbox::mojom::Sandbox GetSandboxType() override {
if (cmd_line_.HasSwitch(sandbox::policy::switches::kDisableGpuSandbox)) {
DVLOG(1) << "GPU sandbox is disabled";
return sandbox::mojom::Sandbox::kNoSandbox;
}
return sandbox::mojom::Sandbox::kGpu;
}
private:
#if BUILDFLAG(IS_WIN)
enum class ProcessIntegrityResult{
kLowIl = 0,
kOpenGlMediumIl = 1,
kDesktopAccessMediumIl = 2,
kMaxValue = kDesktopAccessMediumIl,
};
bool CanLowIntegrityAccessDesktop() {
DWORD desired_access = DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS;
HDESK hdesk = ::GetThreadDesktop(GetCurrentThreadId());
std::optional<base::win::SecurityDescriptor> sd =
base::win::SecurityDescriptor::FromHandle(
hdesk, base::win::SecurityObjectType::kDesktop,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION);
if (!sd) {
return false;
}
std::optional<base::win::AccessToken> token =
base::win::AccessToken::FromCurrentProcess(true,
TOKEN_ADJUST_DEFAULT);
if (!token) {
return false;
}
if (!token->SetIntegrityLevel(SECURITY_MANDATORY_LOW_RID)) {
return false;
}
std::optional<base::win::AccessCheckResult> result = sd->AccessCheck(
*token, desired_access, base::win::SecurityObjectType::kDesktop);
return result && result->access_status;
}
bool ShouldSetDelayedIntegrity() {
if (CanLowIntegrityAccessDesktop()) {
return false;
}
return true;
}
#endif
base::CommandLine cmd_line_;
};
void BindDiscardableMemoryReceiverOnIO(
mojo::PendingReceiver<
discardable_memory::mojom::DiscardableSharedMemoryManager> receiver,
discardable_memory::DiscardableSharedMemoryManager* manager) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
manager->Bind(std::move(receiver));
}
void BindDiscardableMemoryReceiverOnUI(
mojo::PendingReceiver<
discardable_memory::mojom::DiscardableSharedMemoryManager> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&BindDiscardableMemoryReceiverOnIO, std::move(receiver),
discardable_memory::DiscardableSharedMemoryManager::Get()));
}
void InitGpuPersistentCacheFileFactoryOnce() {
#if BUILDFLAG(SKIA_USE_DAWN)
if (features::kSkiaGraphiteDawnUsePersistentCache.Get() &&
!viz::PersistentCacheSandboxedFileFactory::GetInstance()) {
base::FilePath cache_root_dir =
GetContentClient()->browser()->GetGPUPersistentCacheDirectory();
if (cache_root_dir.empty()) {
return;
}
viz::PersistentCacheSandboxedFileFactory::CreateInstance(cache_root_dir);
}
#endif
}
}
bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
static bool is_single_process =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
static bool in_process_GPU =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kInProcessGPU);
if (is_single_process || in_process_GPU || host->valid_) {
return true;
}
host->ForceShutdown();
return false;
}
GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind, bool force_create) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (kind == GPU_PROCESS_KIND_INFO_COLLECTION) {
auto* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableGpu) ||
command_line->HasSwitch(switches::kSingleProcess) ||
command_line->HasSwitch(switches::kInProcessGPU))
return nullptr;
}
if (g_gpu_process_hosts[kind] && ValidateHost(g_gpu_process_hosts[kind]))
return g_gpu_process_hosts[kind];
if (!force_create)
return nullptr;
if (BrowserMainRunner::ExitedMainMessageLoop()) {
DLOG(ERROR) << "BrowserMainRunner::ExitedMainMessageLoop()";
return nullptr;
}
if (kind != GPU_PROCESS_KIND_INFO_COLLECTION) {
InitGpuPersistentCacheFileFactoryOnce();
}
static int last_host_id = 0;
int host_id;
host_id = ++last_host_id;
GpuProcessHost* host = new GpuProcessHost(host_id, kind);
if (host->Init())
return host;
LOG(ERROR) << "GPU process failed to initialize.";
host->RecordProcessCrash();
delete host;
return nullptr;
}
void GpuProcessHost::GetHasGpuProcess(base::OnceCallback<void(bool)> callback) {
if (!GetUIThreadTaskRunner({})->BelongsToCurrentThread()) {
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&GpuProcessHost::GetHasGpuProcess, std::move(callback)));
return;
}
bool has_gpu = false;
for (size_t i = 0; i < std::size(g_gpu_process_hosts); ++i) {
GpuProcessHost* host = g_gpu_process_hosts[i];
if (host && ValidateHost(host)) {
has_gpu = true;
break;
}
}
std::move(callback).Run(has_gpu);
}
void GpuProcessHost::CallOnUI(
const base::Location& location,
GpuProcessKind kind,
bool force_create,
base::OnceCallback<void(GpuProcessHost*)> callback) {
#if !BUILDFLAG(IS_WIN)
DCHECK_NE(kind, GPU_PROCESS_KIND_INFO_COLLECTION);
#endif
GetUIThreadTaskRunner({})->PostTask(
location, base::BindOnce(&RunCallbackOnUI, kind, force_create,
std::move(callback)));
}
void GpuProcessHost::BindInterface(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
if (interface_name ==
discardable_memory::mojom::DiscardableSharedMemoryManager::Name_) {
BindDiscardableMemoryReceiver(
mojo::PendingReceiver<
discardable_memory::mojom::DiscardableSharedMemoryManager>(
std::move(interface_pipe)));
return;
}
process_->child_process()->BindReceiver(
mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
}
#if BUILDFLAG(IS_OZONE)
void GpuProcessHost::TerminateGpuProcess(const std::string& message) {
termination_origin_ = GpuTerminationOrigin::kOzoneWaylandProxy;
process_->TerminateOnBadMessageReceived(message);
}
#endif
GpuProcessHost* GpuProcessHost::FromID(int host_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (int i = 0; i < GPU_PROCESS_KIND_COUNT; ++i) {
GpuProcessHost* host = g_gpu_process_hosts[i];
if (host && host->host_id_ == host_id && ValidateHost(host))
return host;
}
return nullptr;
}
int GpuProcessHost::GetGpuCrashCount() {
return static_cast<int>(base::subtle::NoBarrier_Load(&gpu_crash_count_));
}
void GpuProcessHost::IncrementCrashCount(gpu::GpuMode gpu_mode) {
int forgive_minutes = GetForgiveMinutes(gpu_mode);
DCHECK_GT(forgive_minutes, 0);
static base::TimeTicks last_crash_time;
base::TimeTicks current_time = base::TimeTicks::Now();
if (gpu_mode != last_crash_mode_) {
recent_crash_count_ = 0;
} else if (crashed_before_) {
int minutes_delta = (current_time - last_crash_time).InMinutes();
int crashes_to_forgive = minutes_delta / forgive_minutes;
recent_crash_count_ = std::max(0, recent_crash_count_ - crashes_to_forgive);
}
recent_crash_count_ =
std::min(recent_crash_count_ + 1,
static_cast<int>(GPU_PROCESS_LIFETIME_EVENT_MAX) - 1);
crashed_before_ = true;
last_crash_mode_ = gpu_mode;
last_crash_time = current_time;
}
GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind)
: host_id_(host_id),
valid_(true),
in_process_(false),
kind_(kind),
process_launched_(false) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess) ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kInProcessGPU)) {
in_process_ = true;
}
#if !BUILDFLAG(IS_ANDROID)
if (!in_process_ && kind != GPU_PROCESS_KIND_INFO_COLLECTION) {
memory_pressure_listener_registration_ =
std::make_unique<base::MemoryPressureListenerRegistration>(
FROM_HERE, base::MemoryPressureListenerTag::kGpuProcessHost, this);
}
#endif
DCHECK(!in_process_ || g_gpu_process_hosts[kind] == nullptr);
g_gpu_process_hosts[kind] = this;
process_ =
std::make_unique<BrowserChildProcessHostImpl>(PROCESS_TYPE_GPU, this);
}
GpuProcessHost::~GpuProcessHost() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (in_process_gpu_thread_)
DCHECK(process_);
if (!process_start_time_.is_null() &&
kind_ != GPU_PROCESS_KIND_INFO_COLLECTION) {
base::TimeDelta process_lifetime =
base::TimeTicks::Now() - process_start_time_;
constexpr int kLifetimeMax = 60 * 60 * 24 * 14;
base::UmaHistogramCustomCounts("GPU.ProcessLifetime2",
process_lifetime.InSeconds(), 1,
kLifetimeMax, 50);
}
SendOutstandingReplies();
#if BUILDFLAG(IS_MAC)
if (ca_transaction_gpu_coordinator_) {
ca_transaction_gpu_coordinator_->HostWillBeDestroyed();
ca_transaction_gpu_coordinator_ = nullptr;
}
#endif
#if BUILDFLAG(ARKWEB_PERFORMANCE_SCHEDULING)
if (in_process_gpu_thread_)
OHOS::NWeb::ResSchedClientAdapter::ReportKeyThread(
OHOS::NWeb::ResSchedStatusAdapter::THREAD_DESTROYED,
base::GetCurrentRealPid(), in_process_gpu_thread_->GetThreadRealId().raw(),
OHOS::NWeb::ResSchedRoleAdapter::IMPORTANT_DISPLAY);
#endif
if (g_gpu_process_hosts[kind_] == this)
g_gpu_process_hosts[kind_] = nullptr;
bool block_offscreen_contexts = true;
if (!in_process_ && process_launched_) {
ChildProcessTerminationInfo info =
process_->GetTerminationInfo(false);
std::string message;
if (kind_ == GPU_PROCESS_KIND_SANDBOXED) {
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus2",
ConvertToGpuTerminationStatus(info.status),
GpuTerminationStatus::MAX_ENUM);
int exit_code = std::clamp(info.exit_code, 0, 100);
#if !BUILDFLAG(IS_ANDROID)
if (info.status != base::TERMINATION_STATUS_NORMAL_TERMINATION &&
info.status != base::TERMINATION_STATUS_STILL_RUNNING &&
exit_code !=
static_cast<int>(content::RESULT_CODE_GPU_DEAD_ON_ARRIVAL)) {
metrics::StabilityMetricsHelper::RecordStabilityEvent(
metrics::StabilityEventType::kGpuCrash);
}
#endif
if (info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION ||
info.status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
info.status == base::TERMINATION_STATUS_PROCESS_CRASHED) {
base::UmaHistogramSparse("GPU.GPUProcessExitCode", exit_code);
}
message = "The GPU process ";
} else {
message = "The info collection GPU process ";
}
bool unexpected_exit = false;
switch (info.status) {
case base::TERMINATION_STATUS_NORMAL_TERMINATION:
block_offscreen_contexts = false;
message += "exited normally. Everything is okay.";
break;
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
message +=
"exited with code " + CrashExitCodeToString(info.exit_code) + ".";
unexpected_exit = true;
break;
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationOrigin",
termination_origin_,
GpuTerminationOrigin::kMax);
message += "was killed by you! Why?";
break;
case base::TERMINATION_STATUS_PROCESS_CRASHED:
message +=
"crashed! Exit code: " + CrashExitCodeToString(info.exit_code) +
".";
unexpected_exit = true;
break;
case base::TERMINATION_STATUS_STILL_RUNNING:
message += "hasn't exited yet.";
break;
#if BUILDFLAG(IS_CHROMEOS)
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
message += "was killed due to out of memory.";
unexpected_exit = true;
break;
#endif
#if BUILDFLAG(IS_ANDROID)
case base::TERMINATION_STATUS_OOM_PROTECTED:
message += "was protected from out of memory kill.";
unexpected_exit = true;
break;
#endif
case base::TERMINATION_STATUS_LAUNCH_FAILED:
message += "failed to start!";
unexpected_exit = true;
break;
case base::TERMINATION_STATUS_OOM:
message += "died due to out of memory.";
unexpected_exit = true;
break;
#if BUILDFLAG(IS_WIN)
case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
message += "failed integrity checks.";
unexpected_exit = true;
break;
#endif
case base::TERMINATION_STATUS_EVICTED_FOR_MEMORY:
message += "evicted for memory.";
unexpected_exit = true;
break;
case base::TERMINATION_STATUS_MAX_ENUM:
NOTREACHED();
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceBrowserCrashOnGpuCrash)) {
CHECK(!unexpected_exit)
<< "Force Chrome to crash due to unexpected GPU process crash";
}
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&OnGpuProcessHostDestroyedOnUI, host_id_, message));
}
if (block_offscreen_contexts && gpu_host_)
gpu_host_->BlockLiveOffscreenContexts();
}
bool GpuProcessHost::Init() {
init_start_time_ = base::TimeTicks::Now();
TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD);
process_->GetHost()->CreateChannel();
mode_ = GpuDataManagerImpl::GetInstance()->GetGpuMode();
if (in_process_) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(GetGpuMainThreadFactory());
gpu::GpuPreferences gpu_preferences = GetGpuPreferencesFromCommandLine();
GpuDataManagerImpl::GetInstance()->UpdateGpuPreferences(
&gpu_preferences, GPU_PROCESS_KIND_SANDBOXED);
in_process_gpu_thread_.reset(GetGpuMainThreadFactory()(
InProcessChildThreadParams(
base::SingleThreadTaskRunner::GetCurrentDefault(),
process_->GetInProcessMojoInvitation(), GetIOThreadTaskRunner()),
gpu_preferences));
base::Thread::Options options;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
options.message_pump_type = base::MessagePumpType::UI;
#endif
options.thread_type = base::ThreadType::kDisplayCritical;
in_process_gpu_thread_->StartWithOptions(std::move(options));
#if BUILDFLAG(ARKWEB_PERFORMANCE_SCHEDULING)
OHOS::NWeb::ResSchedClientAdapter::ReportKeyThread(
OHOS::NWeb::ResSchedStatusAdapter::THREAD_CREATED,
base::GetCurrentRealPid(), in_process_gpu_thread_->GetThreadRealId().raw(),
OHOS::NWeb::ResSchedRoleAdapter::IMPORTANT_DISPLAY);
#endif
} else if (!LaunchGpuProcess()) {
return false;
}
mojo::PendingRemote<viz::mojom::VizMain> viz_main_pending_remote;
process_->child_process()->BindServiceInterface(
viz_main_pending_remote.InitWithNewPipeAndPassReceiver());
viz::GpuHostImpl::InitParams params;
params.restart_id = host_id_;
params.disable_gpu_shader_disk_cache = !features::IsShaderDiskCacheEnabled(
base::CommandLine::ForCurrentProcess());
params.product = GetContentClient()->browser()->GetProduct();
params.deadline_to_synchronize_surfaces =
switches::GetDeadlineToSynchronizeSurfaces();
params.main_thread_task_runner = GetUIThreadTaskRunner({});
params.info_collection_gpu_process =
kind_ == GPU_PROCESS_KIND_INFO_COLLECTION;
params.gpu_service_running_in_process = in_process_;
gpu_host_ = std::make_unique<viz::GpuHostImpl>(
this, std::move(viz_main_pending_remote), std::move(params));
if (in_process_) {
OnProcessLaunched();
}
#if BUILDFLAG(IS_MAC)
ca_transaction_gpu_coordinator_ = CATransactionGPUCoordinator::Create(this);
#endif
#if BUILDFLAG(ARKWEB_OOP_GPU_PROCESS)
if (gpu_crash_count_ != 0) {
ArkwebRenderProcessHostImplUtils::Refresh();
}
#endif
return true;
}
void GpuProcessHost::OnProcessLaunched() {
process_start_time_ = base::TimeTicks::Now();
UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime",
process_start_time_ - init_start_time_);
DCHECK(gpu_host_);
if (in_process_) {
gpu_host_->SetProcessId(base::GetCurrentProcId());
} else {
process_id_ = process_->GetProcess().Pid();
DCHECK_NE(base::kNullProcessId, process_id_);
gpu_host_->SetProcessId(process_id_);
#if BUILDFLAG(IS_MAC)
if (base::FeatureList::IsEnabled(features::kAdjustGpuProcessPriority)) {
browser_child_process_backgrounded_bridge_ =
std::make_unique<BrowserChildProcessBackgroundedBridge>(
process_.get());
}
#endif
}
}
#if BUILDFLAG(ARKWEB_REPORT_SYS_EVENT)
const std::string process_type = "gpu";
#endif
void GpuProcessHost::OnProcessLaunchFailed(int error_code) {
LOG(ERROR) << "GPU process launch failed: error_code=" << error_code;
#if BUILDFLAG(ARKWEB_REPORT_SYS_EVENT)
std::string error_msg = "gpu process launch failed, error code:" + std::to_string(error_code);
crashpad::CrashpadDfx::ProcessCrashReport(process_type, "", "", error_msg);
#endif
RecordProcessCrash();
}
void GpuProcessHost::OnProcessCrashed(int exit_code) {
LOG(ERROR) << "GPU process exited unexpectedly: exit_code=" << exit_code;
#if BUILDFLAG(ARKWEB_REPORT_SYS_EVENT)
std::string error_msg = "gpu process crashed, error code:" + std::to_string(exit_code);
crashpad::CrashpadDfx::ProcessCrashReport(process_type, "", "", error_msg);
#endif
RecordProcessCrash();
gpu_host_->OnProcessCrashed();
SendOutstandingReplies();
GpuDataManagerImpl::GetInstance()->ProcessCrashed();
}
gpu::GPUInfo GpuProcessHost::GetGPUInfo() const {
return GpuDataManagerImpl::GetInstance()->GetGPUInfo();
}
gpu::GpuFeatureInfo GpuProcessHost::GetGpuFeatureInfo() const {
return GpuDataManagerImpl::GetInstance()->GetGpuFeatureInfo();
}
void GpuProcessHost::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) {
if (GetGpuCrashCount() > 0) {
LOG(WARNING) << "Reinitialized the GPU process after a crash. The reported "
"initialization time was "
<< gpu_info.initialization_time.InMilliseconds() << " ms";
}
if (kind_ != GPU_PROCESS_KIND_INFO_COLLECTION) {
auto* gpu_data_manager = GpuDataManagerImpl::GetInstance();
gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info,
gpu_feature_info_for_hardware_gpu);
gpu_data_manager->UpdateGpuInfo(gpu_info, gpu_info_for_hardware_gpu);
gpu_data_manager->UpdateGpuExtraInfo(gpu_extra_info);
}
#if BUILDFLAG(IS_ANDROID)
if (!GpuDataManagerImpl::GetInstance()->CanFallback())
recent_crash_count_ = 0;
#endif
}
void GpuProcessHost::DidFailInitialize() {
did_fail_initialize_ = true;
if (kind_ == GPU_PROCESS_KIND_SANDBOXED) {
base::UmaHistogramEnumeration(kFallbackEventCause,
GPUFallbackEventCauseType::kFailureToInit);
GpuDataManagerImpl::GetInstance()->FallBackToNextGpuMode();
}
}
void GpuProcessHost::DidCreateContextSuccessfully() {
#if BUILDFLAG(IS_ANDROID)
if (!GpuDataManagerImpl::GetInstance()->CanFallback())
recent_crash_count_ = 0;
#endif
}
void GpuProcessHost::MaybeShutdownGpuProcess() {
if (!in_process_ &&
GetContentClient()->browser()->CanShutdownGpuProcessNowOnIOThread()) {
delete this;
}
}
void GpuProcessHost::DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) {
GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info, std::nullopt);
}
#if BUILDFLAG(IS_WIN)
void GpuProcessHost::DidUpdateOverlayInfo(
const gpu::OverlayInfo& overlay_info) {
GpuDataManagerImpl::GetInstance()->UpdateOverlayInfo(overlay_info);
}
void GpuProcessHost::DidUpdateDXGIInfo(gfx::mojom::DXGIInfoPtr dxgi_info) {
GpuDataManagerImpl::GetInstance()->UpdateDXGIInfo(std::move(dxgi_info));
}
#endif
std::string GpuProcessHost::GetIsolationKey(
int32_t process_id,
const blink::WebGPUExecutionContextToken& token) {
if (token.Is<blink::DocumentToken>()) {
RenderFrameHostImpl* frame_host = RenderFrameHostImpl::FromDocumentToken(
process_id, token.GetAs<blink::DocumentToken>());
if (!frame_host) {
return "";
}
auto isolation_key =
frame_host->GetNetworkIsolationKey().ToCacheKeyString();
return isolation_key ? *isolation_key : "";
} else if (token.Is<blink::DedicatedWorkerToken>()) {
RenderProcessHost* render_process_host =
RenderProcessHost::FromID(process_id);
if (!render_process_host ||
!render_process_host->IsInitializedAndNotDead()) {
return "";
}
DedicatedWorkerHost* dedicated_worker_host =
static_cast<StoragePartitionImpl*>(
render_process_host->GetStoragePartition())
->GetDedicatedWorkerService()
->GetDedicatedWorkerHostFromToken(
token.GetAs<blink::DedicatedWorkerToken>());
if (!dedicated_worker_host) {
return "";
}
auto isolation_key =
dedicated_worker_host->GetNetworkIsolationKey().ToCacheKeyString();
return isolation_key ? *isolation_key : "";
} else if (token.Is<blink::SharedWorkerToken>()) {
RenderProcessHost* render_process_host =
RenderProcessHost::FromID(process_id);
if (!render_process_host ||
!render_process_host->IsInitializedAndNotDead()) {
return "";
}
auto* storage_partition = static_cast<StoragePartitionImpl*>(
render_process_host->GetStoragePartition());
auto* worker_service = static_cast<SharedWorkerServiceImpl*>(
storage_partition->GetSharedWorkerService());
SharedWorkerHost* shared_worker_host =
worker_service->GetSharedWorkerHostFromToken(
token.GetAs<blink::SharedWorkerToken>());
if (!shared_worker_host) {
return "";
}
auto isolation_key =
shared_worker_host->GetNetworkIsolationKey().ToCacheKeyString();
return isolation_key ? *isolation_key : "";
} else if (token.Is<blink::ServiceWorkerToken>()) {
RenderProcessHost* render_process_host =
RenderProcessHost::FromID(process_id);
if (!render_process_host ||
!render_process_host->IsInitializedAndNotDead()) {
return "";
}
ServiceWorkerContextWrapper* service_worker_context =
static_cast<StoragePartitionImpl*>(
render_process_host->GetStoragePartition())
->GetServiceWorkerContext();
if (!service_worker_context) {
return "";
}
for (const auto& kv :
service_worker_context->GetRunningServiceWorkerInfos()) {
int64_t version_id = kv.first;
ServiceWorkerVersion* version =
service_worker_context->GetLiveVersion(version_id);
if (!version) {
continue;
}
ServiceWorkerHost* service_worker_host = version->worker_host();
if (!service_worker_host) {
continue;
}
if (service_worker_host->token() !=
token.GetAs<blink::ServiceWorkerToken>()) {
continue;
}
auto isolation_key =
service_worker_host->GetNetworkIsolationKey().ToCacheKeyString();
return isolation_key ? *isolation_key : "";
}
return "";
}
NOTREACHED();
}
void GpuProcessHost::BlockDomainsFrom3DAPIs(const std::set<GURL>& urls,
gpu::DomainGuilt guilt) {
GpuDataManagerImpl::GetInstance()->BlockDomainsFrom3DAPIs(urls, guilt);
}
bool GpuProcessHost::GpuAccessAllowed() const {
return GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(nullptr);
}
void GpuProcessHost::DisableGpuCompositing() {
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
DLOG(ERROR) << "Can't disable GPU compositing";
#elif BUILDFLAG(IS_ARKWEB)
LOG(ERROR) << "Can't disable GPU compositing";
#else
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce([]() {
if (auto* factory = ImageTransportFactory::GetInstance())
factory->DisableGpuCompositing();
}));
#endif
}
gpu::GpuDiskCacheFactory* GpuProcessHost::GetGpuDiskCacheFactory() {
return GetGpuDiskCacheFactorySingleton();
}
void GpuProcessHost::RecordLogMessage(int32_t severity,
const std::string& header,
const std::string& message) {
GpuDataManagerImpl::GetInstance()->AddLogMessage(severity, header, message);
}
void GpuProcessHost::BindDiscardableMemoryReceiver(
mojo::PendingReceiver<
discardable_memory::mojom::DiscardableSharedMemoryManager> receiver) {
BindDiscardableMemoryReceiverOnUI(std::move(receiver));
}
GpuProcessKind GpuProcessHost::kind() {
return kind_;
}
void GpuProcessHost::ForceShutdown() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (g_gpu_process_hosts[kind_] == this)
g_gpu_process_hosts[kind_] = nullptr;
process_->ForceShutdown();
}
void GpuProcessHost::DumpProcessStack() {
#if BUILDFLAG(IS_ANDROID)
if (in_process_)
return;
process_->DumpProcessStack();
#endif
}
void GpuProcessHost::RunServiceImpl(mojo::GenericPendingReceiver receiver) {
process_->child_process()->BindServiceInterface(std::move(receiver));
}
bool GpuProcessHost::LaunchGpuProcess() {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
base::CommandLine::StringType gpu_launcher =
browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<base::CommandLine> cmd_line =
std::make_unique<base::CommandLine>(base::CommandLine::NO_PROGRAM);
#else
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF
: ChildProcessHost::CHILD_NORMAL;
#elif BUILDFLAG(IS_MAC)
int child_flags =
features::IsSwiftShaderAllowed(base::CommandLine::ForCurrentProcess())
? ChildProcessHost::CHILD_GPU
: ChildProcessHost::CHILD_NORMAL;
#else
int child_flags = ChildProcessHost::CHILD_NORMAL;
#endif
base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags);
if (exe_path.empty())
return false;
std::unique_ptr<base::CommandLine> cmd_line =
std::make_unique<base::CommandLine>(exe_path);
#endif
cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
#if BUILDFLAG(IS_WIN)
if (kind_ == GPU_PROCESS_KIND_INFO_COLLECTION) {
cmd_line->AppendArgNative(app_launch_prefetch::GetPrefetchSwitch(
app_launch_prefetch::SubprocessType::kGPUInfo));
} else {
cmd_line->AppendArgNative(app_launch_prefetch::GetPrefetchSwitch(
app_launch_prefetch::SubprocessType::kGPU));
}
#endif
if (kind_ == GPU_PROCESS_KIND_INFO_COLLECTION) {
cmd_line->AppendSwitch(sandbox::policy::switches::kDisableGpuSandbox);
cmd_line->AppendSwitchASCII(switches::kUseGL,
gl::kGLImplementationDisabledName);
const gpu::GPUInfo::GPUDevice device_info = GetGPUInfo().active_gpu();
cmd_line->AppendSwitchASCII(
switches::kGpuVendorId,
base::StringPrintf("%u", device_info.vendor_id));
cmd_line->AppendSwitchASCII(
switches::kGpuDeviceId,
base::StringPrintf("%u", device_info.device_id));
#if BUILDFLAG(IS_WIN)
cmd_line->AppendSwitchASCII(
switches::kGpuSubSystemId,
base::StringPrintf("%u", device_info.sub_sys_id));
cmd_line->AppendSwitchASCII(switches::kGpuRevision,
base::StringPrintf("%u", device_info.revision));
#endif
if (device_info.driver_version.length()) {
cmd_line->AppendSwitchASCII(switches::kGpuDriverVersion,
device_info.driver_version);
}
}
cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames);
cmd_line->CopySwitchesFrom(browser_command_line,
switches::kGLSwitchesCopiedFromGpuProcessHost);
cmd_line->CopySwitchesFrom(
browser_command_line,
switches::GetWebNNSwitchesCopiedFromGpuProcessHost());
if (browser_command_line.HasSwitch(switches::kDisableFrameRateLimit))
cmd_line->AppendSwitch(switches::kDisableGpuVsync);
if (browser_command_line.HasSwitch(switches::kForceHighPerformanceGPU)) {
cmd_line->AppendSwitch(gpu::GpuDriverBugWorkaroundTypeToString(
gpu::FORCE_HIGH_PERFORMANCE_GPU));
}
std::vector<const char*> gpu_workarounds;
gpu::GpuDriverBugList::AppendAllWorkarounds(&gpu_workarounds);
cmd_line->CopySwitchesFrom(browser_command_line, gpu_workarounds);
GetContentClient()->browser()->AppendExtraCommandLineSwitches(
cmd_line.get(), process_->GetData().id);
GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line.get(),
kind_);
if (!gpu_launcher.empty())
cmd_line->PrependWrapper(gpu_launcher);
std::unique_ptr<GpuSandboxedProcessLauncherDelegate> delegate =
std::make_unique<GpuSandboxedProcessLauncherDelegate>(*cmd_line);
process_->LaunchWithoutExtraCommandLineSwitches(
std::move(delegate), std::move(cmd_line),
std::make_unique<ChildProcessLauncherFileData>());
process_launched_ = true;
if (kind_ == GPU_PROCESS_KIND_SANDBOXED) {
auto* const histogram = GetProcessLifetimeUmaName(mode_);
if (histogram) {
base::UmaHistogramEnumeration(histogram, LAUNCHED,
GPU_PROCESS_LIFETIME_EVENT_MAX);
}
}
return true;
}
void GpuProcessHost::SendOutstandingReplies() {
valid_ = false;
if (gpu_host_)
gpu_host_->SendOutstandingReplies();
}
int GpuProcessHost::GetFallbackCrashLimit() const {
#if BUILDFLAG(IS_ANDROID)
if (GpuDataManagerImpl::GetInstance()->CanFallback() &&
base::android::ApplicationStatusListener::HasVisibleActivities()) {
return 3;
} else {
return 6;
}
#elif BUILDFLAG(IS_CHROMEOS)
return 6;
#elif BUILDFLAG(ARKWEB_OOP_GPU_PROCESS)
return 6;
#else
return 3;
#endif
}
void GpuProcessHost::RecordProcessCrash() {
if (!process_launched_ || kind_ != GPU_PROCESS_KIND_SANDBOXED)
return;
base::subtle::NoBarrier_AtomicIncrement(&gpu_crash_count_, 1);
LOG(WARNING) << "The GPU process has crashed " << GetGpuCrashCount()
<< " time(s)";
IncrementCrashCount(mode_);
auto* const histogram = GetProcessLifetimeUmaName(mode_);
if (histogram) {
base::UmaHistogramExactLinear(
histogram, DIED_FIRST_TIME + recent_crash_count_ - 1,
static_cast<int>(GPU_PROCESS_LIFETIME_EVENT_MAX));
}
if (did_fail_initialize_)
return;
bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuProcessCrashLimit);
if (recent_crash_count_ >= GetFallbackCrashLimit() && !disable_crash_limit) {
base::UmaHistogramEnumeration(kFallbackEventCause,
GPUFallbackEventCauseType::kCrashLimit);
GpuDataManagerImpl::GetInstance()->FallBackToNextGpuModeDueToCrash();
}
}
viz::mojom::GpuService* GpuProcessHost::gpu_service() {
DCHECK(gpu_host_);
return gpu_host_->gpu_service();
}
#if BUILDFLAG(IS_WIN)
viz::mojom::InfoCollectionGpuService*
GpuProcessHost::info_collection_gpu_service() {
DCHECK(gpu_host_);
return gpu_host_->info_collection_gpu_service();
}
#endif
int GpuProcessHost::GetIDForTesting() const {
return process_->GetData().id;
}
#if !BUILDFLAG(IS_ANDROID)
void GpuProcessHost::OnMemoryPressure(base::MemoryPressureLevel level) {
gpu_host_->gpu_service()->OnMemoryPressure(level);
}
#endif
}