| 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 |