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 3 // found in the LICENSE file. 4 5 #include "content/browser/browser_child_process_host_impl.h" 6 7 #include "base/base_switches.h" 8 #include "base/bind.h" 9 #include "base/command_line.h" 10 #include "base/files/file_path.h" 11 #include "base/lazy_instance.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/path_service.h" 15 #include "base/stl_util.h" 16 #include "base/strings/string_util.h" 17 #include "base/synchronization/waitable_event.h" 18 #include "content/browser/histogram_message_filter.h" 19 #include "content/browser/loader/resource_message_filter.h" 20 #include "content/browser/profiler_message_filter.h" 21 #include "content/browser/tracing/trace_message_filter.h" 22 #include "content/common/child_process_host_impl.h" 23 #include "content/public/browser/browser_child_process_host_delegate.h" 24 #include "content/public/browser/browser_child_process_observer.h" 25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/child_process_data.h" 27 #include "content/public/browser/content_browser_client.h" 28 #include "content/public/common/content_switches.h" 29 #include "content/public/common/process_type.h" 30 #include "content/public/common/result_codes.h" 31 32 #if defined(OS_MACOSX) 33 #include "content/browser/mach_broker_mac.h" 34 #endif 35 36 namespace content { 37 namespace { 38 39 static base::LazyInstance<BrowserChildProcessHostImpl::BrowserChildProcessList> 40 g_child_process_list = LAZY_INSTANCE_INITIALIZER; 41 42 base::LazyInstance<ObserverList<BrowserChildProcessObserver> > 43 g_observers = LAZY_INSTANCE_INITIALIZER; 44 45 void NotifyProcessHostConnected(const ChildProcessData& data) { 46 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(), 47 BrowserChildProcessHostConnected(data)); 48 } 49 50 void NotifyProcessHostDisconnected(const ChildProcessData& data) { 51 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(), 52 BrowserChildProcessHostDisconnected(data)); 53 } 54 55 void NotifyProcessCrashed(const ChildProcessData& data) { 56 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(), 57 BrowserChildProcessCrashed(data)); 58 } 59 60 } // namespace 61 62 BrowserChildProcessHost* BrowserChildProcessHost::Create( 63 int process_type, 64 BrowserChildProcessHostDelegate* delegate) { 65 return new BrowserChildProcessHostImpl(process_type, delegate); 66 } 67 68 #if defined(OS_MACOSX) 69 base::ProcessMetrics::PortProvider* BrowserChildProcessHost::GetPortProvider() { 70 return MachBroker::GetInstance(); 71 } 72 #endif 73 74 // static 75 BrowserChildProcessHostImpl::BrowserChildProcessList* 76 BrowserChildProcessHostImpl::GetIterator() { 77 return g_child_process_list.Pointer(); 78 } 79 80 // static 81 void BrowserChildProcessHostImpl::AddObserver( 82 BrowserChildProcessObserver* observer) { 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 84 g_observers.Get().AddObserver(observer); 85 } 86 87 // static 88 void BrowserChildProcessHostImpl::RemoveObserver( 89 BrowserChildProcessObserver* observer) { 90 // TODO(phajdan.jr): Check thread after fixing http://crbug.com/167126. 91 g_observers.Get().RemoveObserver(observer); 92 } 93 94 BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( 95 int process_type, 96 BrowserChildProcessHostDelegate* delegate) 97 : data_(process_type), 98 delegate_(delegate), 99 power_monitor_message_broadcaster_(this) { 100 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); 101 102 child_process_host_.reset(ChildProcessHost::Create(this)); 103 AddFilter(new TraceMessageFilter); 104 AddFilter(new ProfilerMessageFilter(process_type)); 105 AddFilter(new HistogramMessageFilter); 106 107 g_child_process_list.Get().push_back(this); 108 GetContentClient()->browser()->BrowserChildProcessHostCreated(this); 109 } 110 111 BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() { 112 g_child_process_list.Get().remove(this); 113 114 #if defined(OS_WIN) 115 DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent()); 116 #endif 117 } 118 119 // static 120 void BrowserChildProcessHostImpl::TerminateAll() { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 122 // Make a copy since the BrowserChildProcessHost dtor mutates the original 123 // list. 124 BrowserChildProcessList copy = g_child_process_list.Get(); 125 for (BrowserChildProcessList::iterator it = copy.begin(); 126 it != copy.end(); ++it) { 127 delete (*it)->delegate(); // ~*HostDelegate deletes *HostImpl. 128 } 129 } 130 131 void BrowserChildProcessHostImpl::Launch( 132 #if defined(OS_WIN) 133 SandboxedProcessLauncherDelegate* delegate, 134 #elif defined(OS_POSIX) 135 bool use_zygote, 136 const base::EnvironmentMap& environ, 137 #endif 138 CommandLine* cmd_line) { 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 140 141 GetContentClient()->browser()->AppendExtraCommandLineSwitches( 142 cmd_line, data_.id); 143 144 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 145 static const char* kForwardSwitches[] = { 146 switches::kDisableLogging, 147 switches::kEnableDCHECK, 148 switches::kEnableLogging, 149 switches::kLoggingLevel, 150 switches::kTraceToConsole, 151 switches::kV, 152 switches::kVModule, 153 #if defined(OS_POSIX) 154 switches::kChildCleanExit, 155 #endif 156 #if defined(OS_WIN) 157 switches::kEnableHighResolutionTime, 158 #endif 159 }; 160 cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches, 161 arraysize(kForwardSwitches)); 162 163 child_process_.reset(new ChildProcessLauncher( 164 #if defined(OS_WIN) 165 delegate, 166 #elif defined(OS_POSIX) 167 use_zygote, 168 environ, 169 child_process_host_->TakeClientFileDescriptor(), 170 #endif 171 cmd_line, 172 data_.id, 173 this)); 174 } 175 176 const ChildProcessData& BrowserChildProcessHostImpl::GetData() const { 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 178 return data_; 179 } 180 181 ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const { 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 183 return child_process_host_.get(); 184 } 185 186 base::ProcessHandle BrowserChildProcessHostImpl::GetHandle() const { 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 188 DCHECK(child_process_.get()) 189 << "Requesting a child process handle before launching."; 190 DCHECK(child_process_->GetHandle()) 191 << "Requesting a child process handle before launch has completed OK."; 192 return child_process_->GetHandle(); 193 } 194 195 void BrowserChildProcessHostImpl::SetName(const base::string16& name) { 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 197 data_.name = name; 198 } 199 200 void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) { 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 202 data_.handle = handle; 203 } 204 205 void BrowserChildProcessHostImpl::ForceShutdown() { 206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 207 g_child_process_list.Get().remove(this); 208 child_process_host_->ForceShutdown(); 209 } 210 211 void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) { 212 child_process_->SetProcessBackgrounded(backgrounded); 213 } 214 215 void BrowserChildProcessHostImpl::SetTerminateChildOnShutdown( 216 bool terminate_on_shutdown) { 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 218 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); 219 } 220 221 void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) { 222 child_process_host_->AddFilter(filter->GetFilter()); 223 } 224 225 void BrowserChildProcessHostImpl::NotifyProcessInstanceCreated( 226 const ChildProcessData& data) { 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 228 FOR_EACH_OBSERVER(BrowserChildProcessObserver, g_observers.Get(), 229 BrowserChildProcessInstanceCreated(data)); 230 } 231 232 base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus( 233 bool known_dead, int* exit_code) { 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 235 if (!child_process_) // If the delegate doesn't use Launch() helper. 236 return base::GetTerminationStatus(data_.handle, exit_code); 237 return child_process_->GetChildTerminationStatus(known_dead, 238 exit_code); 239 } 240 241 bool BrowserChildProcessHostImpl::OnMessageReceived( 242 const IPC::Message& message) { 243 return delegate_->OnMessageReceived(message); 244 } 245 246 void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) { 247 #if defined(OS_WIN) 248 // From this point onward, the exit of the child process is detected by an 249 // error on the IPC channel. 250 DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent()); 251 early_exit_watcher_.StopWatching(); 252 #endif 253 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 255 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 256 base::Bind(&NotifyProcessHostConnected, data_)); 257 258 delegate_->OnChannelConnected(peer_pid); 259 } 260 261 void BrowserChildProcessHostImpl::OnChannelError() { 262 delegate_->OnChannelError(); 263 } 264 265 bool BrowserChildProcessHostImpl::CanShutdown() { 266 return delegate_->CanShutdown(); 267 } 268 269 void BrowserChildProcessHostImpl::OnChildDisconnected() { 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 271 if (child_process_.get() || data_.handle) { 272 DCHECK(data_.handle != base::kNullProcessHandle); 273 int exit_code; 274 base::TerminationStatus status = GetTerminationStatus( 275 true /* known_dead */, &exit_code); 276 switch (status) { 277 case base::TERMINATION_STATUS_PROCESS_CRASHED: 278 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { 279 delegate_->OnProcessCrashed(exit_code); 280 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 281 base::Bind(&NotifyProcessCrashed, data_)); 282 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2", 283 data_.process_type, 284 PROCESS_TYPE_MAX); 285 break; 286 } 287 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { 288 delegate_->OnProcessCrashed(exit_code); 289 // Report that this child process was killed. 290 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2", 291 data_.process_type, 292 PROCESS_TYPE_MAX); 293 break; 294 } 295 case base::TERMINATION_STATUS_STILL_RUNNING: { 296 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive2", 297 data_.process_type, 298 PROCESS_TYPE_MAX); 299 } 300 default: 301 break; 302 } 303 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2", 304 data_.process_type, 305 PROCESS_TYPE_MAX); 306 } 307 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 308 base::Bind(&NotifyProcessHostDisconnected, data_)); 309 delete delegate_; // Will delete us 310 } 311 312 bool BrowserChildProcessHostImpl::Send(IPC::Message* message) { 313 return child_process_host_->Send(message); 314 } 315 316 void BrowserChildProcessHostImpl::OnProcessLaunched() { 317 base::ProcessHandle handle = child_process_->GetHandle(); 318 if (!handle) { 319 delete delegate_; // Will delete us 320 return; 321 } 322 323 #if defined(OS_WIN) 324 // Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the 325 // child process exits. This watcher is stopped once the IPC channel is 326 // connected and the exit of the child process is detecter by an error on the 327 // IPC channel thereafter. 328 DCHECK(!early_exit_watcher_.GetWatchedEvent()); 329 early_exit_watcher_.StartWatching( 330 new base::WaitableEvent(handle), 331 base::Bind(&BrowserChildProcessHostImpl::OnProcessExitedEarly, 332 base::Unretained(this))); 333 #endif 334 335 data_.handle = handle; 336 delegate_->OnProcessLaunched(); 337 } 338 339 #if defined(OS_WIN) 340 341 void BrowserChildProcessHostImpl::DeleteProcessWaitableEvent( 342 base::WaitableEvent* event) { 343 if (!event) 344 return; 345 346 // The WaitableEvent does not own the process handle so ensure it does not 347 // close it. 348 event->Release(); 349 350 delete event; 351 } 352 353 void BrowserChildProcessHostImpl::OnProcessExitedEarly( 354 base::WaitableEvent* event) { 355 DeleteProcessWaitableEvent(event); 356 OnChildDisconnected(); 357 } 358 359 #endif 360 361 } // namespace content 362