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, &param))
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