OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/child_process_host.h" | 5 #include "chrome/browser/child_process_host.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/histogram.h" | 10 #include "base/histogram.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/mp/mp_messages.h" |
12 #include "base/path_service.h" | 13 #include "base/path_service.h" |
13 #include "base/process_util.h" | 14 #include "base/process_util.h" |
14 #include "base/singleton.h" | 15 #include "base/singleton.h" |
15 #include "base/string_util.h" | 16 #include "base/string_util.h" |
16 #include "base/waitable_event.h" | 17 #include "base/waitable_event.h" |
17 #include "chrome/browser/chrome_thread.h" | 18 #include "chrome/browser/chrome_thread.h" |
18 #include "chrome/common/chrome_constants.h" | 19 #include "chrome/common/chrome_constants.h" |
19 #include "chrome/common/chrome_paths_internal.h" | 20 #include "chrome/common/chrome_paths_internal.h" |
20 #include "chrome/common/chrome_switches.h" | 21 #include "chrome/common/chrome_switches.h" |
21 #include "chrome/common/env_vars.h" | 22 #include "chrome/common/env_vars.h" |
22 #include "chrome/common/notification_service.h" | 23 #include "chrome/common/notification_service.h" |
23 #include "chrome/common/notification_type.h" | 24 #include "chrome/common/notification_type.h" |
24 #include "chrome/common/plugin_messages.h" | |
25 #include "chrome/common/process_watcher.h" | 25 #include "chrome/common/process_watcher.h" |
26 #include "chrome/common/result_codes.h" | 26 #include "chrome/common/result_codes.h" |
27 #include "chrome/installer/util/google_update_settings.h" | 27 #include "chrome/installer/util/google_update_settings.h" |
28 | 28 |
29 #if defined(OS_LINUX) | 29 #if defined(OS_LINUX) |
30 #include "base/linux_util.h" | 30 #include "base/linux_util.h" |
31 #endif // OS_LINUX | 31 #endif // OS_LINUX |
32 | 32 |
33 #if defined(OS_POSIX) | 33 #if defined(OS_POSIX) |
34 // This is defined in chrome/browser/google_update_settings_posix.cc. It's the | 34 // This is defined in chrome/browser/google_update_settings_posix.cc. It's the |
(...skipping 28 matching lines...) Expand all Loading... |
63 NotificationType notification_type_; | 63 NotificationType notification_type_; |
64 ChildProcessInfo info_; | 64 ChildProcessInfo info_; |
65 }; | 65 }; |
66 | 66 |
67 } // namespace | 67 } // namespace |
68 | 68 |
69 | 69 |
70 ChildProcessHost::ChildProcessHost( | 70 ChildProcessHost::ChildProcessHost( |
71 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host) | 71 ProcessType type, ResourceDispatcherHost* resource_dispatcher_host) |
72 : Receiver(type, -1), | 72 : Receiver(type, -1), |
73 ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), | 73 base::MpChildProcessHost(&context_), |
74 resource_dispatcher_host_(resource_dispatcher_host), | 74 resource_dispatcher_host_(resource_dispatcher_host) { |
75 opening_channel_(false) { | |
76 Singleton<ChildProcessList>::get()->push_back(this); | |
77 } | 75 } |
78 | 76 |
79 | 77 |
80 ChildProcessHost::~ChildProcessHost() { | 78 ChildProcessHost::~ChildProcessHost() { |
81 Singleton<ChildProcessList>::get()->remove(this); | |
82 | |
83 if (resource_dispatcher_host_) | 79 if (resource_dispatcher_host_) |
84 resource_dispatcher_host_->CancelRequestsForProcess(id()); | 80 resource_dispatcher_host_->CancelRequestsForProcess(id()); |
85 } | 81 } |
86 | 82 |
87 // static | 83 // static |
88 FilePath ChildProcessHost::GetChildPath(bool allow_self) { | 84 FilePath ChildProcessHost::GetChildPath(bool allow_self) { |
89 FilePath child_path; | 85 FilePath child_path; |
90 | 86 |
91 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( | 87 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( |
92 switches::kBrowserSubprocessPath); | 88 switches::kBrowserSubprocessPath); |
(...skipping 30 matching lines...) Expand all Loading... |
123 "," + | 119 "," + |
124 base::GetLinuxDistro())); | 120 base::GetLinuxDistro())); |
125 } | 121 } |
126 #elif defined(OS_MACOSX) | 122 #elif defined(OS_MACOSX) |
127 if (GoogleUpdateSettings::GetCollectStatsConsent()) | 123 if (GoogleUpdateSettings::GetCollectStatsConsent()) |
128 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter, | 124 command_line->AppendSwitchWithValue(switches::kEnableCrashReporter, |
129 ASCIIToWide(google_update::posix_guid)); | 125 ASCIIToWide(google_update::posix_guid)); |
130 #endif // OS_MACOSX | 126 #endif // OS_MACOSX |
131 } | 127 } |
132 | 128 |
133 void ChildProcessHost::Launch( | 129 bool ChildProcessHost::Send(IPC::Message* msg) { |
134 #if defined(OS_WIN) | 130 return base::MpChildProcessHost::Send(msg); |
135 const FilePath& exposed_dir, | |
136 #elif defined(OS_POSIX) | |
137 bool use_zygote, | |
138 const base::environment_vector& environ, | |
139 #endif | |
140 CommandLine* cmd_line) { | |
141 child_process_.reset(new ChildProcessLauncher( | |
142 #if defined(OS_WIN) | |
143 exposed_dir, | |
144 #elif defined(OS_POSIX) | |
145 use_zygote, | |
146 environ, | |
147 channel_->GetClientFileDescriptor(), | |
148 #endif | |
149 cmd_line, | |
150 &listener_)); | |
151 } | 131 } |
152 | 132 |
153 bool ChildProcessHost::CreateChannel() { | 133 void ChildProcessHost::Notify( |
154 channel_id_ = GenerateRandomChannelID(this); | 134 base::MpChildProcessHost::MpNotificationType type) { |
155 channel_.reset(new IPC::Channel( | 135 NotificationType chrome_type(NotificationType::ALL); |
156 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); | 136 switch (type) { |
157 if (!channel_->Connect()) | 137 case base::MpChildProcessHost::CHILD_INSTANCE_CREATED: |
158 return false; | 138 chrome_type = NotificationType::CHILD_INSTANCE_CREATED; |
159 | 139 break; |
160 opening_channel_ = true; | 140 case base::MpChildProcessHost::CHILD_PROCESS_CRASHED: |
161 | 141 chrome_type = NotificationType::CHILD_PROCESS_CRASHED; |
162 return true; | 142 break; |
| 143 case base::MpChildProcessHost::CHILD_PROCESS_HOST_CONNECTED: |
| 144 chrome_type = NotificationType::CHILD_PROCESS_HOST_CONNECTED; |
| 145 break; |
| 146 case base::MpChildProcessHost::CHILD_PROCESS_HOST_DISCONNECTED: |
| 147 chrome_type = NotificationType::CHILD_PROCESS_HOST_DISCONNECTED; |
| 148 break; |
| 149 default: |
| 150 NOTREACHED(); |
| 151 } |
| 152 ChromeThread::PostTask( |
| 153 ChromeThread::UI, FROM_HERE, |
| 154 new ChildNotificationTask(chrome_type, this)); |
163 } | 155 } |
164 | 156 |
165 void ChildProcessHost::InstanceCreated() { | 157 bool ChildProcessHost::OnDispatchMessageReceived(const IPC::Message& msg, |
166 Notify(NotificationType::CHILD_INSTANCE_CREATED); | 158 bool *msg_is_ok) { |
| 159 return resource_dispatcher_host_->OnMessageReceived(msg, this, msg_is_ok); |
167 } | 160 } |
168 | 161 |
169 bool ChildProcessHost::Send(IPC::Message* msg) { | 162 void ChildProcessHost::OnProcessLaunched() { |
170 if (!channel_.get()) { | 163 set_handle(GetHandle()); |
171 delete msg; | |
172 return false; | |
173 } | |
174 return channel_->Send(msg); | |
175 } | 164 } |
176 | 165 |
177 void ChildProcessHost::Notify(NotificationType type) { | 166 int ChildProcessHost::GetType() { |
178 ChromeThread::PostTask( | 167 return type(); |
179 ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this)); | |
180 } | 168 } |
181 | 169 |
182 bool ChildProcessHost::DidChildCrash() { | |
183 return child_process_->DidProcessCrash(); | |
184 } | |
185 | |
186 void ChildProcessHost::OnChildDied() { | |
187 if (handle() != base::kNullProcessHandle) { | |
188 bool did_crash = DidChildCrash(); | |
189 if (did_crash) { | |
190 OnProcessCrashed(); | |
191 // Report that this child process crashed. | |
192 Notify(NotificationType::CHILD_PROCESS_CRASHED); | |
193 UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", this->type()); | |
194 } | |
195 // Notify in the main loop of the disconnection. | |
196 Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED); | |
197 } | |
198 | |
199 delete this; | |
200 } | |
201 | |
202 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) | |
203 : host_(host) { | |
204 } | |
205 | |
206 void ChildProcessHost::ListenerHook::OnMessageReceived( | |
207 const IPC::Message& msg) { | |
208 #ifdef IPC_MESSAGE_LOG_ENABLED | |
209 IPC::Logging* logger = IPC::Logging::current(); | |
210 if (msg.type() == IPC_LOGGING_ID) { | |
211 logger->OnReceivedLoggingMessage(msg); | |
212 return; | |
213 } | |
214 | |
215 if (logger->Enabled()) | |
216 logger->OnPreDispatchMessage(msg); | |
217 #endif | |
218 | |
219 bool msg_is_ok = true; | |
220 bool handled = false; | |
221 | |
222 if (host_->resource_dispatcher_host_) | |
223 host_->resource_dispatcher_host_->OnMessageReceived( | |
224 msg, host_, &msg_is_ok); | |
225 | |
226 if (!handled) { | |
227 if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) { | |
228 // Must remove the process from the list now, in case it gets used for a | |
229 // new instance before our watcher tells us that the process terminated. | |
230 Singleton<ChildProcessList>::get()->remove(host_); | |
231 if (host_->CanShutdown()) | |
232 host_->Send(new PluginProcessMsg_Shutdown()); | |
233 } else { | |
234 host_->OnMessageReceived(msg); | |
235 } | |
236 } | |
237 | |
238 if (!msg_is_ok) | |
239 base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false); | |
240 | |
241 #ifdef IPC_MESSAGE_LOG_ENABLED | |
242 if (logger->Enabled()) | |
243 logger->OnPostDispatchMessage(msg, host_->channel_id_); | |
244 #endif | |
245 } | |
246 | |
247 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { | |
248 host_->opening_channel_ = false; | |
249 host_->OnChannelConnected(peer_pid); | |
250 | |
251 #if defined(IPC_MESSAGE_LOG_ENABLED) | |
252 bool enabled = IPC::Logging::current()->Enabled(); | |
253 host_->Send(new PluginProcessMsg_SetIPCLoggingEnabled(enabled)); | |
254 #endif | |
255 | |
256 host_->Send(new PluginProcessMsg_AskBeforeShutdown()); | |
257 | |
258 // Notify in the main loop of the connection. | |
259 host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); | |
260 } | |
261 | |
262 void ChildProcessHost::ListenerHook::OnChannelError() { | |
263 host_->opening_channel_ = false; | |
264 host_->OnChannelError(); | |
265 | |
266 // This will delete host_, which will also destroy this! | |
267 host_->OnChildDied(); | |
268 } | |
269 | |
270 void ChildProcessHost::ListenerHook::OnProcessLaunched() { | |
271 if (!host_->child_process_->GetHandle()) { | |
272 delete this; | |
273 return; | |
274 } | |
275 | |
276 host_->set_handle(host_->child_process_->GetHandle()); | |
277 host_->OnProcessLaunched(); | |
278 } | |
279 | |
280 | |
281 ChildProcessHost::Iterator::Iterator() | 170 ChildProcessHost::Iterator::Iterator() |
282 : all_(true), type_(UNKNOWN_PROCESS) { | 171 : all_(true), type_(UNKNOWN_PROCESS) { |
283 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << | 172 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << |
284 "ChildProcessInfo::Iterator must be used on the IO thread."; | 173 "ChildProcessInfo::Iterator must be used on the IO thread."; |
285 iterator_ = Singleton<ChildProcessList>::get()->begin(); | 174 iterator_ = Singleton<ChildProcessList>::get()->begin(); |
286 } | 175 } |
287 | 176 |
288 ChildProcessHost::Iterator::Iterator(ProcessType type) | 177 ChildProcessHost::Iterator::Iterator(ProcessType type) |
289 : all_(false), type_(type) { | 178 : all_(false), type_(type) { |
290 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << | 179 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)) << |
(...skipping 14 matching lines...) Expand all Loading... |
305 | 194 |
306 return *iterator_; | 195 return *iterator_; |
307 } while (true); | 196 } while (true); |
308 | 197 |
309 return NULL; | 198 return NULL; |
310 } | 199 } |
311 | 200 |
312 bool ChildProcessHost::Iterator::Done() { | 201 bool ChildProcessHost::Iterator::Done() { |
313 return iterator_ == Singleton<ChildProcessList>::get()->end(); | 202 return iterator_ == Singleton<ChildProcessList>::get()->end(); |
314 } | 203 } |
315 | |
316 void ChildProcessHost::ForceShutdown() { | |
317 Singleton<ChildProcessList>::get()->remove(this); | |
318 Send(new PluginProcessMsg_Shutdown()); | |
319 } | |
OLD | NEW |