| 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 "content/browser/gpu/gpu_process_host.h" | 5 #include "content/browser/gpu/gpu_process_host.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <list> | 10 #include <list> |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 } else { | 199 } else { |
| 200 delete message; | 200 delete message; |
| 201 } | 201 } |
| 202 } | 202 } |
| 203 #endif | 203 #endif |
| 204 | 204 |
| 205 // NOTE: changes to this class need to be reviewed by the security team. | 205 // NOTE: changes to this class need to be reviewed by the security team. |
| 206 class GpuSandboxedProcessLauncherDelegate | 206 class GpuSandboxedProcessLauncherDelegate |
| 207 : public SandboxedProcessLauncherDelegate { | 207 : public SandboxedProcessLauncherDelegate { |
| 208 public: | 208 public: |
| 209 explicit GpuSandboxedProcessLauncherDelegate(base::CommandLine* cmd_line) | 209 explicit GpuSandboxedProcessLauncherDelegate( |
| 210 const base::CommandLine& cmd_line) |
| 210 #if defined(OS_WIN) | 211 #if defined(OS_WIN) |
| 211 : cmd_line_(cmd_line) | 212 : cmd_line_(cmd_line) |
| 212 #endif | 213 #endif |
| 213 { | 214 { |
| 214 } | 215 } |
| 215 | 216 |
| 216 ~GpuSandboxedProcessLauncherDelegate() override {} | 217 ~GpuSandboxedProcessLauncherDelegate() override {} |
| 217 | 218 |
| 218 #if defined(OS_WIN) | 219 #if defined(OS_WIN) |
| 219 bool ShouldSandbox() override { | 220 bool ShouldSandbox() override { |
| 220 bool sandbox = !cmd_line_->HasSwitch(switches::kDisableGpuSandbox); | 221 bool sandbox = !cmd_line_.HasSwitch(switches::kDisableGpuSandbox); |
| 221 if (!sandbox) { | 222 if (!sandbox) { |
| 222 DVLOG(1) << "GPU sandbox is disabled"; | 223 DVLOG(1) << "GPU sandbox is disabled"; |
| 223 } | 224 } |
| 224 return sandbox; | 225 return sandbox; |
| 225 } | 226 } |
| 226 | 227 |
| 227 bool DisableDefaultPolicy() override { | 228 bool DisableDefaultPolicy() override { |
| 228 return true; | 229 return true; |
| 229 } | 230 } |
| 230 | 231 |
| 231 // For the GPU process we gotten as far as USER_LIMITED. The next level | 232 // For the GPU process we gotten as far as USER_LIMITED. The next level |
| 232 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL | 233 // which is USER_RESTRICTED breaks both the DirectX backend and the OpenGL |
| 233 // backend. Note that the GPU process is connected to the interactive | 234 // backend. Note that the GPU process is connected to the interactive |
| 234 // desktop. | 235 // desktop. |
| 235 bool PreSpawnTarget(sandbox::TargetPolicy* policy) override { | 236 bool PreSpawnTarget(sandbox::TargetPolicy* policy) override { |
| 236 if (base::win::GetVersion() > base::win::VERSION_XP) { | 237 if (base::win::GetVersion() > base::win::VERSION_XP) { |
| 237 if (cmd_line_->GetSwitchValueASCII(switches::kUseGL) == | 238 if (cmd_line_.GetSwitchValueASCII(switches::kUseGL) == |
| 238 gl::kGLImplementationDesktopName) { | 239 gl::kGLImplementationDesktopName) { |
| 239 // Open GL path. | 240 // Open GL path. |
| 240 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, | 241 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, |
| 241 sandbox::USER_LIMITED); | 242 sandbox::USER_LIMITED); |
| 242 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); | 243 SetJobLevel(cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); |
| 243 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); | 244 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); |
| 244 } else { | 245 } else { |
| 245 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, | 246 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, |
| 246 sandbox::USER_LIMITED); | 247 sandbox::USER_LIMITED); |
| 247 | 248 |
| 248 // UI restrictions break when we access Windows from outside our job. | 249 // UI restrictions break when we access Windows from outside our job. |
| 249 // However, we don't want a proxy window in this process because it can | 250 // However, we don't want a proxy window in this process because it can |
| 250 // introduce deadlocks where the renderer blocks on the gpu, which in | 251 // introduce deadlocks where the renderer blocks on the gpu, which in |
| 251 // turn blocks on the browser UI thread. So, instead we forgo a window | 252 // turn blocks on the browser UI thread. So, instead we forgo a window |
| 252 // message pump entirely and just add job restrictions to prevent child | 253 // message pump entirely and just add job restrictions to prevent child |
| 253 // processes. | 254 // processes. |
| 254 SetJobLevel(*cmd_line_, | 255 SetJobLevel(cmd_line_, |
| 255 sandbox::JOB_LIMITED_USER, | 256 sandbox::JOB_LIMITED_USER, |
| 256 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | | 257 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | |
| 257 JOB_OBJECT_UILIMIT_DESKTOP | | 258 JOB_OBJECT_UILIMIT_DESKTOP | |
| 258 JOB_OBJECT_UILIMIT_EXITWINDOWS | | 259 JOB_OBJECT_UILIMIT_EXITWINDOWS | |
| 259 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS, | 260 JOB_OBJECT_UILIMIT_DISPLAYSETTINGS, |
| 260 policy); | 261 policy); |
| 261 | 262 |
| 262 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); | 263 policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); |
| 263 } | 264 } |
| 264 } else { | 265 } else { |
| 265 SetJobLevel(*cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); | 266 SetJobLevel(cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy); |
| 266 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, | 267 policy->SetTokenLevel(sandbox::USER_UNPROTECTED, |
| 267 sandbox::USER_LIMITED); | 268 sandbox::USER_LIMITED); |
| 268 } | 269 } |
| 269 | 270 |
| 270 // Allow the server side of GPU sockets, which are pipes that have | 271 // Allow the server side of GPU sockets, which are pipes that have |
| 271 // the "chrome.gpu" namespace and an arbitrary suffix. | 272 // the "chrome.gpu" namespace and an arbitrary suffix. |
| 272 sandbox::ResultCode result = policy->AddRule( | 273 sandbox::ResultCode result = policy->AddRule( |
| 273 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, | 274 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, |
| 274 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, | 275 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, |
| 275 L"\\\\.\\pipe\\chrome.gpu.*"); | 276 L"\\\\.\\pipe\\chrome.gpu.*"); |
| 276 if (result != sandbox::SBOX_ALL_OK) | 277 if (result != sandbox::SBOX_ALL_OK) |
| 277 return false; | 278 return false; |
| 278 | 279 |
| 279 // Block this DLL even if it is not loaded by the browser process. | 280 // Block this DLL even if it is not loaded by the browser process. |
| 280 policy->AddDllToUnload(L"cmsetac.dll"); | 281 policy->AddDllToUnload(L"cmsetac.dll"); |
| 281 | 282 |
| 282 if (cmd_line_->HasSwitch(switches::kEnableLogging)) { | 283 if (cmd_line_.HasSwitch(switches::kEnableLogging)) { |
| 283 base::string16 log_file_path = logging::GetLogFileFullPath(); | 284 base::string16 log_file_path = logging::GetLogFileFullPath(); |
| 284 if (!log_file_path.empty()) { | 285 if (!log_file_path.empty()) { |
| 285 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, | 286 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, |
| 286 sandbox::TargetPolicy::FILES_ALLOW_ANY, | 287 sandbox::TargetPolicy::FILES_ALLOW_ANY, |
| 287 log_file_path.c_str()); | 288 log_file_path.c_str()); |
| 288 if (result != sandbox::SBOX_ALL_OK) | 289 if (result != sandbox::SBOX_ALL_OK) |
| 289 return false; | 290 return false; |
| 290 } | 291 } |
| 291 } | 292 } |
| 292 | 293 |
| 293 return true; | 294 return true; |
| 294 } | 295 } |
| 295 #endif // OS_WIN | 296 #endif // OS_WIN |
| 296 | 297 |
| 297 SandboxType GetSandboxType() override { | 298 SandboxType GetSandboxType() override { |
| 298 return SANDBOX_TYPE_GPU; | 299 return SANDBOX_TYPE_GPU; |
| 299 } | 300 } |
| 300 | 301 |
| 301 private: | 302 private: |
| 302 #if defined(OS_WIN) | 303 #if defined(OS_WIN) |
| 303 base::CommandLine* cmd_line_; | 304 base::CommandLine cmd_line_; |
| 304 #endif // OS_WIN | 305 #endif // OS_WIN |
| 305 }; | 306 }; |
| 306 | 307 |
| 307 void HostLoadedShader(int host_id, | 308 void HostLoadedShader(int host_id, |
| 308 const std::string& key, | 309 const std::string& key, |
| 309 const std::string& data) { | 310 const std::string& data) { |
| 310 GpuProcessHost* host = GpuProcessHost::FromID(host_id); | 311 GpuProcessHost* host = GpuProcessHost::FromID(host_id); |
| 311 if (host) | 312 if (host) |
| 312 host->LoadedShader(key, data); | 313 host->LoadedShader(key, data); |
| 313 } | 314 } |
| (...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 const base::CommandLine& browser_command_line = | 979 const base::CommandLine& browser_command_line = |
| 979 *base::CommandLine::ForCurrentProcess(); | 980 *base::CommandLine::ForCurrentProcess(); |
| 980 | 981 |
| 981 base::CommandLine::StringType gpu_launcher = | 982 base::CommandLine::StringType gpu_launcher = |
| 982 browser_command_line.GetSwitchValueNative(switches::kGpuLauncher); | 983 browser_command_line.GetSwitchValueNative(switches::kGpuLauncher); |
| 983 | 984 |
| 984 #if defined(OS_ANDROID) | 985 #if defined(OS_ANDROID) |
| 985 // crbug.com/447735. readlink("self/proc/exe") sometimes fails on Android | 986 // crbug.com/447735. readlink("self/proc/exe") sometimes fails on Android |
| 986 // at startup with EACCES. As a workaround ignore this here, since the | 987 // at startup with EACCES. As a workaround ignore this here, since the |
| 987 // executable name is actually not used or useful anyways. | 988 // executable name is actually not used or useful anyways. |
| 988 base::CommandLine* cmd_line = | 989 std::unique_ptr<base::CommandLine> cmd_line = |
| 989 new base::CommandLine(base::CommandLine::NO_PROGRAM); | 990 base::MakeUnique<base::CommandLine>(base::CommandLine::NO_PROGRAM); |
| 990 #else | 991 #else |
| 991 #if defined(OS_LINUX) | 992 #if defined(OS_LINUX) |
| 992 int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : | 993 int child_flags = gpu_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF : |
| 993 ChildProcessHost::CHILD_NORMAL; | 994 ChildProcessHost::CHILD_NORMAL; |
| 994 #else | 995 #else |
| 995 int child_flags = ChildProcessHost::CHILD_NORMAL; | 996 int child_flags = ChildProcessHost::CHILD_NORMAL; |
| 996 #endif | 997 #endif |
| 997 | 998 |
| 998 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags); | 999 base::FilePath exe_path = ChildProcessHost::GetChildPath(child_flags); |
| 999 if (exe_path.empty()) | 1000 if (exe_path.empty()) |
| 1000 return false; | 1001 return false; |
| 1001 | 1002 |
| 1002 base::CommandLine* cmd_line = new base::CommandLine(exe_path); | 1003 std::unique_ptr<base::CommandLine> cmd_line = |
| 1004 base::MakeUnique<base::CommandLine>(exe_path); |
| 1003 #endif | 1005 #endif |
| 1004 | 1006 |
| 1005 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); | 1007 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); |
| 1006 | 1008 |
| 1007 BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line); | 1009 BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line.get()); |
| 1008 | 1010 |
| 1009 #if defined(OS_WIN) | 1011 #if defined(OS_WIN) |
| 1010 cmd_line->AppendArg(switches::kPrefetchArgumentGpu); | 1012 cmd_line->AppendArg(switches::kPrefetchArgumentGpu); |
| 1011 #endif // defined(OS_WIN) | 1013 #endif // defined(OS_WIN) |
| 1012 | 1014 |
| 1013 if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED) | 1015 if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED) |
| 1014 cmd_line->AppendSwitch(switches::kDisableGpuSandbox); | 1016 cmd_line->AppendSwitch(switches::kDisableGpuSandbox); |
| 1015 | 1017 |
| 1016 // TODO(penghuang): Replace all GPU related switches with GpuPreferences. | 1018 // TODO(penghuang): Replace all GPU related switches with GpuPreferences. |
| 1017 // https://crbug.com/590825 | 1019 // https://crbug.com/590825 |
| 1018 // If you want a browser command-line switch passed to the GPU process | 1020 // If you want a browser command-line switch passed to the GPU process |
| 1019 // you need to add it to |kSwitchNames| at the beginning of this file. | 1021 // you need to add it to |kSwitchNames| at the beginning of this file. |
| 1020 cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames, | 1022 cmd_line->CopySwitchesFrom(browser_command_line, kSwitchNames, |
| 1021 arraysize(kSwitchNames)); | 1023 arraysize(kSwitchNames)); |
| 1022 cmd_line->CopySwitchesFrom( | 1024 cmd_line->CopySwitchesFrom( |
| 1023 browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost, | 1025 browser_command_line, switches::kGLSwitchesCopiedFromGpuProcessHost, |
| 1024 switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches); | 1026 switches::kGLSwitchesCopiedFromGpuProcessHostNumSwitches); |
| 1025 | 1027 |
| 1026 GetContentClient()->browser()->AppendExtraCommandLineSwitches( | 1028 GetContentClient()->browser()->AppendExtraCommandLineSwitches( |
| 1027 cmd_line, process_->GetData().id); | 1029 cmd_line.get(), process_->GetData().id); |
| 1028 | 1030 |
| 1029 GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line, | 1031 GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line.get(), |
| 1030 gpu_preferences); | 1032 gpu_preferences); |
| 1031 if (cmd_line->HasSwitch(switches::kUseGL)) { | 1033 if (cmd_line->HasSwitch(switches::kUseGL)) { |
| 1032 swiftshader_rendering_ = | 1034 swiftshader_rendering_ = |
| 1033 (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"); | 1035 (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"); |
| 1034 } | 1036 } |
| 1035 | 1037 |
| 1036 bool current_gpu_type_enabled = | 1038 bool current_gpu_type_enabled = |
| 1037 swiftshader_rendering_ ? gpu_enabled_ : hardware_gpu_enabled_; | 1039 swiftshader_rendering_ ? gpu_enabled_ : hardware_gpu_enabled_; |
| 1038 if (!current_gpu_type_enabled) { | 1040 if (!current_gpu_type_enabled) { |
| 1039 SendOutstandingReplies(); | 1041 SendOutstandingReplies(); |
| 1040 return false; | 1042 return false; |
| 1041 } | 1043 } |
| 1042 | 1044 |
| 1043 UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessSoftwareRendering", | 1045 UMA_HISTOGRAM_BOOLEAN("GPU.GPUProcessSoftwareRendering", |
| 1044 swiftshader_rendering_); | 1046 swiftshader_rendering_); |
| 1045 | 1047 |
| 1046 // If specified, prepend a launcher program to the command line. | 1048 // If specified, prepend a launcher program to the command line. |
| 1047 if (!gpu_launcher.empty()) | 1049 if (!gpu_launcher.empty()) |
| 1048 cmd_line->PrependWrapper(gpu_launcher); | 1050 cmd_line->PrependWrapper(gpu_launcher); |
| 1049 | 1051 |
| 1050 process_->Launch(new GpuSandboxedProcessLauncherDelegate(cmd_line), cmd_line, | 1052 std::unique_ptr<GpuSandboxedProcessLauncherDelegate> delegate = |
| 1051 true); | 1053 base::MakeUnique<GpuSandboxedProcessLauncherDelegate>(*cmd_line); |
| 1054 process_->Launch(std::move(delegate), std::move(cmd_line), true); |
| 1052 process_launched_ = true; | 1055 process_launched_ = true; |
| 1053 | 1056 |
| 1054 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", | 1057 UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents", |
| 1055 LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX); | 1058 LAUNCHED, GPU_PROCESS_LIFETIME_EVENT_MAX); |
| 1056 return true; | 1059 return true; |
| 1057 } | 1060 } |
| 1058 | 1061 |
| 1059 void GpuProcessHost::SendOutstandingReplies() { | 1062 void GpuProcessHost::SendOutstandingReplies() { |
| 1060 valid_ = false; | 1063 valid_ = false; |
| 1061 // First send empty channel handles for all EstablishChannel requests. | 1064 // First send empty channel handles for all EstablishChannel requests. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); | 1197 TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); |
| 1195 ClientIdToShaderCacheMap::iterator iter = | 1198 ClientIdToShaderCacheMap::iterator iter = |
| 1196 client_id_to_shader_cache_.find(client_id); | 1199 client_id_to_shader_cache_.find(client_id); |
| 1197 // If the cache doesn't exist then this is an off the record profile. | 1200 // If the cache doesn't exist then this is an off the record profile. |
| 1198 if (iter == client_id_to_shader_cache_.end()) | 1201 if (iter == client_id_to_shader_cache_.end()) |
| 1199 return; | 1202 return; |
| 1200 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); | 1203 iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); |
| 1201 } | 1204 } |
| 1202 | 1205 |
| 1203 } // namespace content | 1206 } // namespace content |
| OLD | NEW |