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