15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <dwmapi.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/lazy_instance.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/metrics/histogram.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/child_process.h"
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "content/common/content_constants_internal.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gpu/gpu_config.h"
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/common/gpu/gpu_messages.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/common/sandbox_linux/sandbox_linux.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/gpu/gpu_child_thread.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/gpu/gpu_process.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/gpu/gpu_watchdog_thread.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_client.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_switches.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/main_function_params.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "gpu/command_buffer/service/gpu_switches.h"
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "gpu/config/gpu_info_collector.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "gpu/config/gpu_util.h"
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/events/platform/platform_event_source.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_implementation.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_switches.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gpu_switching_manager.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/win/windows_version.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_com_initializer.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_X11)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/sandbox_init.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_MACOSX)
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/message_loop/message_pump_mac.h"
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/common/sandbox_mac.h"
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(ADDRESS_SANITIZER)
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <sanitizer/asan_interface.h>
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kGpuTimeout = 10000;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               const CommandLine& command_line);
737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool WarmUpSandbox(const CommandLine& command_line);
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if !defined(OS_MACOSX)
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info);
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_LINUX)
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if !defined(OS_CHROMEOS)
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool CanAccessNvidiaDeviceFile();
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool StartSandboxLinux(const gpu::GPUInfo&, GpuWatchdogThread*, bool);
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(OS_WIN)
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*);
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::LazyInstance<GpuChildThread::DeferredMessages> deferred_messages =
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool GpuProcessLogMessageHandler(int severity,
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 const char* file, int line,
937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 size_t message_start,
947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                 const std::string& str) {
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string header = str.substr(0, message_start);
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string message = str.substr(message_start);
977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  deferred_messages.Get().push(new GpuHostMsg_OnLogMessage(
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      severity, header, message));
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return false;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace anonymous
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Main function for starting the Gpu process.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GpuMain(const MainFunctionParams& parameters) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("gpu", "GpuMain");
1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::debug::TraceLog::GetInstance()->SetProcessName("GPU Process");
1087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::debug::TraceLog::GetInstance()->SetProcessSortIndex(
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      kTraceEventGpuProcessSortIndex);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command_line = parameters.command_line;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line.HasSwitch(switches::kGpuStartupDialog)) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChildProcess::WaitForDebugger("Gpu");
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::Time start_time = base::Time::Now();
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Prevent Windows from displaying a modal dialog on failures like not being
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // able to load a DLL.
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SetErrorMode(
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SEM_FAILCRITICALERRORS |
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SEM_NOGPFAULTERRORBOX |
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SEM_NOOPENFILEERRORBOX);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(USE_X11)
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ui::SetDefaultX11ErrorHandlers();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  logging::SetLogMessageHandler(GpuProcessLogMessageHandler);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (command_line.HasSwitch(switches::kSupportsDualGpus)) {
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string types = command_line.GetSwitchValueASCII(
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        switches::kGpuDriverBugWorkarounds);
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::set<int> workarounds;
135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gpu::StringToFeatureSet(types, &workarounds);
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (workarounds.count(gpu::FORCE_DISCRETE_GPU) == 1)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu();
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    else if (workarounds.count(gpu::FORCE_INTEGRATED_GPU) == 1)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialization of the OpenGL bindings may fail, in which case we
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will need to tear down this process. However, we can not do so
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // safely until the IPC channel is set up, because the detection of
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // early return of a child process is implemented using an IPC
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // channel error. If the IPC channel is not fully set up between the
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // browser and GPU process, and the GPU process crashes or exits
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // early, the browser process will never detect it.  For this reason
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we defer tearing down the GPU process until receiving the
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GpuMsg_Initialize message from the browser.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool dead_on_arrival = false;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop::Type message_loop_type = base::MessageLoop::TYPE_IO;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unless we're running on desktop GL, we don't need a UI message
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loop, so avoid its use to work around apparent problems with some
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // third-party software.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line.HasSwitch(switches::kUseGL) &&
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kUseGL) ==
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gfx::kGLImplementationDesktopName) {
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    message_loop_type = base::MessageLoop::TYPE_UI;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop main_message_loop(message_loop_type);
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#elif defined(OS_LINUX) && defined(USE_X11)
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // and https://crbug.com/326995.
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ui::PlatformEventSource> event_source =
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ui::PlatformEventSource::CreateDefault();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop main_message_loop(base::MessageLoop::TYPE_DEFAULT);
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#elif defined(OS_MACOSX)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This is necessary for CoreAnimation layers hosted in the GPU process to be
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // drawn. See http://crbug.com/312462.
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop());
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop main_message_loop(pump.Pass());
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#else
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::MessageLoop main_message_loop(base::MessageLoop::TYPE_IO);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PlatformThread::SetName("CrGpuMain");
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In addition to disabling the watchdog if the command line switch is
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // present, disable the watchdog on valgrind because the code is expected
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to run slowly in that case.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enable_watchdog =
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      !command_line.HasSwitch(switches::kDisableGpuWatchdog) &&
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !RunningOnValgrind();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable the watchdog in debug builds because they tend to only be run by
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // developers who will not appreciate the watchdog killing the GPU process.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enable_watchdog = false;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool delayed_watchdog_enable = false;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_CHROMEOS)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't start watchdog immediately, to allow developers to switch to VT2 on
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // startup.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delayed_watchdog_enable = true;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<GpuWatchdogThread> watchdog_thread;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the GPU watchdog only after anything that is expected to be time
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // consuming has completed, otherwise the process is liable to be aborted.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enable_watchdog && !delayed_watchdog_enable) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watchdog_thread = new GpuWatchdogThread(kGpuTimeout);
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::Thread::Options options;
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    options.timer_slack = base::TIMER_SLACK_MAXIMUM;
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    watchdog_thread->StartWithOptions(options);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  gpu::GPUInfo gpu_info;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get vendor_id, device_id, driver_version from browser process through
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // commandline switches.
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GetGpuInfoFromCommandLine(gpu_info, command_line);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TimeDelta collect_context_time;
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TimeDelta initialize_one_off_time;
222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Warm up resources that don't need access to GPUInfo.
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (WarmUpSandbox(command_line)) {
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_LINUX)
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool initialized_sandbox = false;
2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool initialized_gl_context = false;
2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool should_initialize_gl_context = false;
229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // On Chrome OS ARM Mali, GPU driver userspace creates threads when
230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // initializing a GL context, so start the sandbox early.
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (command_line.HasSwitch(switches::kGpuSandboxStartEarly)) {
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      gpu_info.sandboxed = StartSandboxLinux(
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          gpu_info, watchdog_thread.get(), should_initialize_gl_context);
234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      initialized_sandbox = true;
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // defined(OS_LINUX)
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::TimeTicks before_initialize_one_off = base::TimeTicks::Now();
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determine if we need to initialize GL here or it has already been done.
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool gl_already_initialized = false;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_MACOSX)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!command_line.HasSwitch(switches::kNoSandbox)) {
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // On Mac, if the sandbox is enabled, then GLSurface::InitializeOneOff()
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // is called from the sandbox warmup code before getting here.
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_already_initialized = true;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (command_line.HasSwitch(switches::kInProcessGPU)) {
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // With in-process GPU, GLSurface::InitializeOneOff() is called from
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // GpuChildThread before getting here.
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      gl_already_initialized = true;
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Load and initialize the GL implementation and locate the GL entry points.
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool gl_initialized =
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        gl_already_initialized
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            ? gfx::GetGLImplementation() != gfx::kGLImplementationNone
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            : gfx::GLSurface::InitializeOneOff();
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (gl_initialized) {
2617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // We need to collect GL strings (VENDOR, RENDERER) for blacklisting
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // purposes. However, on Mac we don't actually use them. As documented in
2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // crbug.com/222934, due to some driver issues, glGetString could take
2647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // multiple seconds to finish, which in turn cause the GPU process to
2657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // crash.
2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // By skipping the following code on Mac, we don't really lose anything,
2677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // because the basic GPU information is passed down from browser process
2687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      // and we already registered them through SetGpuInfo() above.
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::TimeTicks before_collect_context_graphics_info =
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::TimeTicks::Now();
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_MACOSX)
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!CollectGraphicsInfo(gpu_info))
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        dead_on_arrival = true;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // Recompute gpu driver bug workarounds - this is specifically useful
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // on systems where vendor_id/device_id aren't available.
278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        gpu::ApplyGpuDriverBugWorkarounds(
280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            gpu_info, const_cast<CommandLine*>(&command_line));
281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_LINUX)
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      initialized_gl_context = true;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(OS_CHROMEOS)
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      if (gpu_info.gpu.vendor_id == 0x10de &&  // NVIDIA
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          gpu_info.driver_vendor == "NVIDIA" &&
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          !CanAccessNvidiaDeviceFile())
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        dead_on_arrival = true;
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // !defined(OS_CHROMEOS)
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // defined(OS_LINUX)
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // !defined(OS_MACOSX)
294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      collect_context_time =
295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::TimeTicks::Now() - before_collect_context_graphics_info;
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {  // gl_initialized
2977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
2987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      dead_on_arrival = true;
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
301a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    initialize_one_off_time =
302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        base::TimeTicks::Now() - before_initialize_one_off;
303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (enable_watchdog && delayed_watchdog_enable) {
3057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      watchdog_thread = new GpuWatchdogThread(kGpuTimeout);
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Thread::Options options;
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      options.timer_slack = base::TIMER_SLACK_MAXIMUM;
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      watchdog_thread->StartWithOptions(options);
3097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // OSMesa is expected to run very slowly, so disable the watchdog in that
3127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // case.
3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (enable_watchdog &&
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        gfx::GetGLImplementation() == gfx::kGLImplementationOSMesaGL) {
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      watchdog_thread->Stop();
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      watchdog_thread = NULL;
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
3207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    should_initialize_gl_context = !initialized_gl_context &&
3217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                   !dead_on_arrival;
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!initialized_sandbox) {
3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get(),
3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             should_initialize_gl_context);
3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(OS_WIN)
3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    gpu_info.sandboxed = StartSandboxWindows(parameters.sandbox_info);
329116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#elif defined(OS_MACOSX)
330116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    gpu_info.sandboxed = Sandbox::SandboxIsCurrentlyActive();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gpu_info.video_encode_accelerator_supported_profiles =
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        content::GpuVideoEncodeAccelerator::GetSupportedProfiles();
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  } else {
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dead_on_arrival = true;
3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  logging::SetLogMessageHandler(NULL);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GpuProcess gpu_process;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // These UMA must be stored after GpuProcess is constructed as it
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // initializes StatisticsRecorder which tracks the histograms.
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("GPU.InitializeOneOffTime", initialize_one_off_time);
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GpuChildThread* child_thread = new GpuChildThread(watchdog_thread.get(),
3497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                    dead_on_arrival,
3507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                    gpu_info,
3517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                    deferred_messages.Get());
3527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  while (!deferred_messages.Get().empty())
3537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    deferred_messages.Get().pop();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  child_thread->Init(start_time);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gpu_process.set_main_thread(child_thread);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (watchdog_thread.get())
3603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    watchdog_thread->AddPowerObserver();
3613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TRACE_EVENT0("gpu", "Run Message Loop");
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_message_loop.Run();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  child_thread->StopWatchdog();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info,
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               const CommandLine& command_line) {
376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(command_line.HasSwitch(switches::kGpuVendorID) &&
377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         command_line.HasSwitch(switches::kGpuDeviceID) &&
378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         command_line.HasSwitch(switches::kGpuDriverVersion));
379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool success = base::HexStringToUInt(
380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kGpuVendorID),
381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      &gpu_info.gpu.vendor_id);
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(success);
383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  success = base::HexStringToUInt(
384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kGpuDeviceID),
385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      &gpu_info.gpu.device_id);
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(success);
387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gpu_info.driver_vendor =
388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kGpuDriverVendor);
389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gpu_info.driver_version =
390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      command_line.GetSwitchValueASCII(switches::kGpuDriverVersion);
391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GetContentClient()->SetGpuInfo(gpu_info);
392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool WarmUpSandbox(const CommandLine& command_line) {
395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  {
396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    TRACE_EVENT0("gpu", "Warm up rand");
397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Warm up the random subsystem, which needs to be done pre-sandbox on all
398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // platforms.
399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    (void) base::RandUint64();
400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
403f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
404f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if !defined(OS_MACOSX)
405f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info) {
406f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool res = true;
407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info);
408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (result) {
409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case gpu::kCollectInfoFatalFailure:
410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      res = false;
412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case gpu::kCollectInfoNonFatalFailure:
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      VLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case gpu::kCollectInfoNone:
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      NOTREACHED();
4181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case gpu::kCollectInfoSuccess:
420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GetContentClient()->SetGpuInfo(gpu_info);
423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return res;
424f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
425f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
428f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if !defined(OS_CHROMEOS)
429f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool CanAccessNvidiaDeviceFile() {
430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool res = true;
431f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (access("/dev/nvidiactl", R_OK) != 0) {
433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    VLOG(1) << "NVIDIA device file /dev/nvidiactl access denied";
434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    res = false;
435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return res;
437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CreateDummyGlContext() {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<gfx::GLSurface> surface(
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size()));
443868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!surface.get()) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "gfx::GLSurface::CreateOffscreenGLSurface failed";
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Linux, this is needed to make sure /dev/nvidiactl has
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // been opened and its descriptor cached.
450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_refptr<gfx::GLContext> context(gfx::GLContext::CreateGLContext(
451868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      NULL, surface.get(), gfx::PreferDiscreteGpu));
452868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!context.get()) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "gfx::GLContext::CreateGLContext failed";
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Similarly, this is needed for /dev/nvidia0.
458868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (context->MakeCurrent(surface.get())) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context->ReleaseCurrent(surface.get());
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1)  << "gfx::GLContext::MakeCurrent failed";
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WarmUpSandboxNvidia(const gpu::GPUInfo& gpu_info,
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         bool should_initialize_gl_context) {
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We special case Optimus since the vendor_id we see may not be Nvidia.
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool uses_nvidia_driver = (gpu_info.gpu.vendor_id == 0x10de &&  // NVIDIA.
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             gpu_info.driver_vendor == "NVIDIA") ||
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            gpu_info.optimus;
471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (uses_nvidia_driver && should_initialize_gl_context) {
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We need this on Nvidia to pre-open /dev/nvidiactl and /dev/nvidia0.
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CreateDummyGlContext();
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool StartSandboxLinux(const gpu::GPUInfo& gpu_info,
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       GpuWatchdogThread* watchdog_thread,
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       bool should_initialize_gl_context) {
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TRACE_EVENT0("gpu", "Initialize sandbox");
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool res = false;
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WarmUpSandboxNvidia(gpu_info, should_initialize_gl_context);
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (watchdog_thread) {
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // LinuxSandbox needs to be able to ensure that the thread
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // has really been stopped.
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LinuxSandbox::StopThread(watchdog_thread);
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
49146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
49246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(ADDRESS_SANITIZER)
49346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  const std::string sancov_file_name =
49446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      "gpu." + base::Uint64ToString(base::RandUint64());
49546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance();
49646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  linux_sandbox->sanitizer_args()->coverage_sandboxed = 1;
49746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  linux_sandbox->sanitizer_args()->coverage_fd =
49846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      __sanitizer_maybe_open_cov_file(sancov_file_name.c_str());
49946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  linux_sandbox->sanitizer_args()->coverage_max_block_size = 0;
50046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
50146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // LinuxSandbox::InitializeSandbox() must always be called
503c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // with only one thread.
504c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  res = LinuxSandbox::InitializeSandbox();
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (watchdog_thread) {
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::Thread::Options options;
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    options.timer_slack = base::TIMER_SLACK_MAXIMUM;
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    watchdog_thread->StartWithOptions(options);
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return res;
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // defined(OS_LINUX)
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_WIN)
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo* sandbox_info) {
517c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TRACE_EVENT0("gpu", "Lower token");
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // For Windows, if the target_services interface is not zero, the process
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // is sandboxed and we must call LowerToken() before rendering untrusted
521c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // content.
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sandbox::TargetServices* target_services = sandbox_info->target_services;
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (target_services) {
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    target_services->LowerToken();
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
526c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
529c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // defined(OS_WIN)
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
535