Commit 663c4b35 authored by jorgelo@chromium.org's avatar jorgelo@chromium.org

Refactor GPU init to allow ARM sandboxing.

    
BUG=232068
TEST=daisy loads and GPU acceleration works together with a policy change.
TEST=desktop Chrome works with NVIDIA graphics.

Review URL: https://chromiumcodereview.appspot.com/14271005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194793 0039d316-1c4b-4281-b951-d872f2087c98
parent bb72e614
...@@ -54,7 +54,12 @@ const int kGpuTimeout = 10000; ...@@ -54,7 +54,12 @@ const int kGpuTimeout = 10000;
namespace content { namespace content {
namespace { namespace {
void WarmUpSandbox(const GPUInfo&, bool); void WarmUpSandbox();
#if defined(OS_LINUX)
bool StartSandboxLinux(const GPUInfo&, GpuWatchdogThread*, bool);
#elif defined(OS_WIN)
bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo*);
#endif
} }
// Main function for starting the Gpu process. // Main function for starting the Gpu process.
...@@ -170,12 +175,26 @@ int GpuMain(const MainFunctionParams& parameters) { ...@@ -170,12 +175,26 @@ int GpuMain(const MainFunctionParams& parameters) {
command_line.GetSwitchValueASCII(switches::kGpuDriverVersion); command_line.GetSwitchValueASCII(switches::kGpuDriverVersion);
GetContentClient()->SetGpuInfo(gpu_info); GetContentClient()->SetGpuInfo(gpu_info);
// We need to track that information for the WarmUpSandbox function. // Warm up resources that don't need access to GPUInfo.
WarmUpSandbox();
#if defined(OS_LINUX)
bool initialized_sandbox = false;
bool initialized_gl_context = false; bool initialized_gl_context = false;
bool should_initialize_gl_context = false;
#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
// On Chrome OS ARM, GPU driver userspace creates threads when initializing
// a GL context, so start the sandbox early.
gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get(),
should_initialize_gl_context);
initialized_sandbox = true;
#endif
#endif // defined(OS_LINUX)
// Load and initialize the GL implementation and locate the GL entry points. // Load and initialize the GL implementation and locate the GL entry points.
if (gfx::GLSurface::InitializeOneOff()) { if (gfx::GLSurface::InitializeOneOff()) {
// We need to collect GL strings (VENDOR, RENDERER) for blacklisting // We need to collect GL strings (VENDOR, RENDERER) for blacklisting
// purpose. However, on Mac we don't actually use them. As documented in // purposes. However, on Mac we don't actually use them. As documented in
// crbug.com/222934, due to some driver issues, glGetString could take // crbug.com/222934, due to some driver issues, glGetString could take
// multiple seconds to finish, which in turn cause the GPU process to crash. // multiple seconds to finish, which in turn cause the GPU process to crash.
// By skipping the following code on Mac, we don't really lose anything, // By skipping the following code on Mac, we don't really lose anything,
...@@ -186,10 +205,9 @@ int GpuMain(const MainFunctionParams& parameters) { ...@@ -186,10 +205,9 @@ int GpuMain(const MainFunctionParams& parameters) {
VLOG(1) << "gpu_info_collector::CollectGraphicsInfo failed"; VLOG(1) << "gpu_info_collector::CollectGraphicsInfo failed";
GetContentClient()->SetGpuInfo(gpu_info); GetContentClient()->SetGpuInfo(gpu_info);
// We know that CollectGraphicsInfo will initialize a GLContext. #if defined(OS_LINUX)
initialized_gl_context = true; initialized_gl_context = true;
#if !defined(OS_CHROMEOS)
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA if (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA
gpu_info.driver_vendor == "NVIDIA") { gpu_info.driver_vendor == "NVIDIA") {
base::ThreadRestrictions::AssertIOAllowed(); base::ThreadRestrictions::AssertIOAllowed();
...@@ -199,8 +217,9 @@ int GpuMain(const MainFunctionParams& parameters) { ...@@ -199,8 +217,9 @@ int GpuMain(const MainFunctionParams& parameters) {
dead_on_arrival = true; dead_on_arrival = true;
} }
} }
#endif // OS_CHROMEOS #endif // !defined(OS_CHROMEOS)
#endif // OS_MACOSX #endif // defined(OS_LINUX)
#endif // !defined(OS_MACOSX)
} else { } else {
VLOG(1) << "gfx::GLSurface::InitializeOneOff failed"; VLOG(1) << "gfx::GLSurface::InitializeOneOff failed";
gpu_info.gpu_accessible = false; gpu_info.gpu_accessible = false;
...@@ -222,47 +241,15 @@ int GpuMain(const MainFunctionParams& parameters) { ...@@ -222,47 +241,15 @@ int GpuMain(const MainFunctionParams& parameters) {
watchdog_thread = NULL; watchdog_thread = NULL;
} }
{
const bool should_initialize_gl_context = !initialized_gl_context &&
!dead_on_arrival;
// Warm up the current process before enabling the sandbox.
WarmUpSandbox(gpu_info, should_initialize_gl_context);
}
#if defined(OS_LINUX) #if defined(OS_LINUX)
{ should_initialize_gl_context = !initialized_gl_context &&
TRACE_EVENT0("gpu", "Initialize sandbox"); !dead_on_arrival;
bool do_init_sandbox = true;
if (!initialized_sandbox)
#if defined(OS_CHROMEOS) && defined(NDEBUG) gpu_info.sandboxed = StartSandboxLinux(gpu_info, watchdog_thread.get(),
// On Chrome OS and when not on a debug build, initialize should_initialize_gl_context);
// the GPU process' sandbox only for Intel GPUs. #elif defined(OS_WIN)
do_init_sandbox = gpu_info.gpu.vendor_id == 0x8086; // Intel GPU. gpu_info.sandboxed = StartSandboxWindows(parameters.sandbox_info);
#endif
if (do_init_sandbox) {
if (watchdog_thread)
watchdog_thread->Stop();
gpu_info.sandboxed = LinuxSandbox::InitializeSandbox();
if (watchdog_thread)
watchdog_thread->Start();
}
}
#endif
#if defined(OS_WIN)
{
TRACE_EVENT0("gpu", "Lower token");
// For windows, if the target_services interface is not zero, the process
// is sandboxed and we must call LowerToken() before rendering untrusted
// content.
sandbox::TargetServices* target_services =
parameters.sandbox_info->target_services;
if (target_services) {
target_services->LowerToken();
gpu_info.sandboxed = true;
}
}
#endif #endif
GpuProcess gpu_process; GpuProcess gpu_process;
...@@ -315,8 +302,7 @@ void CreateDummyGlContext() { ...@@ -315,8 +302,7 @@ void CreateDummyGlContext() {
} }
#endif #endif
void WarmUpSandbox(const GPUInfo& gpu_info, void WarmUpSandbox() {
bool should_initialize_gl_context) {
{ {
TRACE_EVENT0("gpu", "Warm up rand"); TRACE_EVENT0("gpu", "Warm up rand");
// Warm up the random subsystem, which needs to be done pre-sandbox on all // Warm up the random subsystem, which needs to be done pre-sandbox on all
...@@ -342,17 +328,6 @@ void WarmUpSandbox(const GPUInfo& gpu_info, ...@@ -342,17 +328,6 @@ void WarmUpSandbox(const GPUInfo& gpu_info,
VaapiVideoDecodeAccelerator::PreSandboxInitialization(); VaapiVideoDecodeAccelerator::PreSandboxInitialization();
#endif #endif
#if defined(OS_LINUX)
// We special case Optimus since the vendor_id we see may not be Nvidia.
bool uses_nvidia_driver = (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA.
gpu_info.driver_vendor == "NVIDIA") ||
gpu_info.optimus;
if (uses_nvidia_driver && should_initialize_gl_context) {
// We need this on Nvidia to pre-open /dev/nvidiactl and /dev/nvidia0.
CreateDummyGlContext();
}
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
{ {
TRACE_EVENT0("gpu", "Preload setupapi.dll"); TRACE_EVENT0("gpu", "Preload setupapi.dll");
...@@ -368,6 +343,57 @@ void WarmUpSandbox(const GPUInfo& gpu_info, ...@@ -368,6 +343,57 @@ void WarmUpSandbox(const GPUInfo& gpu_info,
#endif #endif
} }
#if defined(OS_LINUX)
void WarmUpSandboxNvidia(const GPUInfo& gpu_info,
bool should_initialize_gl_context) {
// We special case Optimus since the vendor_id we see may not be Nvidia.
bool uses_nvidia_driver = (gpu_info.gpu.vendor_id == 0x10de && // NVIDIA.
gpu_info.driver_vendor == "NVIDIA") ||
gpu_info.optimus;
if (uses_nvidia_driver && should_initialize_gl_context) {
// We need this on Nvidia to pre-open /dev/nvidiactl and /dev/nvidia0.
CreateDummyGlContext();
}
}
bool StartSandboxLinux(const GPUInfo& gpu_info,
GpuWatchdogThread* watchdog_thread,
bool should_initialize_gl_context) {
TRACE_EVENT0("gpu", "Initialize sandbox");
bool res = false;
WarmUpSandboxNvidia(gpu_info, should_initialize_gl_context);
if (watchdog_thread)
watchdog_thread->Stop();
// LinuxSandbox::InitializeSandbox() must always be called
// with only one thread.
res = LinuxSandbox::InitializeSandbox();
if (watchdog_thread)
watchdog_thread->Start();
return res;
}
#endif // defined(OS_LINUX)
#if defined(OS_WIN)
bool StartSandboxWindows(const sandbox::SandboxInterfaceInfo* sandbox_info) {
TRACE_EVENT0("gpu", "Lower token");
// For Windows, if the target_services interface is not zero, the process
// is sandboxed and we must call LowerToken() before rendering untrusted
// content.
sandbox::TargetServices* target_services = sandbox_info->target_services;
if (target_services) {
target_services->LowerToken();
return true;
}
return false;
}
#endif // defined(OS_WIN)
} // namespace. } // namespace.
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment