| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 | 7 |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/lazy_instance.h" | |
| 12 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 13 #include "base/metrics/histogram.h" | |
| 14 #include "base/metrics/statistics_recorder.h" | |
| 15 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 16 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 17 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 19 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 16 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| 20 #include "base/threading/platform_thread.h" | 17 #include "base/threading/platform_thread.h" |
| 21 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 22 #include "build/build_config.h" | 19 #include "build/build_config.h" |
| 23 #include "content/child/child_process.h" | 20 #include "content/child/child_process.h" |
| 24 #include "content/common/content_constants_internal.h" | 21 #include "content/common/content_constants_internal.h" |
| 25 #include "content/common/gpu_host_messages.h" | |
| 26 #include "content/common/sandbox_linux/sandbox_linux.h" | 22 #include "content/common/sandbox_linux/sandbox_linux.h" |
| 27 #include "content/gpu/gpu_child_thread.h" | 23 #include "content/gpu/gpu_child_thread.h" |
| 28 #include "content/gpu/gpu_process.h" | 24 #include "content/gpu/gpu_process.h" |
| 29 #include "content/public/common/content_client.h" | 25 #include "content/public/common/content_client.h" |
| 30 #include "content/public/common/content_switches.h" | 26 #include "content/public/common/content_switches.h" |
| 31 #include "content/public/common/main_function_params.h" | 27 #include "content/public/common/main_function_params.h" |
| 32 #include "gpu/command_buffer/service/gpu_switches.h" | 28 #include "gpu/command_buffer/service/gpu_switches.h" |
| 33 #include "gpu/config/gpu_info_collector.h" | 29 #include "gpu/config/gpu_info_collector.h" |
| 34 #include "gpu/config/gpu_switches.h" | |
| 35 #include "gpu/config/gpu_util.h" | |
| 36 #include "gpu/ipc/common/gpu_memory_buffer_support.h" | |
| 37 #include "gpu/ipc/service/gpu_config.h" | 30 #include "gpu/ipc/service/gpu_config.h" |
| 38 #include "gpu/ipc/service/gpu_memory_buffer_factory.h" | 31 #include "gpu/ipc/service/gpu_init.h" |
| 32 #include "gpu/ipc/service/gpu_init_delegate.h" |
| 39 #include "gpu/ipc/service/gpu_watchdog_thread.h" | 33 #include "gpu/ipc/service/gpu_watchdog_thread.h" |
| 40 #include "ui/events/platform/platform_event_source.h" | 34 #include "ui/events/platform/platform_event_source.h" |
| 41 #include "ui/gl/gl_context.h" | |
| 42 #include "ui/gl/gl_implementation.h" | |
| 43 #include "ui/gl/gl_surface.h" | |
| 44 #include "ui/gl/gl_switches.h" | |
| 45 #include "ui/gl/gpu_switching_manager.h" | |
| 46 #include "ui/gl/init/gl_factory.h" | |
| 47 | 35 |
| 48 #if defined(OS_WIN) | 36 #if defined(OS_WIN) |
| 49 #include <windows.h> | 37 #include <windows.h> |
| 50 #include <dwmapi.h> | 38 #include <dwmapi.h> |
| 51 #endif | 39 #endif |
| 52 | 40 |
| 53 #if defined(OS_ANDROID) | 41 #if defined(OS_ANDROID) |
| 54 #include "base/trace_event/memory_dump_manager.h" | 42 #include "base/trace_event/memory_dump_manager.h" |
| 55 #include "components/tracing/common/graphics_memory_dump_provider_android.h" | 43 #include "components/tracing/common/graphics_memory_dump_provider_android.h" |
| 56 #endif | 44 #endif |
| 57 | 45 |
| 58 #if defined(OS_WIN) | 46 #if defined(OS_WIN) |
| 59 #include "base/win/scoped_com_initializer.h" | 47 #include "base/win/scoped_com_initializer.h" |
| 60 #include "base/win/windows_version.h" | 48 #include "base/win/windows_version.h" |
| 61 #include "media/gpu/dxva_video_decode_accelerator_win.h" | 49 #include "media/gpu/dxva_video_decode_accelerator_win.h" |
| 62 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" | 50 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" |
| 63 #include "sandbox/win/src/sandbox.h" | 51 #include "sandbox/win/src/sandbox.h" |
| 64 #endif | 52 #endif |
| 65 | 53 |
| 66 #if defined(USE_X11) | 54 #if defined(USE_X11) |
| 67 #include "ui/base/x/x11_util.h" // nogncheck | |
| 68 #include "ui/gfx/x/x11_switches.h" // nogncheck | 55 #include "ui/gfx/x/x11_switches.h" // nogncheck |
| 69 #endif | 56 #endif |
| 70 | 57 |
| 71 #if defined(OS_LINUX) | 58 #if defined(OS_LINUX) |
| 72 #include "content/public/common/sandbox_init.h" | 59 #include "content/public/common/sandbox_init.h" |
| 73 #endif | 60 #endif |
| 74 | 61 |
| 75 #if defined(OS_MACOSX) | 62 #if defined(OS_MACOSX) |
| 76 #include "base/message_loop/message_pump_mac.h" | 63 #include "base/message_loop/message_pump_mac.h" |
| 77 #include "content/common/sandbox_mac.h" | 64 #include "content/common/sandbox_mac.h" |
| 78 #endif | 65 #endif |
| 79 | 66 |
| 80 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) | 67 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) |
| 81 #include "media/gpu/vaapi_wrapper.h" | 68 #include "media/gpu/vaapi_wrapper.h" |
| 82 #endif | 69 #endif |
| 83 | 70 |
| 84 #if defined(SANITIZER_COVERAGE) | 71 #if defined(SANITIZER_COVERAGE) |
| 85 #include <sanitizer/common_interface_defs.h> | 72 #include <sanitizer/common_interface_defs.h> |
| 86 #include <sanitizer/coverage_interface.h> | 73 #include <sanitizer/coverage_interface.h> |
| 87 #endif | 74 #endif |
| 88 | 75 |
| 89 namespace content { | 76 namespace content { |
| 90 | 77 |
| 91 namespace { | 78 namespace { |
| 92 | 79 |
| 93 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, | |
| 94 const base::CommandLine& command_line); | |
| 95 void WarmUpSandbox(); | |
| 96 | |
| 97 #if !defined(OS_MACOSX) | |
| 98 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info); | |
| 99 #endif | |
| 100 | |
| 101 #if defined(OS_LINUX) | 80 #if defined(OS_LINUX) |
| 102 #if !defined(OS_CHROMEOS) | |
| 103 bool CanAccessNvidiaDeviceFile(); | |
| 104 #endif | |
| 105 bool StartSandboxLinux(const gpu::GPUInfo&, gpu::GpuWatchdogThread*); | 81 bool StartSandboxLinux(const gpu::GPUInfo&, gpu::GpuWatchdogThread*); |
| 106 #elif defined(OS_WIN) | 82 #elif defined(OS_WIN) |
| 107 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); | 83 bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*); |
| 108 #endif | 84 #endif |
| 109 | 85 |
| 110 base::LazyInstance<GpuChildThread::DeferredMessages> deferred_messages = | 86 class ContentGpuInitDelegate : public gpu::GpuInitDelegate { |
| 111 LAZY_INSTANCE_INITIALIZER; | 87 public: |
| 88 explicit ContentGpuInitDelegate(const base::CommandLine* command_line) |
| 89 : command_line_(command_line), watchdog_thread_(nullptr) { |
| 90 DCHECK(command_line_); |
| 91 } |
| 92 ~ContentGpuInitDelegate() override {} |
| 112 | 93 |
| 113 bool GpuProcessLogMessageHandler(int severity, | 94 #if defined(OS_WIN) |
| 114 const char* file, int line, | 95 void set_sandbox_info(sandbox::SandboxInterfaceInfo* sandbox_info) { |
| 115 size_t message_start, | 96 sandbox_info_ = sandbox_info; |
| 116 const std::string& str) { | 97 } |
| 117 std::string header = str.substr(0, message_start); | 98 #endif |
| 118 std::string message = str.substr(message_start); | 99 |
| 119 deferred_messages.Get().push( | 100 private: |
| 120 new GpuHostMsg_OnLogMessage(severity, header, message)); | 101 // gpu::GpuInit::Delegate: |
| 121 return false; | 102 void OnGpuInfoUpdate(const gpu::GPUInfo& gpu_info) override { |
| 122 } | 103 gpu_info_ = gpu_info; |
| 104 GetContentClient()->SetGpuInfo(gpu_info_); |
| 105 } |
| 106 |
| 107 void OnGpuWatchdogThreadCreated(gpu::GpuWatchdogThread* thread) override { |
| 108 watchdog_thread_ = thread; |
| 109 } |
| 110 |
| 111 void OnGpuWatchdogThreadDestroyed() override { watchdog_thread_ = nullptr; } |
| 112 |
| 113 bool ShouldInitializeGL() override { |
| 114 #if defined(OS_MACOSX) |
| 115 // On Mac, if the sandbox is enabled, then gl::init::InitializeGLOneOff() |
| 116 // is called from the sandbox warmup code before getting here. |
| 117 if (!command_line_->HasSwitch(switches::kNoSandbox)) |
| 118 return false; |
| 119 #endif |
| 120 if (command_line_->HasSwitch(switches::kInProcessGPU)) { |
| 121 // With in-process GPU, gl::init::InitializeGLOneOff() is called from |
| 122 // GpuChildThread before getting here. |
| 123 return false; |
| 124 } |
| 125 return true; |
| 126 } |
| 127 |
| 128 void WaitForDebugger() override { ChildProcess::WaitForDebugger("Gpu"); } |
| 129 |
| 130 void InitializeMessageLoop() override { |
| 131 #if defined(OS_WIN) |
| 132 // Use a UI message loop because ANGLE and the desktop GL platform can |
| 133 // create child windows to render to. |
| 134 base::MessagePumpForGpu::InitFactory(); |
| 135 message_loop_ = |
| 136 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_UI); |
| 137 #elif defined(OS_LINUX) && defined(USE_X11) |
| 138 // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX |
| 139 // and https://crbug.com/326995. |
| 140 message_loop_ = |
| 141 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_UI); |
| 142 std::unique_ptr<ui::PlatformEventSource> event_source = |
| 143 ui::PlatformEventSource::CreateDefault(); |
| 144 #elif defined(OS_LINUX) |
| 145 message_loop_ = |
| 146 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_DEFAULT); |
| 147 #elif defined(OS_MACOSX) |
| 148 // This is necessary for CoreAnimation layers hosted in the GPU process to |
| 149 // be |
| 150 // drawn. See http://crbug.com/312462. |
| 151 std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop()); |
| 152 message_loop_ = base::MakeUnique<base::MessageLoop>(std::move(pump)); |
| 153 #else |
| 154 message_loop_ = |
| 155 base::MakeUnique<base::MessageLoop>(base::MessageLoop::TYPE_IO); |
| 156 #endif |
| 157 } |
| 158 |
| 159 void PreSandboxInitialization() override { |
| 160 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) |
| 161 media::VaapiWrapper::PreSandboxInitialization(); |
| 162 #endif |
| 163 } |
| 164 |
| 165 bool ShouldStartSandboxEarly() override { |
| 166 #if defined(OS_LINUX) |
| 167 // On Chrome OS ARM Mali, GPU driver userspace creates threads when |
| 168 // initializing a GL context, so start the sandbox early. |
| 169 return command_line_->HasSwitch(switches::kGpuSandboxStartEarly); |
| 170 #else |
| 171 return false; |
| 172 #endif |
| 173 } |
| 174 |
| 175 void WarmUpSandbox() override { |
| 176 #if defined(OS_WIN) |
| 177 media::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); |
| 178 media::MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization(); |
| 179 #endif |
| 180 } |
| 181 |
| 182 bool StartSandbox() override { |
| 183 #if defined(OS_LINUX) |
| 184 return StartSandboxLinux(gpu_info_, watchdog_thread_); |
| 185 #elif defined(OS_WIN) |
| 186 return StartSandboxWindows(sandbox_info_); |
| 187 #elif defined(OS_MACOSX) |
| 188 return Sandbox::SandboxIsCurrentlyActive(); |
| 189 #else |
| 190 return false; |
| 191 #endif |
| 192 } |
| 193 |
| 194 void Initialize(base::Time start_time, |
| 195 bool dead_on_arrival, |
| 196 std::vector<gpu::GpuInitLogMessage> init_log_messages, |
| 197 gpu::GpuMemoryBufferFactory* gpu_buffer_factory) override { |
| 198 base::ThreadPriority io_thread_priority = base::ThreadPriority::NORMAL; |
| 199 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) |
| 200 io_thread_priority = base::ThreadPriority::DISPLAY; |
| 201 #endif |
| 202 gpu_process_.reset(new GpuProcess(io_thread_priority)); |
| 203 |
| 204 GpuChildThread* child_thread = |
| 205 new GpuChildThread(watchdog_thread_, dead_on_arrival, gpu_info_, |
| 206 std::move(init_log_messages), gpu_buffer_factory); |
| 207 child_thread->Init(start_time); |
| 208 |
| 209 gpu_process_->set_main_thread(child_thread); |
| 210 |
| 211 #if defined(OS_ANDROID) |
| 212 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( |
| 213 tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics", |
| 214 nullptr); |
| 215 #endif |
| 216 } |
| 217 |
| 218 const base::CommandLine* command_line_; |
| 219 gpu::GpuWatchdogThread* watchdog_thread_ = nullptr; |
| 220 gpu::GPUInfo gpu_info_; |
| 221 std::unique_ptr<base::MessageLoop> message_loop_; |
| 222 std::unique_ptr<GpuProcess> gpu_process_; |
| 223 #if defined(OS_WIN) |
| 224 sandbox::SandboxInterfaceInfo* sandbox_info_ = nullptr; |
| 225 #endif |
| 226 |
| 227 DISALLOW_COPY_AND_ASSIGN(ContentGpuInitDelegate); |
| 228 }; |
| 123 | 229 |
| 124 } // namespace anonymous | 230 } // namespace anonymous |
| 125 | 231 |
| 126 // Main function for starting the Gpu process. | 232 // Main function for starting the Gpu process. |
| 127 int GpuMain(const MainFunctionParams& parameters) { | 233 int GpuMain(const MainFunctionParams& parameters) { |
| 128 TRACE_EVENT0("gpu", "GpuMain"); | 234 TRACE_EVENT0("gpu", "GpuMain"); |
| 129 base::trace_event::TraceLog::GetInstance()->SetProcessName("GPU Process"); | 235 base::trace_event::TraceLog::GetInstance()->SetProcessName("GPU Process"); |
| 130 base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( | 236 base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( |
| 131 kTraceEventGpuProcessSortIndex); | 237 kTraceEventGpuProcessSortIndex); |
| 132 | 238 |
| 133 const base::CommandLine& command_line = parameters.command_line; | 239 DCHECK(parameters.command_line.HasSwitch(switches::kGpuVendorID) && |
| 134 if (command_line.HasSwitch(switches::kGpuStartupDialog)) { | 240 parameters.command_line.HasSwitch(switches::kGpuDeviceID) && |
| 135 ChildProcess::WaitForDebugger("Gpu"); | 241 parameters.command_line.HasSwitch(switches::kGpuDriverVersion)); |
| 136 } | 242 #if defined(USE_X11) && !defined(OS_CHROMEOS) |
| 243 DCHECK(parameters.command_line.HasSwitch(switches::kWindowDepth)); |
| 244 DCHECK(parameters.command_line.HasSwitch(switches::kX11VisualID)); |
| 245 #endif // defined(USE_X11) && !defined(OS_CHROMEOS) |
| 137 | 246 |
| 138 base::Time start_time = base::Time::Now(); | 247 ContentGpuInitDelegate init_delegate(¶meters.command_line); |
| 139 | |
| 140 #if defined(OS_WIN) | 248 #if defined(OS_WIN) |
| 141 // Prevent Windows from displaying a modal dialog on failures like not being | 249 init_delegate.set_sandbox_info(parameters.sandbox_info); |
| 142 // able to load a DLL. | |
| 143 SetErrorMode( | |
| 144 SEM_FAILCRITICALERRORS | | |
| 145 SEM_NOGPFAULTERRORBOX | | |
| 146 SEM_NOOPENFILEERRORBOX); | |
| 147 #elif defined(USE_X11) | |
| 148 ui::SetDefaultX11ErrorHandlers(); | |
| 149 | |
| 150 #if !defined(OS_CHROMEOS) | |
| 151 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 152 switches::kWindowDepth)); | |
| 153 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 154 switches::kX11VisualID)); | |
| 155 #endif | 250 #endif |
| 156 | 251 gpu::GpuInit gpu_init(&init_delegate, parameters.command_line); |
| 157 #endif | |
| 158 | |
| 159 logging::SetLogMessageHandler(GpuProcessLogMessageHandler); | |
| 160 | |
| 161 if (command_line.HasSwitch(switches::kSupportsDualGpus)) { | |
| 162 std::string types = command_line.GetSwitchValueASCII( | |
| 163 switches::kGpuDriverBugWorkarounds); | |
| 164 std::set<int> workarounds; | |
| 165 gpu::StringToFeatureSet(types, &workarounds); | |
| 166 if (workarounds.count(gpu::FORCE_DISCRETE_GPU) == 1) | |
| 167 ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu(); | |
| 168 else if (workarounds.count(gpu::FORCE_INTEGRATED_GPU) == 1) | |
| 169 ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu(); | |
| 170 } | |
| 171 | |
| 172 // Initialization of the OpenGL bindings may fail, in which case we | |
| 173 // will need to tear down this process. However, we can not do so | |
| 174 // safely until the IPC channel is set up, because the detection of | |
| 175 // early return of a child process is implemented using an IPC | |
| 176 // channel error. If the IPC channel is not fully set up between the | |
| 177 // browser and GPU process, and the GPU process crashes or exits | |
| 178 // early, the browser process will never detect it. For this reason | |
| 179 // we defer tearing down the GPU process until receiving the | |
| 180 // GpuMsg_Initialize message from the browser. | |
| 181 bool dead_on_arrival = false; | |
| 182 | |
| 183 #if defined(OS_WIN) | |
| 184 // Use a UI message loop because ANGLE and the desktop GL platform can | |
| 185 // create child windows to render to. | |
| 186 base::MessagePumpForGpu::InitFactory(); | |
| 187 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI); | |
| 188 #elif defined(OS_LINUX) && defined(USE_X11) | |
| 189 // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX | |
| 190 // and https://crbug.com/326995. | |
| 191 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI); | |
| 192 std::unique_ptr<ui::PlatformEventSource> event_source = | |
| 193 ui::PlatformEventSource::CreateDefault(); | |
| 194 #elif defined(OS_LINUX) | |
| 195 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_DEFAULT); | |
| 196 #elif defined(OS_MACOSX) | |
| 197 // This is necessary for CoreAnimation layers hosted in the GPU process to be | |
| 198 // drawn. See http://crbug.com/312462. | |
| 199 std::unique_ptr<base::MessagePump> pump(new base::MessagePumpCFRunLoop()); | |
| 200 base::MessageLoop main_message_loop(std::move(pump)); | |
| 201 #else | |
| 202 base::MessageLoop main_message_loop(base::MessageLoop::TYPE_IO); | |
| 203 #endif | |
| 204 | |
| 205 base::PlatformThread::SetName("CrGpuMain"); | |
| 206 | |
| 207 // In addition to disabling the watchdog if the command line switch is | |
| 208 // present, disable the watchdog on valgrind because the code is expected | |
| 209 // to run slowly in that case. | |
| 210 bool enable_watchdog = | |
| 211 !command_line.HasSwitch(switches::kDisableGpuWatchdog) && | |
| 212 !RunningOnValgrind(); | |
| 213 | |
| 214 // Disable the watchdog in debug builds because they tend to only be run by | |
| 215 // developers who will not appreciate the watchdog killing the GPU process. | |
| 216 #ifndef NDEBUG | |
| 217 enable_watchdog = false; | |
| 218 #endif | |
| 219 | |
| 220 bool delayed_watchdog_enable = false; | |
| 221 | |
| 222 #if defined(OS_CHROMEOS) | |
| 223 // Don't start watchdog immediately, to allow developers to switch to VT2 on | |
| 224 // startup. | |
| 225 delayed_watchdog_enable = true; | |
| 226 #endif | |
| 227 | |
| 228 scoped_refptr<gpu::GpuWatchdogThread> watchdog_thread; | |
| 229 | |
| 230 // Start the GPU watchdog only after anything that is expected to be time | |
| 231 // consuming has completed, otherwise the process is liable to be aborted. | |
| 232 if (enable_watchdog && !delayed_watchdog_enable) | |
| 233 watchdog_thread = gpu::GpuWatchdogThread::Create(); | |
| 234 | |
| 235 // Initializes StatisticsRecorder which tracks UMA histograms. | |
| 236 base::StatisticsRecorder::Initialize(); | |
| 237 | |
| 238 gpu::GPUInfo gpu_info; | |
| 239 // Get vendor_id, device_id, driver_version from browser process through | |
| 240 // commandline switches. | |
| 241 GetGpuInfoFromCommandLine(gpu_info, command_line); | |
| 242 gpu_info.in_process_gpu = false; | |
| 243 | |
| 244 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) | |
| 245 media::VaapiWrapper::PreSandboxInitialization(); | |
| 246 #endif | |
| 247 | |
| 248 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) | |
| 249 // Set thread priority before sandbox initialization. | |
| 250 base::PlatformThread::SetCurrentThreadPriority(base::ThreadPriority::DISPLAY); | |
| 251 #endif | |
| 252 | |
| 253 // Warm up resources that don't need access to GPUInfo. | |
| 254 WarmUpSandbox(); | |
| 255 | |
| 256 #if defined(OS_LINUX) | |
| 257 bool initialized_sandbox = false; | |
| 258 // On Chrome OS ARM Mali, GPU driver userspace creates threads when | |
| 259 // initializing a GL context, so start the sandbox early. | |
| 260 if (command_line.HasSwitch(switches::kGpuSandboxStartEarly)) { | |
| 261 gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get()); | |
| 262 initialized_sandbox = true; | |
| 263 } | |
| 264 #endif // defined(OS_LINUX) | |
| 265 | |
| 266 base::TimeTicks before_initialize_one_off = base::TimeTicks::Now(); | |
| 267 | |
| 268 // Determine if we need to initialize GL here or it has already been done. | |
| 269 bool gl_already_initialized = false; | |
| 270 #if defined(OS_MACOSX) | |
| 271 if (!command_line.HasSwitch(switches::kNoSandbox)) { | |
| 272 // On Mac, if the sandbox is enabled, then gl::init::InitializeGLOneOff() | |
| 273 // is called from the sandbox warmup code before getting here. | |
| 274 gl_already_initialized = true; | |
| 275 } | |
| 276 #endif | |
| 277 if (command_line.HasSwitch(switches::kInProcessGPU)) { | |
| 278 // With in-process GPU, gl::init::InitializeGLOneOff() is called from | |
| 279 // GpuChildThread before getting here. | |
| 280 gl_already_initialized = true; | |
| 281 } | |
| 282 | |
| 283 // Load and initialize the GL implementation and locate the GL entry points. | |
| 284 bool gl_initialized = | |
| 285 gl_already_initialized | |
| 286 ? gl::GetGLImplementation() != gl::kGLImplementationNone | |
| 287 : gl::init::InitializeGLOneOff(); | |
| 288 if (gl_initialized) { | |
| 289 // We need to collect GL strings (VENDOR, RENDERER) for blacklisting | |
| 290 // purposes. However, on Mac we don't actually use them. As documented in | |
| 291 // crbug.com/222934, due to some driver issues, glGetString could take | |
| 292 // multiple seconds to finish, which in turn cause the GPU process to | |
| 293 // crash. | |
| 294 // By skipping the following code on Mac, we don't really lose anything, | |
| 295 // because the basic GPU information is passed down from browser process | |
| 296 // and we already registered them through SetGpuInfo() above. | |
| 297 base::TimeTicks before_collect_context_graphics_info = | |
| 298 base::TimeTicks::Now(); | |
| 299 #if !defined(OS_MACOSX) | |
| 300 if (!CollectGraphicsInfo(gpu_info)) | |
| 301 dead_on_arrival = true; | |
| 302 | |
| 303 // Recompute gpu driver bug workarounds. | |
| 304 // This is necessary on systems where vendor_id/device_id aren't available | |
| 305 // (Chrome OS, Android) or where workarounds may be dependent on GL_VENDOR | |
| 306 // and GL_RENDERER strings which are lazily computed (Linux). | |
| 307 if (!command_line.HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { | |
| 308 // TODO: this can not affect disabled extensions, since they're already | |
| 309 // initialized in the bindings. This should be moved before bindings | |
| 310 // initialization. However, populating GPUInfo fully works only on | |
| 311 // Android. Other platforms would need the bindings to query GL strings. | |
| 312 gpu::ApplyGpuDriverBugWorkarounds( | |
| 313 gpu_info, const_cast<base::CommandLine*>(&command_line)); | |
| 314 } | |
| 315 #endif // !defined(OS_MACOSX) | |
| 316 | |
| 317 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
| 318 if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA | |
| 319 gpu_info.driver_vendor == "NVIDIA" && !CanAccessNvidiaDeviceFile()) | |
| 320 dead_on_arrival = true; | |
| 321 #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
| 322 | |
| 323 base::TimeDelta collect_context_time = | |
| 324 base::TimeTicks::Now() - before_collect_context_graphics_info; | |
| 325 UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time); | |
| 326 } else { // gl_initialized | |
| 327 VLOG(1) << "gl::init::InitializeGLOneOff failed"; | |
| 328 dead_on_arrival = true; | |
| 329 } | |
| 330 | |
| 331 base::TimeDelta initialize_one_off_time = | |
| 332 base::TimeTicks::Now() - before_initialize_one_off; | |
| 333 UMA_HISTOGRAM_MEDIUM_TIMES("GPU.InitializeOneOffMediumTime", | |
| 334 initialize_one_off_time); | |
| 335 if (enable_watchdog && delayed_watchdog_enable) | |
| 336 watchdog_thread = gpu::GpuWatchdogThread::Create(); | |
| 337 | |
| 338 // OSMesa is expected to run very slowly, so disable the watchdog in that | |
| 339 // case. | |
| 340 if (enable_watchdog && | |
| 341 gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) { | |
| 342 watchdog_thread->Stop(); | |
| 343 watchdog_thread = NULL; | |
| 344 } | |
| 345 | |
| 346 #if defined(OS_LINUX) | |
| 347 if (!initialized_sandbox) | |
| 348 gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get()); | |
| 349 #elif defined(OS_WIN) | |
| 350 gpu_info.sandboxed = StartSandboxWindows(parameters.sandbox_info); | |
| 351 #elif defined(OS_MACOSX) | |
| 352 gpu_info.sandboxed = Sandbox::SandboxIsCurrentlyActive(); | |
| 353 #endif | |
| 354 | |
| 355 logging::SetLogMessageHandler(NULL); | |
| 356 | |
| 357 std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory; | |
| 358 if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) | |
| 359 gpu_memory_buffer_factory = gpu::GpuMemoryBufferFactory::CreateNativeType(); | |
| 360 | |
| 361 base::ThreadPriority io_thread_priority = base::ThreadPriority::NORMAL; | |
| 362 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) | |
| 363 io_thread_priority = base::ThreadPriority::DISPLAY; | |
| 364 #endif | |
| 365 | |
| 366 GpuProcess gpu_process(io_thread_priority); | |
| 367 | |
| 368 GpuChildThread* child_thread = new GpuChildThread( | |
| 369 watchdog_thread.get(), dead_on_arrival, gpu_info, deferred_messages.Get(), | |
| 370 gpu_memory_buffer_factory.get()); | |
| 371 while (!deferred_messages.Get().empty()) | |
| 372 deferred_messages.Get().pop(); | |
| 373 | |
| 374 child_thread->Init(start_time); | |
| 375 | |
| 376 gpu_process.set_main_thread(child_thread); | |
| 377 | |
| 378 if (watchdog_thread.get()) | |
| 379 watchdog_thread->AddPowerObserver(); | |
| 380 | |
| 381 #if defined(OS_ANDROID) | |
| 382 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | |
| 383 tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics", | |
| 384 nullptr); | |
| 385 #endif | |
| 386 | |
| 387 { | 252 { |
| 388 TRACE_EVENT0("gpu", "Run Message Loop"); | 253 TRACE_EVENT0("gpu", "Run Message Loop"); |
| 389 base::RunLoop().Run(); | 254 base::RunLoop().Run(); |
| 390 } | 255 } |
| 391 | 256 |
| 392 child_thread->StopWatchdog(); | 257 return 0; |
| 393 | |
| 394 return dead_on_arrival ? 2 : 0; | |
| 395 } | 258 } |
| 396 | 259 |
| 397 namespace { | 260 namespace { |
| 398 | 261 |
| 399 void GetGpuInfoFromCommandLine(gpu::GPUInfo& gpu_info, | |
| 400 const base::CommandLine& command_line) { | |
| 401 DCHECK(command_line.HasSwitch(switches::kGpuVendorID) && | |
| 402 command_line.HasSwitch(switches::kGpuDeviceID) && | |
| 403 command_line.HasSwitch(switches::kGpuDriverVersion)); | |
| 404 bool success = base::HexStringToUInt( | |
| 405 command_line.GetSwitchValueASCII(switches::kGpuVendorID), | |
| 406 &gpu_info.gpu.vendor_id); | |
| 407 DCHECK(success); | |
| 408 success = base::HexStringToUInt( | |
| 409 command_line.GetSwitchValueASCII(switches::kGpuDeviceID), | |
| 410 &gpu_info.gpu.device_id); | |
| 411 DCHECK(success); | |
| 412 gpu_info.driver_vendor = | |
| 413 command_line.GetSwitchValueASCII(switches::kGpuDriverVendor); | |
| 414 gpu_info.driver_version = | |
| 415 command_line.GetSwitchValueASCII(switches::kGpuDriverVersion); | |
| 416 gpu_info.driver_date = | |
| 417 command_line.GetSwitchValueASCII(switches::kGpuDriverDate); | |
| 418 gpu::ParseSecondaryGpuDevicesFromCommandLine(command_line, &gpu_info); | |
| 419 | |
| 420 // Set active gpu device. | |
| 421 if (command_line.HasSwitch(switches::kGpuActiveVendorID) && | |
| 422 command_line.HasSwitch(switches::kGpuActiveDeviceID)) { | |
| 423 uint32_t active_vendor_id = 0; | |
| 424 uint32_t active_device_id = 0; | |
| 425 success = base::HexStringToUInt( | |
| 426 command_line.GetSwitchValueASCII(switches::kGpuActiveVendorID), | |
| 427 &active_vendor_id); | |
| 428 DCHECK(success); | |
| 429 success = base::HexStringToUInt( | |
| 430 command_line.GetSwitchValueASCII(switches::kGpuActiveDeviceID), | |
| 431 &active_device_id); | |
| 432 DCHECK(success); | |
| 433 if (gpu_info.gpu.vendor_id == active_vendor_id && | |
| 434 gpu_info.gpu.device_id == active_device_id) { | |
| 435 gpu_info.gpu.active = true; | |
| 436 } else { | |
| 437 for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { | |
| 438 if (gpu_info.secondary_gpus[i].vendor_id == active_vendor_id && | |
| 439 gpu_info.secondary_gpus[i].device_id == active_device_id) { | |
| 440 gpu_info.secondary_gpus[i].active = true; | |
| 441 break; | |
| 442 } | |
| 443 } | |
| 444 } | |
| 445 } | |
| 446 | |
| 447 GetContentClient()->SetGpuInfo(gpu_info); | |
| 448 } | |
| 449 | |
| 450 void WarmUpSandbox() { | |
| 451 { | |
| 452 TRACE_EVENT0("gpu", "Warm up rand"); | |
| 453 // Warm up the random subsystem, which needs to be done pre-sandbox on all | |
| 454 // platforms. | |
| 455 (void) base::RandUint64(); | |
| 456 } | |
| 457 | |
| 458 #if defined(OS_WIN) | |
| 459 media::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); | |
| 460 media::MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization(); | |
| 461 #endif | |
| 462 } | |
| 463 | |
| 464 #if !defined(OS_MACOSX) | |
| 465 bool CollectGraphicsInfo(gpu::GPUInfo& gpu_info) { | |
| 466 TRACE_EVENT0("gpu,startup", "Collect Graphics Info"); | |
| 467 | |
| 468 bool res = true; | |
| 469 gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info); | |
| 470 switch (result) { | |
| 471 case gpu::kCollectInfoFatalFailure: | |
| 472 LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal)."; | |
| 473 res = false; | |
| 474 break; | |
| 475 case gpu::kCollectInfoNonFatalFailure: | |
| 476 DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal)."; | |
| 477 break; | |
| 478 case gpu::kCollectInfoNone: | |
| 479 NOTREACHED(); | |
| 480 break; | |
| 481 case gpu::kCollectInfoSuccess: | |
| 482 break; | |
| 483 } | |
| 484 GetContentClient()->SetGpuInfo(gpu_info); | |
| 485 return res; | |
| 486 } | |
| 487 #endif | |
| 488 | |
| 489 #if defined(OS_LINUX) | 262 #if defined(OS_LINUX) |
| 490 #if !defined(OS_CHROMEOS) | |
| 491 bool CanAccessNvidiaDeviceFile() { | |
| 492 bool res = true; | |
| 493 base::ThreadRestrictions::AssertIOAllowed(); | |
| 494 if (access("/dev/nvidiactl", R_OK) != 0) { | |
| 495 DVLOG(1) << "NVIDIA device file /dev/nvidiactl access denied"; | |
| 496 res = false; | |
| 497 } | |
| 498 return res; | |
| 499 } | |
| 500 #endif | |
| 501 | |
| 502 bool StartSandboxLinux(const gpu::GPUInfo& gpu_info, | 263 bool StartSandboxLinux(const gpu::GPUInfo& gpu_info, |
| 503 gpu::GpuWatchdogThread* watchdog_thread) { | 264 gpu::GpuWatchdogThread* watchdog_thread) { |
| 504 TRACE_EVENT0("gpu,startup", "Initialize sandbox"); | 265 TRACE_EVENT0("gpu,startup", "Initialize sandbox"); |
| 505 | 266 |
| 506 bool res = false; | 267 bool res = false; |
| 507 | 268 |
| 508 if (watchdog_thread) { | 269 if (watchdog_thread) { |
| 509 // LinuxSandbox needs to be able to ensure that the thread | 270 // LinuxSandbox needs to be able to ensure that the thread |
| 510 // has really been stopped. | 271 // has really been stopped. |
| 511 LinuxSandbox::StopThread(watchdog_thread); | 272 LinuxSandbox::StopThread(watchdog_thread); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 return true; | 308 return true; |
| 548 } | 309 } |
| 549 | 310 |
| 550 return false; | 311 return false; |
| 551 } | 312 } |
| 552 #endif // defined(OS_WIN) | 313 #endif // defined(OS_WIN) |
| 553 | 314 |
| 554 } // namespace. | 315 } // namespace. |
| 555 | 316 |
| 556 } // namespace content | 317 } // namespace content |
| OLD | NEW |