gpu_process_host.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/gpu/gpu_process_host.h" 6 7#include "base/base64.h" 8#include "base/base_switches.h" 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/callback_helpers.h" 12#include "base/command_line.h" 13#include "base/debug/trace_event.h" 14#include "base/logging.h" 15#include "base/memory/ref_counted.h" 16#include "base/metrics/histogram.h" 17#include "base/sha1.h" 18#include "base/threading/thread.h" 19#include "content/browser/browser_child_process_host_impl.h" 20#include "content/browser/gpu/compositor_util.h" 21#include "content/browser/gpu/gpu_data_manager_impl.h" 22#include "content/browser/gpu/gpu_process_host_ui_shim.h" 23#include "content/browser/gpu/shader_disk_cache.h" 24#include "content/browser/renderer_host/render_widget_host_impl.h" 25#include "content/browser/renderer_host/render_widget_resize_helper.h" 26#include "content/common/child_process_host_impl.h" 27#include "content/common/gpu/gpu_messages.h" 28#include "content/common/view_messages.h" 29#include "content/public/browser/browser_thread.h" 30#include "content/public/browser/content_browser_client.h" 31#include "content/public/browser/render_process_host.h" 32#include "content/public/browser/render_widget_host_view.h" 33#include "content/public/browser/render_widget_host_view_frame_subscriber.h" 34#include "content/public/common/content_client.h" 35#include "content/public/common/content_switches.h" 36#include "content/public/common/result_codes.h" 37#include "content/public/common/sandboxed_process_launcher_delegate.h" 38#include "gpu/command_buffer/service/gpu_switches.h" 39#include "ipc/ipc_channel_handle.h" 40#include "ipc/ipc_switches.h" 41#include "ipc/message_filter.h" 42#include "media/base/media_switches.h" 43#include "ui/base/ui_base_switches.h" 44#include "ui/events/latency_info.h" 45#include "ui/gl/gl_switches.h" 46 47#if defined(OS_WIN) 48#include "base/win/windows_version.h" 49#include "content/common/sandbox_win.h" 50#include "sandbox/win/src/sandbox_policy.h" 51#include "ui/gfx/switches.h" 52#endif 53 54#if defined(USE_OZONE) 55#include "ui/ozone/public/ozone_switches.h" 56#endif 57 58#if defined(USE_X11) && !defined(OS_CHROMEOS) 59#include "ui/gfx/x/x11_switches.h" 60#endif 61 62namespace content { 63 64bool GpuProcessHost::gpu_enabled_ = true; 65bool GpuProcessHost::hardware_gpu_enabled_ = true; 66int GpuProcessHost::gpu_crash_count_ = 0; 67int GpuProcessHost::gpu_recent_crash_count_ = 0; 68bool GpuProcessHost::crashed_before_ = false; 69int GpuProcessHost::swiftshader_crash_count_ = 0; 70 71namespace { 72 73// Command-line switches to propagate to the GPU process. 74static const char* const kSwitchNames[] = { 75 switches::kDisableAcceleratedVideoDecode, 76 switches::kDisableBreakpad, 77 switches::kDisableGpuSandbox, 78 switches::kDisableGpuWatchdog, 79 switches::kDisableLogging, 80 switches::kDisableSeccompFilterSandbox, 81#if defined(ENABLE_WEBRTC) 82 switches::kDisableWebRtcHWEncoding, 83#endif 84 switches::kEnableLogging, 85 switches::kEnableShareGroupAsyncTextureUpload, 86#if defined(OS_CHROMEOS) 87 switches::kDisableVaapiAcceleratedVideoEncode, 88#endif 89 switches::kGpuStartupDialog, 90 switches::kGpuSandboxAllowSysVShm, 91 switches::kGpuSandboxFailuresFatal, 92 switches::kGpuSandboxStartEarly, 93 switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode, 94 switches::kLoggingLevel, 95 switches::kLowEndDeviceMode, 96 switches::kNoSandbox, 97 switches::kTestGLLib, 98 switches::kTraceStartup, 99 switches::kTraceToConsole, 100 switches::kV, 101 switches::kVModule, 102#if defined(OS_MACOSX) 103 switches::kEnableRemoteCoreAnimation, 104 switches::kEnableSandboxLogging, 105#endif 106#if defined(USE_AURA) 107 switches::kUIPrioritizeInGpuProcess, 108#endif 109#if defined(USE_OZONE) 110 switches::kOzonePlatform, 111 switches::kOzoneUseSurfaceless, 112#endif 113#if defined(USE_X11) && !defined(OS_CHROMEOS) 114 switches::kX11Display, 115#endif 116}; 117 118enum GPUProcessLifetimeEvent { 119 LAUNCHED, 120 DIED_FIRST_TIME, 121 DIED_SECOND_TIME, 122 DIED_THIRD_TIME, 123 DIED_FOURTH_TIME, 124 GPU_PROCESS_LIFETIME_EVENT_MAX = 100 125}; 126 127// Indexed by GpuProcessKind. There is one of each kind maximum. This array may 128// only be accessed from the IO thread. 129GpuProcessHost* g_gpu_process_hosts[GpuProcessHost::GPU_PROCESS_KIND_COUNT]; 130 131 132void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind, 133 CauseForGpuLaunch cause, 134 IPC::Message* message) { 135 GpuProcessHost* host = GpuProcessHost::Get(kind, cause); 136 if (host) { 137 host->Send(message); 138 } else { 139 delete message; 140 } 141} 142 143// NOTE: changes to this class need to be reviewed by the security team. 144class GpuSandboxedProcessLauncherDelegate 145 : public SandboxedProcessLauncherDelegate { 146 public: 147 GpuSandboxedProcessLauncherDelegate(base::CommandLine* cmd_line, 148 ChildProcessHost* host) 149#if defined(OS_WIN) 150 : cmd_line_(cmd_line) {} 151#elif defined(OS_POSIX) 152 : ipc_fd_(host->TakeClientFileDescriptor()) {} 153#endif 154 155 virtual ~GpuSandboxedProcessLauncherDelegate() {} 156 157#if defined(OS_WIN) 158 virtual bool ShouldSandbox() OVERRIDE { 159 bool sandbox = !cmd_line_->HasSwitch(switches::kDisableGpuSandbox); 160 if(! sandbox) { 161 DVLOG(1) << "GPU sandbox is disabled"; 162 } 163 return sandbox; 164 } 165 166 virtual void PreSandbox(bool* disable_default_policy, 167 base::FilePath* exposed_dir) OVERRIDE { 168 *disable_default_policy = true; 169 } 170 171 // For the GPU process we gotten as far as USER_LIMITED. The next level 172 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL 173 // backend. Note that the GPU process is connected to the interactive 174 // desktop. 175 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy, 176 bool* success) { 177 if (base::win::GetVersion() > base::win::VERSION_XP) { 178 if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) == 179 gfx::kGLImplementationDesktopName) { 180 // Open GL path. 181 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 182 sandbox::USER_LIMITED); 183 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); 184 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 185 } else { 186 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, 187 sandbox::USER_LIMITED); 188 189 // UI restrictions break when we access Windows from outside our job. 190 // However, we don't want a proxy window in this process because it can 191 // introduce deadlocks where the renderer blocks on the gpu, which in 192 // turn blocks on the browser UI thread. So, instead we forgo a window 193 // message pump entirely and just add job restrictions to prevent child 194 // processes. 195 SetJobLevel(*cmd_line_, 196 sandbox::JOB_LIMITED_USER, 197 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | 198 JOB_OBJECT_UILIMIT_DESKTOP | 199 JOB_OBJECT_UILIMIT_EXITWINDOWS | 200 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS, 201 policy); 202 203 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); 204 } 205 } else { 206 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); 207 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, 208 sandbox::USER_LIMITED); 209 } 210 211 // Allow the server side of GPU sockets, which are pipes that have 212 // the "chrome.gpu" namespace and an arbitrary suffix. 213 sandbox::ResultCode result = policy->AddRule( 214 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 215 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 216 L"\\\\.\\pipe\\chrome.gpu.*"); 217 if (result != sandbox::SBOX_ALL_OK) { 218 *success = false; 219 return; 220 } 221 222 // Block this DLL even if it is not loaded by the browser process. 223 policy->AddDllToUnload(L"cmsetac.dll"); 224 225#ifdef USE_AURA 226 // GPU also needs to add sections to the browser for aura 227 // TODO(jschuh): refactor the GPU channel to remove this. crbug.com/128786 228 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES, 229 sandbox::TargetPolicy::HANDLES_DUP_BROKER, 230 L"Section"); 231 if (result != sandbox::SBOX_ALL_OK) { 232 *success = false; 233 return; 234 } 235#endif 236 237 if (cmd_line_->HasSwitch(switches::kEnableLogging)) { 238 base::string16 log_file_path = logging::GetLogFileFullPath(); 239 if (!log_file_path.empty()) { 240 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 241 sandbox::TargetPolicy::FILES_ALLOW_ANY, 242 log_file_path.c_str()); 243 if (result != sandbox::SBOX_ALL_OK) { 244 *success = false; 245 return; 246 } 247 } 248 } 249 } 250#elif defined(OS_POSIX) 251 252 virtual int GetIpcFd() OVERRIDE { 253 return ipc_fd_; 254 } 255#endif // OS_WIN 256 257 private: 258#if defined(OS_WIN) 259 base::CommandLine* cmd_line_; 260#elif defined(OS_POSIX) 261 int ipc_fd_; 262#endif // OS_WIN 263}; 264 265} // anonymous namespace 266 267// static 268bool GpuProcessHost::ValidateHost(GpuProcessHost* host) { 269 // The Gpu process is invalid if it's not using SwiftShader, the card is 270 // blacklisted, and we can kill it and start over. 271 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 272 switches::kSingleProcess) || 273 base::CommandLine::ForCurrentProcess()->HasSwitch( 274 switches::kInProcessGPU) || 275 (host->valid_ && 276 (host->swiftshader_rendering_ || 277 !GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()))) { 278 return true; 279 } 280 281 host->ForceShutdown(); 282 return false; 283} 284 285// static 286GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind, 287 CauseForGpuLaunch cause) { 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 289 290 // Don't grant further access to GPU if it is not allowed. 291 GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance(); 292 DCHECK(gpu_data_manager); 293 if (!gpu_data_manager->GpuAccessAllowed(NULL)) 294 return NULL; 295 296 if (g_gpu_process_hosts[kind] && ValidateHost(g_gpu_process_hosts[kind])) 297 return g_gpu_process_hosts[kind]; 298 299 if (cause == CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH) 300 return NULL; 301 302 static int last_host_id = 0; 303 int host_id; 304 host_id = ++last_host_id; 305 306 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLaunchCause", 307 cause, 308 CAUSE_FOR_GPU_LAUNCH_MAX_ENUM); 309 310 GpuProcessHost* host = new GpuProcessHost(host_id, kind); 311 if (host->Init()) 312 return host; 313 314 delete host; 315 return NULL; 316} 317 318// static 319void GpuProcessHost::GetProcessHandles( 320 const GpuDataManager::GetGpuProcessHandlesCallback& callback) { 321 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 322 BrowserThread::PostTask( 323 BrowserThread::IO, 324 FROM_HERE, 325 base::Bind(&GpuProcessHost::GetProcessHandles, callback)); 326 return; 327 } 328 std::list<base::ProcessHandle> handles; 329 for (size_t i = 0; i < arraysize(g_gpu_process_hosts); ++i) { 330 GpuProcessHost* host = g_gpu_process_hosts[i]; 331 if (host && ValidateHost(host)) 332 handles.push_back(host->process_->GetHandle()); 333 } 334 BrowserThread::PostTask( 335 BrowserThread::UI, 336 FROM_HERE, 337 base::Bind(callback, handles)); 338} 339 340// static 341void GpuProcessHost::SendOnIO(GpuProcessKind kind, 342 CauseForGpuLaunch cause, 343 IPC::Message* message) { 344 if (!BrowserThread::PostTask( 345 BrowserThread::IO, FROM_HERE, 346 base::Bind( 347 &SendGpuProcessMessage, kind, cause, message))) { 348 delete message; 349 } 350} 351 352GpuMainThreadFactoryFunction g_gpu_main_thread_factory = NULL; 353 354void GpuProcessHost::RegisterGpuMainThreadFactory( 355 GpuMainThreadFactoryFunction create) { 356 g_gpu_main_thread_factory = create; 357} 358 359// static 360GpuProcessHost* GpuProcessHost::FromID(int host_id) { 361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 362 363 for (int i = 0; i < GPU_PROCESS_KIND_COUNT; ++i) { 364 GpuProcessHost* host = g_gpu_process_hosts[i]; 365 if (host && host->host_id_ == host_id && ValidateHost(host)) 366 return host; 367 } 368 369 return NULL; 370} 371 372GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind) 373 : host_id_(host_id), 374 valid_(true), 375 in_process_(false), 376 swiftshader_rendering_(false), 377 kind_(kind), 378 process_launched_(false), 379 initialized_(false), 380 gpu_crash_recorded_(false), 381 uma_memory_stats_received_(false) { 382 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 383 switches::kSingleProcess) || 384 base::CommandLine::ForCurrentProcess()->HasSwitch( 385 switches::kInProcessGPU)) { 386 in_process_ = true; 387 } 388 389 // If the 'single GPU process' policy ever changes, we still want to maintain 390 // it for 'gpu thread' mode and only create one instance of host and thread. 391 DCHECK(!in_process_ || g_gpu_process_hosts[kind] == NULL); 392 393 g_gpu_process_hosts[kind] = this; 394 395 // Post a task to create the corresponding GpuProcessHostUIShim. The 396 // GpuProcessHostUIShim will be destroyed if either the browser exits, 397 // in which case it calls GpuProcessHostUIShim::DestroyAll, or the 398 // GpuProcessHost is destroyed, which happens when the corresponding GPU 399 // process terminates or fails to launch. 400 BrowserThread::PostTask( 401 BrowserThread::UI, 402 FROM_HERE, 403 base::Bind(base::IgnoreResult(&GpuProcessHostUIShim::Create), host_id)); 404 405 process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_GPU, this)); 406} 407 408GpuProcessHost::~GpuProcessHost() { 409 DCHECK(CalledOnValidThread()); 410 411 SendOutstandingReplies(); 412 413 RecordProcessCrash(); 414 415 // In case we never started, clean up. 416 while (!queued_messages_.empty()) { 417 delete queued_messages_.front(); 418 queued_messages_.pop(); 419 } 420 421 // This is only called on the IO thread so no race against the constructor 422 // for another GpuProcessHost. 423 if (g_gpu_process_hosts[kind_] == this) 424 g_gpu_process_hosts[kind_] = NULL; 425 426 // If there are any remaining offscreen contexts at the point the 427 // GPU process exits, assume something went wrong, and block their 428 // URLs from accessing client 3D APIs without prompting. 429 BlockLiveOffscreenContexts(); 430 431 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitSurfaceCount", 432 GpuSurfaceTracker::Get()->GetSurfaceCount()); 433 UMA_HISTOGRAM_BOOLEAN("GPU.AtExitReceivedMemoryStats", 434 uma_memory_stats_received_); 435 436 if (uma_memory_stats_received_) { 437 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitManagedMemoryClientCount", 438 uma_memory_stats_.client_count); 439 UMA_HISTOGRAM_COUNTS_100("GPU.AtExitContextGroupCount", 440 uma_memory_stats_.context_group_count); 441 UMA_HISTOGRAM_CUSTOM_COUNTS( 442 "GPU.AtExitMBytesAllocated", 443 uma_memory_stats_.bytes_allocated_current / 1024 / 1024, 1, 2000, 50); 444 UMA_HISTOGRAM_CUSTOM_COUNTS( 445 "GPU.AtExitMBytesAllocatedMax", 446 uma_memory_stats_.bytes_allocated_max / 1024 / 1024, 1, 2000, 50); 447 UMA_HISTOGRAM_CUSTOM_COUNTS( 448 "GPU.AtExitMBytesLimit", 449 uma_memory_stats_.bytes_limit / 1024 / 1024, 1, 2000, 50); 450 } 451 452 std::string message; 453 if (!in_process_) { 454 int exit_code; 455 base::TerminationStatus status = process_->GetTerminationStatus( 456 false /* known_dead */, &exit_code); 457 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessTerminationStatus", 458 status, 459 base::TERMINATION_STATUS_MAX_ENUM); 460 461 if (status == base::TERMINATION_STATUS_NORMAL_TERMINATION || 462 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { 463 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessExitCode", 464 exit_code, 465 RESULT_CODE_LAST_CODE); 466 } 467 468 switch (status) { 469 case base::TERMINATION_STATUS_NORMAL_TERMINATION: 470 message = "The GPU process exited normally. Everything is okay."; 471 break; 472 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: 473 message = base::StringPrintf( 474 "The GPU process exited with code %d.", 475 exit_code); 476 break; 477 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: 478 message = "You killed the GPU process! Why?"; 479 break; 480 case base::TERMINATION_STATUS_PROCESS_CRASHED: 481 message = "The GPU process crashed!"; 482 break; 483 default: 484 break; 485 } 486 } 487 488 BrowserThread::PostTask(BrowserThread::UI, 489 FROM_HERE, 490 base::Bind(&GpuProcessHostUIShim::Destroy, 491 host_id_, 492 message)); 493} 494 495bool GpuProcessHost::Init() { 496 init_start_time_ = base::TimeTicks::Now(); 497 498 TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD); 499 500 std::string channel_id = process_->GetHost()->CreateChannel(); 501 if (channel_id.empty()) 502 return false; 503 504 if (in_process_) { 505 DCHECK(g_gpu_main_thread_factory); 506 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 507 command_line->AppendSwitch(switches::kDisableGpuWatchdog); 508 509 GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance(); 510 DCHECK(gpu_data_manager); 511 gpu_data_manager->AppendGpuCommandLine(command_line); 512 513 in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id)); 514 in_process_gpu_thread_->Start(); 515 516 OnProcessLaunched(); // Fake a callback that the process is ready. 517 } else if (!LaunchGpuProcess(channel_id)) { 518 return false; 519 } 520 521 if (!Send(new GpuMsg_Initialize())) 522 return false; 523 524 return true; 525} 526 527void GpuProcessHost::RouteOnUIThread(const IPC::Message& message) { 528 BrowserThread::PostTask( 529 BrowserThread::UI, 530 FROM_HERE, 531 base::Bind(&RouteToGpuProcessHostUIShimTask, host_id_, message)); 532} 533 534bool GpuProcessHost::Send(IPC::Message* msg) { 535 DCHECK(CalledOnValidThread()); 536 if (process_->GetHost()->IsChannelOpening()) { 537 queued_messages_.push(msg); 538 return true; 539 } 540 541 bool result = process_->Send(msg); 542 if (!result) { 543 // Channel is hosed, but we may not get destroyed for a while. Send 544 // outstanding channel creation failures now so that the caller can restart 545 // with a new process/channel without waiting. 546 SendOutstandingReplies(); 547 } 548 return result; 549} 550 551void GpuProcessHost::AddFilter(IPC::MessageFilter* filter) { 552 DCHECK(CalledOnValidThread()); 553 process_->GetHost()->AddFilter(filter); 554} 555 556bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) { 557 DCHECK(CalledOnValidThread()); 558 IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message) 559 IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized) 560 IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished) 561 IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated) 562 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer) 563 IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryBufferCreated, 564 OnGpuMemoryBufferCreated) 565 IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext, 566 OnDidCreateOffscreenContext) 567 IPC_MESSAGE_HANDLER(GpuHostMsg_DidLoseContext, OnDidLoseContext) 568 IPC_MESSAGE_HANDLER(GpuHostMsg_DidDestroyOffscreenContext, 569 OnDidDestroyOffscreenContext) 570 IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryUmaStats, 571 OnGpuMemoryUmaStatsReceived) 572#if defined(OS_MACOSX) 573 IPC_MESSAGE_HANDLER_GENERIC(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, 574 OnAcceleratedSurfaceBuffersSwapped(message)) 575#endif 576 IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel, 577 OnDestroyChannel) 578 IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader, 579 OnCacheShader) 580 581 IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message)) 582 IPC_END_MESSAGE_MAP() 583 584 return true; 585} 586 587void GpuProcessHost::OnChannelConnected(int32 peer_pid) { 588 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelConnected"); 589 590 while (!queued_messages_.empty()) { 591 Send(queued_messages_.front()); 592 queued_messages_.pop(); 593 } 594} 595 596void GpuProcessHost::EstablishGpuChannel( 597 int client_id, 598 bool share_context, 599 bool allow_future_sync_points, 600 const EstablishChannelCallback& callback) { 601 DCHECK(CalledOnValidThread()); 602 TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel"); 603 604 // If GPU features are already blacklisted, no need to establish the channel. 605 if (!GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) { 606 DVLOG(1) << "GPU blacklisted, refusing to open a GPU channel."; 607 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 608 return; 609 } 610 611 if (Send(new GpuMsg_EstablishChannel( 612 client_id, share_context, allow_future_sync_points))) { 613 channel_requests_.push(callback); 614 } else { 615 DVLOG(1) << "Failed to send GpuMsg_EstablishChannel."; 616 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 617 } 618 619 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( 620 switches::kDisableGpuShaderDiskCache)) { 621 CreateChannelCache(client_id); 622 } 623} 624 625void GpuProcessHost::CreateViewCommandBuffer( 626 const gfx::GLSurfaceHandle& compositing_surface, 627 int surface_id, 628 int client_id, 629 const GPUCreateCommandBufferConfig& init_params, 630 int route_id, 631 const CreateCommandBufferCallback& callback) { 632 TRACE_EVENT0("gpu", "GpuProcessHost::CreateViewCommandBuffer"); 633 634 DCHECK(CalledOnValidThread()); 635 636 if (!compositing_surface.is_null() && 637 Send(new GpuMsg_CreateViewCommandBuffer( 638 compositing_surface, surface_id, client_id, init_params, route_id))) { 639 create_command_buffer_requests_.push(callback); 640 surface_refs_.insert(std::make_pair(surface_id, 641 GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(surface_id))); 642 } else { 643 // Could distinguish here between compositing_surface being NULL 644 // and Send failing, if desired. 645 callback.Run(CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST); 646 } 647} 648 649void GpuProcessHost::CreateGpuMemoryBuffer( 650 const gfx::GpuMemoryBufferHandle& handle, 651 const gfx::Size& size, 652 unsigned internalformat, 653 unsigned usage, 654 const CreateGpuMemoryBufferCallback& callback) { 655 TRACE_EVENT0("gpu", "GpuProcessHost::CreateGpuMemoryBuffer"); 656 657 DCHECK(CalledOnValidThread()); 658 659 if (Send(new GpuMsg_CreateGpuMemoryBuffer( 660 handle, size, internalformat, usage))) { 661 create_gpu_memory_buffer_requests_.push(callback); 662 } else { 663 callback.Run(gfx::GpuMemoryBufferHandle()); 664 } 665} 666 667void GpuProcessHost::DestroyGpuMemoryBuffer( 668 const gfx::GpuMemoryBufferHandle& handle, 669 int sync_point) { 670 TRACE_EVENT0("gpu", "GpuProcessHost::DestroyGpuMemoryBuffer"); 671 672 DCHECK(CalledOnValidThread()); 673 674 Send(new GpuMsg_DestroyGpuMemoryBuffer(handle, sync_point)); 675} 676 677void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) { 678 UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessInitialized", result); 679 initialized_ = result; 680 681 if (!initialized_) 682 GpuDataManagerImpl::GetInstance()->OnGpuProcessInitFailure(); 683 else if (!in_process_) 684 GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info); 685} 686 687void GpuProcessHost::OnChannelEstablished( 688 const IPC::ChannelHandle& channel_handle) { 689 TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished"); 690 691 if (channel_requests_.empty()) { 692 // This happens when GPU process is compromised. 693 RouteOnUIThread(GpuHostMsg_OnLogMessage( 694 logging::LOG_WARNING, 695 "WARNING", 696 "Received a ChannelEstablished message but no requests in queue.")); 697 return; 698 } 699 EstablishChannelCallback callback = channel_requests_.front(); 700 channel_requests_.pop(); 701 702 // Currently if any of the GPU features are blacklisted, we don't establish a 703 // GPU channel. 704 if (!channel_handle.name.empty() && 705 !GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) { 706 Send(new GpuMsg_CloseChannel(channel_handle)); 707 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 708 RouteOnUIThread(GpuHostMsg_OnLogMessage( 709 logging::LOG_WARNING, 710 "WARNING", 711 "Hardware acceleration is unavailable.")); 712 return; 713 } 714 715 callback.Run(channel_handle, 716 GpuDataManagerImpl::GetInstance()->GetGPUInfo()); 717} 718 719void GpuProcessHost::OnCommandBufferCreated(CreateCommandBufferResult result) { 720 TRACE_EVENT0("gpu", "GpuProcessHost::OnCommandBufferCreated"); 721 722 if (create_command_buffer_requests_.empty()) 723 return; 724 725 CreateCommandBufferCallback callback = 726 create_command_buffer_requests_.front(); 727 create_command_buffer_requests_.pop(); 728 callback.Run(result); 729} 730 731void GpuProcessHost::OnDestroyCommandBuffer(int32 surface_id) { 732 TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyCommandBuffer"); 733 SurfaceRefMap::iterator it = surface_refs_.find(surface_id); 734 if (it != surface_refs_.end()) { 735 surface_refs_.erase(it); 736 } 737} 738 739void GpuProcessHost::OnGpuMemoryBufferCreated( 740 const gfx::GpuMemoryBufferHandle& handle) { 741 TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryBufferCreated"); 742 743 if (create_gpu_memory_buffer_requests_.empty()) 744 return; 745 746 CreateGpuMemoryBufferCallback callback = 747 create_gpu_memory_buffer_requests_.front(); 748 create_gpu_memory_buffer_requests_.pop(); 749 callback.Run(handle); 750} 751 752void GpuProcessHost::OnDidCreateOffscreenContext(const GURL& url) { 753 urls_with_live_offscreen_contexts_.insert(url); 754} 755 756void GpuProcessHost::OnDidLoseContext(bool offscreen, 757 gpu::error::ContextLostReason reason, 758 const GURL& url) { 759 // TODO(kbr): would be nice to see the "offscreen" flag too. 760 TRACE_EVENT2("gpu", "GpuProcessHost::OnDidLoseContext", 761 "reason", reason, 762 "url", 763 url.possibly_invalid_spec()); 764 765 if (!offscreen || url.is_empty()) { 766 // Assume that the loss of the compositor's or accelerated canvas' 767 // context is a serious event and blame the loss on all live 768 // offscreen contexts. This more robustly handles situations where 769 // the GPU process may not actually detect the context loss in the 770 // offscreen context. 771 BlockLiveOffscreenContexts(); 772 return; 773 } 774 775 GpuDataManagerImpl::DomainGuilt guilt; 776 switch (reason) { 777 case gpu::error::kGuilty: 778 guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN; 779 break; 780 case gpu::error::kUnknown: 781 guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN; 782 break; 783 case gpu::error::kInnocent: 784 return; 785 default: 786 NOTREACHED(); 787 return; 788 } 789 790 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs(url, guilt); 791} 792 793void GpuProcessHost::OnDidDestroyOffscreenContext(const GURL& url) { 794 urls_with_live_offscreen_contexts_.erase(url); 795} 796 797void GpuProcessHost::OnGpuMemoryUmaStatsReceived( 798 const GPUMemoryUmaStats& stats) { 799 TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryUmaStatsReceived"); 800 uma_memory_stats_received_ = true; 801 uma_memory_stats_ = stats; 802} 803 804#if defined(OS_MACOSX) 805void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( 806 const IPC::Message& message) { 807 RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message); 808} 809#endif 810 811void GpuProcessHost::OnProcessLaunched() { 812 UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime", 813 base::TimeTicks::Now() - init_start_time_); 814} 815 816void GpuProcessHost::OnProcessCrashed(int exit_code) { 817 SendOutstandingReplies(); 818 RecordProcessCrash(); 819 GpuDataManagerImpl::GetInstance()->ProcessCrashed( 820 process_->GetTerminationStatus(true /* known_dead */, NULL)); 821} 822 823GpuProcessHost::GpuProcessKind GpuProcessHost::kind() { 824 return kind_; 825} 826 827void GpuProcessHost::ForceShutdown() { 828 // This is only called on the IO thread so no race against the constructor 829 // for another GpuProcessHost. 830 if (g_gpu_process_hosts[kind_] == this) 831 g_gpu_process_hosts[kind_] = NULL; 832 833 process_->ForceShutdown(); 834} 835 836void GpuProcessHost::BeginFrameSubscription( 837 int surface_id, 838 base::WeakPtr<RenderWidgetHostViewFrameSubscriber> subscriber) { 839 frame_subscribers_[surface_id] = subscriber; 840} 841 842void GpuProcessHost::EndFrameSubscription(int surface_id) { 843 frame_subscribers_.erase(surface_id); 844} 845 846bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { 847 if (!(gpu_enabled_ && 848 GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) && 849 !hardware_gpu_enabled_) { 850 SendOutstandingReplies(); 851 return false; 852 } 853 854 const base::CommandLine& browser_command_line = 855 *base::CommandLine::ForCurrentProcess(); 856 857 base::CommandLine::StringType gpu_launcher = 858 browser_command_line.GetSwitchValueNative(switches::kGpuLauncher); 859 860#if defined(OS_LINUX) 861 int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : 862 ChildProcessHost::CHILD_NORMAL; 863#else 864 int child_flags = ChildProcessHost::CHILD_NORMAL; 865#endif 866 867 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags); 868 if (exe_path.empty()) 869 return false; 870 871 base::CommandLine* cmd_line = new base::CommandLine(exe_path); 872 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); 873 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); 874 875 if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED) 876 cmd_line->AppendSwitch(switches::kDisableGpuSandbox); 877 878 // If you want a browser command-line switch passed to the GPU process 879 // you need to add it to |kSwitchNames| at the beginning of this file. 880 cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames, 881 arraysize(kSwitchNames)); 882 cmd_line->CopySwitchesFrom( 883 browser_command_line, switches::kGpuSwitches, switches::kNumGpuSwitches); 884 cmd_line->CopySwitchesFrom( 885 browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost, 886 switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches); 887 888 GetContentClient()->browser()->AppendExtraCommandLineSwitches( 889 cmd_line, process_->GetData().id); 890 891 GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line); 892 893 if (cmd_line->HasSwitch(switches::kUseGL)) { 894 swiftshader_rendering_ = 895 (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"); 896 } 897 898 UMA_HISTOGRAM_BOOLEAN("GPU.GPU.GPUProcessSoftwareRendering", 899 swiftshader_rendering_); 900 901 // If specified, prepend a launcher program to the command line. 902 if (!gpu_launcher.empty()) 903 cmd_line->PrependWrapper(gpu_launcher); 904 905 process_->Launch( 906 new GpuSandboxedProcessLauncherDelegate(cmd_line, 907 process_->GetHost()), 908 cmd_line); 909 process_launched_ = true; 910 911 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", 912 LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX); 913 return true; 914} 915 916void GpuProcessHost::SendOutstandingReplies() { 917 valid_ = false; 918 // First send empty channel handles for all EstablishChannel requests. 919 while (!channel_requests_.empty()) { 920 EstablishChannelCallback callback = channel_requests_.front(); 921 channel_requests_.pop(); 922 callback.Run(IPC::ChannelHandle(), gpu::GPUInfo()); 923 } 924 925 while (!create_command_buffer_requests_.empty()) { 926 CreateCommandBufferCallback callback = 927 create_command_buffer_requests_.front(); 928 create_command_buffer_requests_.pop(); 929 callback.Run(CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST); 930 } 931 932 while (!create_gpu_memory_buffer_requests_.empty()) { 933 CreateGpuMemoryBufferCallback callback = 934 create_gpu_memory_buffer_requests_.front(); 935 create_gpu_memory_buffer_requests_.pop(); 936 callback.Run(gfx::GpuMemoryBufferHandle()); 937 } 938} 939 940void GpuProcessHost::BlockLiveOffscreenContexts() { 941 for (std::multiset<GURL>::iterator iter = 942 urls_with_live_offscreen_contexts_.begin(); 943 iter != urls_with_live_offscreen_contexts_.end(); ++iter) { 944 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( 945 *iter, GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN); 946 } 947} 948 949void GpuProcessHost::RecordProcessCrash() { 950 // Skip if a GPU process crash was already counted. 951 if (gpu_crash_recorded_) 952 return; 953 954 // Maximum number of times the GPU process is allowed to crash in a session. 955 // Once this limit is reached, any request to launch the GPU process will 956 // fail. 957 const int kGpuMaxCrashCount = 3; 958 959 // Last time the GPU process crashed. 960 static base::Time last_gpu_crash_time; 961 962 bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch( 963 switches::kDisableGpuProcessCrashLimit); 964 965 // Ending only acts as a failure if the GPU process was actually started and 966 // was intended for actual rendering (and not just checking caps or other 967 // options). 968 if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) { 969 gpu_crash_recorded_ = true; 970 if (swiftshader_rendering_) { 971 UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents", 972 DIED_FIRST_TIME + swiftshader_crash_count_, 973 GPU_PROCESS_LIFETIME_EVENT_MAX); 974 975 if (++swiftshader_crash_count_ >= kGpuMaxCrashCount && 976 !disable_crash_limit) { 977 // SwiftShader is too unstable to use. Disable it for current session. 978 gpu_enabled_ = false; 979 } 980 } else { 981 ++gpu_crash_count_; 982 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", 983 std::min(DIED_FIRST_TIME + gpu_crash_count_, 984 GPU_PROCESS_LIFETIME_EVENT_MAX - 1), 985 GPU_PROCESS_LIFETIME_EVENT_MAX); 986 987 // Allow about 1 GPU crash per hour to be removed from the crash count, 988 // so very occasional crashes won't eventually add up and prevent the 989 // GPU process from launching. 990 ++gpu_recent_crash_count_; 991 base::Time current_time = base::Time::Now(); 992 if (crashed_before_) { 993 int hours_different = (current_time - last_gpu_crash_time).InHours(); 994 gpu_recent_crash_count_ = 995 std::max(0, gpu_recent_crash_count_ - hours_different); 996 } 997 998 crashed_before_ = true; 999 last_gpu_crash_time = current_time; 1000 1001 if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount && 1002 !disable_crash_limit) || 1003 !initialized_) { 1004#if !defined(OS_CHROMEOS) 1005 // The GPU process is too unstable to use. Disable it for current 1006 // session. 1007 hardware_gpu_enabled_ = false; 1008 GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration(); 1009#endif 1010 } 1011 } 1012 } 1013} 1014 1015std::string GpuProcessHost::GetShaderPrefixKey() { 1016 if (shader_prefix_key_.empty()) { 1017 gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); 1018 1019 std::string in_str = GetContentClient()->GetProduct() + "-" + 1020 info.gl_vendor + "-" + info.gl_renderer + "-" + 1021 info.driver_version + "-" + info.driver_vendor; 1022 1023 base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_); 1024 } 1025 1026 return shader_prefix_key_; 1027} 1028 1029void GpuProcessHost::LoadedShader(const std::string& key, 1030 const std::string& data) { 1031 std::string prefix = GetShaderPrefixKey(); 1032 if (!key.compare(0, prefix.length(), prefix)) 1033 Send(new GpuMsg_LoadedShader(data)); 1034} 1035 1036void GpuProcessHost::CreateChannelCache(int32 client_id) { 1037 TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache"); 1038 1039 scoped_refptr<ShaderDiskCache> cache = 1040 ShaderCacheFactory::GetInstance()->Get(client_id); 1041 if (!cache.get()) 1042 return; 1043 1044 cache->set_host_id(host_id_); 1045 1046 client_id_to_shader_cache_[client_id] = cache; 1047} 1048 1049void GpuProcessHost::OnDestroyChannel(int32 client_id) { 1050 TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyChannel"); 1051 client_id_to_shader_cache_.erase(client_id); 1052} 1053 1054void GpuProcessHost::OnCacheShader(int32 client_id, 1055 const std::string& key, 1056 const std::string& shader) { 1057 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); 1058 ClientIdToShaderCacheMap::iterator iter = 1059 client_id_to_shader_cache_.find(client_id); 1060 // If the cache doesn't exist then this is an off the record profile. 1061 if (iter == client_id_to_shader_cache_.end()) 1062 return; 1063 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); 1064} 1065 1066} // namespace content 1067