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 = | |
Ken Rockot(use gerrit already)
2017/02/09 17:17:28
I don't see this being used? Is the |service_name|
Jay Civelli
2017/02/09 22:08:27
It's a bit confusing, I am setting a local var tha
| |
240 g_process_name_to_service_name.Get(); | |
241 if (service_name_resolver.empty()) { | |
242 // Populate the process name to service name. | |
Ken Rockot(use gerrit already)
2017/02/09 17:17:28
nit: s/Populate/Translate/?
Also maybe add a TODO
Jay Civelli
2017/02/09 22:08:27
Changed to populate map.
| |
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 |