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