OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/child_process_launcher_helper.h" | 5 #include "content/browser/child_process_launcher_helper.h" |
6 | 6 |
| 7 #include "base/base_paths.h" |
| 8 #include "base/files/file.h" |
| 9 #include "base/lazy_instance.h" |
7 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
| 11 #include "base/path_service.h" |
| 12 #include "base/posix/global_descriptors.h" |
| 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_util.h" |
8 #include "content/browser/child_process_launcher.h" | 15 #include "content/browser/child_process_launcher.h" |
| 16 #include "content/public/common/content_descriptors.h" |
9 #include "content/public/common/content_switches.h" | 17 #include "content/public/common/content_switches.h" |
10 #include "content/public/common/sandboxed_process_launcher_delegate.h" | 18 #include "content/public/common/sandboxed_process_launcher_delegate.h" |
11 #include "mojo/edk/embedder/platform_channel_pair.h" | 19 #include "mojo/edk/embedder/platform_channel_pair.h" |
12 | 20 |
13 namespace content { | 21 namespace content { |
14 namespace internal { | 22 namespace internal { |
15 | 23 |
16 namespace { | 24 namespace { |
17 | 25 |
| 26 base::LazyInstance< |
| 27 std::map<std::string, std::unique_ptr<catalog::RequiredFileMap>>> |
| 28 g_required_files_by_service = LAZY_INSTANCE_INITIALIZER; |
| 29 |
| 30 base::LazyInstance<std::map<std::string, std::string>> |
| 31 g_process_name_to_service_name = LAZY_INSTANCE_INITIALIZER; |
| 32 |
| 33 typedef std::map<base::FilePath, |
| 34 std::pair<base::PlatformFile, base::MemoryMappedFile::Region>> |
| 35 OpenedFileMap; |
| 36 base::LazyInstance<OpenedFileMap> g_opened_files = LAZY_INSTANCE_INITIALIZER; |
| 37 |
18 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { | 38 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
19 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 39 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
20 // Log the launch time, separating out the first one (which will likely be | 40 // Log the launch time, separating out the first one (which will likely be |
21 // slower due to the rest of the browser initializing at the same time). | 41 // slower due to the rest of the browser initializing at the same time). |
22 static bool done_first_launch = false; | 42 static bool done_first_launch = false; |
23 if (done_first_launch) { | 43 if (done_first_launch) { |
24 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); | 44 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); |
25 } else { | 45 } else { |
26 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); | 46 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); |
27 done_first_launch = true; | 47 done_first_launch = true; |
28 } | 48 } |
29 } | 49 } |
30 | 50 |
| 51 base::PlatformFile OpenFileIfNecessary(const base::FilePath& path, |
| 52 base::MemoryMappedFile::Region* region) { |
| 53 const auto& iter = g_opened_files.Get().find(path); |
| 54 if (iter != g_opened_files.Get().end()) { |
| 55 *region = iter->second.second; |
| 56 return iter->second.first; |
| 57 } |
| 58 base::File file = ChildProcessLauncherHelper::OpenFile(path, region); |
| 59 if (!file.IsValid()) { |
| 60 return base::kInvalidPlatformFile; |
| 61 } |
| 62 // g_opened_files becomes the owner of the file descriptor. |
| 63 base::PlatformFile fd = file.TakePlatformFile(); |
| 64 g_opened_files.Get()[path] = std::make_pair(fd, *region); |
| 65 return fd; |
| 66 } |
| 67 |
31 } // namespace | 68 } // namespace |
32 | 69 |
33 ChildProcessLauncherHelper::Process::Process(Process&& other) | 70 ChildProcessLauncherHelper::Process::Process(Process&& other) |
34 : process(std::move(other.process)) | 71 : process(std::move(other.process)) |
35 #if defined(OS_LINUX) | 72 #if defined(OS_LINUX) |
36 , zygote(other.zygote) | 73 , zygote(other.zygote) |
37 #endif | 74 #endif |
38 { | 75 { |
39 } | 76 } |
40 | 77 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 base::Bind(&ChildProcessLauncherHelper::LaunchOnLauncherThread, this)); | 121 base::Bind(&ChildProcessLauncherHelper::LaunchOnLauncherThread, this)); |
85 } | 122 } |
86 | 123 |
87 void ChildProcessLauncherHelper::LaunchOnLauncherThread() { | 124 void ChildProcessLauncherHelper::LaunchOnLauncherThread() { |
88 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); | 125 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
89 | 126 |
90 begin_launch_time_ = base::TimeTicks::Now(); | 127 begin_launch_time_ = base::TimeTicks::Now(); |
91 | 128 |
92 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap(); | 129 std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap(); |
93 | 130 |
| 131 // Also include the files specified in the services' manifests. |
| 132 const auto& service_name_iter = |
| 133 g_process_name_to_service_name.Get().find(GetProcessType()); |
| 134 CHECK(service_name_iter != g_process_name_to_service_name.Get().end()); |
| 135 std::string service_name = service_name_iter->second; |
| 136 const auto& files_iter = g_required_files_by_service.Get().find(service_name); |
| 137 if (files_iter != g_required_files_by_service.Get().end()) { |
| 138 catalog::RequiredFileMap* required_files_map = files_iter->second.get(); |
| 139 base::GlobalDescriptors::Key key = kContentDynamicDescriptorStart; |
| 140 std::string switch_value; |
| 141 for (const auto& key_path_iter : *required_files_map) { |
| 142 base::MemoryMappedFile::Region region; |
| 143 base::PlatformFile file = |
| 144 OpenFileIfNecessary(base::FilePath(key_path_iter.second), ®ion); |
| 145 if (file == base::kInvalidPlatformFile) { |
| 146 LOG(ERROR) << "Ignoring invalid file " << key_path_iter.second; |
| 147 continue; |
| 148 } |
| 149 if (!switch_value.empty()) { |
| 150 switch_value += ","; |
| 151 } |
| 152 switch_value += key_path_iter.first; |
| 153 switch_value += ":"; |
| 154 switch_value += base::IntToString(key); |
| 155 files_to_register->ShareWithRegion(key, file, region); |
| 156 key++; |
| 157 DCHECK(key < kContentDynamicDescriptorMax); |
| 158 } |
| 159 command_line()->AppendSwitchASCII(switches::kSharedFiles, switch_value); |
| 160 } |
| 161 |
94 bool is_synchronous_launch = true; | 162 bool is_synchronous_launch = true; |
95 int launch_result = LAUNCH_RESULT_FAILURE; | 163 int launch_result = LAUNCH_RESULT_FAILURE; |
96 base::LaunchOptions options; | 164 base::LaunchOptions options; |
97 BeforeLaunchOnLauncherThread(*files_to_register, &options); | 165 BeforeLaunchOnLauncherThread(*files_to_register, &options); |
98 | 166 |
99 Process process = LaunchProcessOnLauncherThread(options, | 167 Process process = LaunchProcessOnLauncherThread(options, |
100 std::move(files_to_register), | 168 std::move(files_to_register), |
101 &is_synchronous_launch, | 169 &is_synchronous_launch, |
102 &launch_result); | 170 &launch_result); |
103 | 171 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 return; | 222 return; |
155 } | 223 } |
156 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! | 224 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! |
157 // So don't do this on the UI/IO threads. | 225 // So don't do this on the UI/IO threads. |
158 BrowserThread::PostTask( | 226 BrowserThread::PostTask( |
159 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, | 227 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
160 base::Bind(&ChildProcessLauncherHelper::ForceNormalProcessTerminationSync, | 228 base::Bind(&ChildProcessLauncherHelper::ForceNormalProcessTerminationSync, |
161 base::Passed(&process))); | 229 base::Passed(&process))); |
162 } | 230 } |
163 | 231 |
| 232 // static |
| 233 void ChildProcessLauncherHelper::SetRegisteredFilesForService( |
| 234 const std::string& service_name, |
| 235 std::unique_ptr<catalog::RequiredFileMap> required_files) { |
| 236 if (required_files->empty()) |
| 237 return; |
| 238 |
| 239 std::map<std::string, std::string>& service_name_resolver = |
| 240 g_process_name_to_service_name.Get(); |
| 241 if (service_name_resolver.empty()) { |
| 242 // Populate the process name to service name. |
| 243 // The service names are defined in the JSON manifests, so we don't have a |
| 244 // constant accessible for them. |
| 245 service_name_resolver[switches::kRendererProcess] = "content_renderer"; |
| 246 service_name_resolver[switches::kGpuProcess] = "content_gpu"; |
| 247 service_name_resolver[switches::kPpapiPluginProcess] = "content_plugin"; |
| 248 service_name_resolver[switches::kUtilityProcess] = "content_utility"; |
| 249 } |
| 250 |
| 251 if (!base::StartsWith(service_name, "content", |
| 252 base::CompareCase::INSENSITIVE_ASCII)) { |
| 253 // Not a content child service, ignore. |
| 254 return; |
| 255 } |
| 256 |
| 257 DCHECK(g_required_files_by_service.Get().count(service_name) == 0); |
| 258 g_required_files_by_service.Get()[service_name] = std::move(required_files); |
| 259 } |
| 260 |
164 } // namespace internal | 261 } // namespace internal |
165 } // namespace content | 262 } // namespace content |
OLD | NEW |