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