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/child_process_launcher.h" 6 7 #include <utility> // For std::pair. 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/file_util.h" 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/metrics/histogram.h" 15 #include "base/process/process.h" 16 #include "base/synchronization/lock.h" 17 #include "base/threading/thread.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/content_browser_client.h" 20 #include "content/public/common/content_descriptors.h" 21 #include "content/public/common/content_switches.h" 22 #include "content/public/common/result_codes.h" 23 24 #if defined(OS_WIN) 25 #include "base/files/file_path.h" 26 #include "content/common/sandbox_win.h" 27 #include "content/public/common/sandbox_init.h" 28 #include "content/public/common/sandboxed_process_launcher_delegate.h" 29 #elif defined(OS_MACOSX) 30 #include "content/browser/mach_broker_mac.h" 31 #elif defined(OS_ANDROID) 32 #include "base/android/jni_android.h" 33 #include "content/browser/android/child_process_launcher_android.h" 34 #elif defined(OS_POSIX) 35 #include "base/memory/singleton.h" 36 #include "content/browser/renderer_host/render_sandbox_host_linux.h" 37 #include "content/browser/zygote_host/zygote_host_impl_linux.h" 38 #endif 39 40 #if defined(OS_POSIX) 41 #include "base/posix/global_descriptors.h" 42 #endif 43 44 namespace content { 45 46 // Having the functionality of ChildProcessLauncher be in an internal 47 // ref counted object allows us to automatically terminate the process when the 48 // parent class destructs, while still holding on to state that we need. 49 class ChildProcessLauncher::Context 50 : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> { 51 public: 52 Context() 53 : client_(NULL), 54 client_thread_id_(BrowserThread::UI), 55 termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION), 56 exit_code_(RESULT_CODE_NORMAL_EXIT), 57 starting_(true) 58 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 59 , zygote_(false) 60 #endif 61 { 62 #if defined(OS_POSIX) 63 terminate_child_on_shutdown_ = !CommandLine::ForCurrentProcess()-> 64 HasSwitch(switches::kChildCleanExit); 65 #else 66 terminate_child_on_shutdown_ = true; 67 #endif 68 } 69 70 void Launch( 71 #if defined(OS_WIN) 72 SandboxedProcessLauncherDelegate* delegate, 73 #elif defined(OS_ANDROID) 74 int ipcfd, 75 #elif defined(OS_POSIX) 76 bool use_zygote, 77 const base::EnvironmentVector& environ, 78 int ipcfd, 79 #endif 80 CommandLine* cmd_line, 81 int child_process_id, 82 Client* client) { 83 client_ = client; 84 85 CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); 86 87 #if defined(OS_ANDROID) 88 // We need to close the client end of the IPC channel to reliably detect 89 // child termination. We will close this fd after we create the child 90 // process which is asynchronous on Android. 91 ipcfd_ = ipcfd; 92 #endif 93 BrowserThread::PostTask( 94 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 95 base::Bind( 96 &Context::LaunchInternal, 97 make_scoped_refptr(this), 98 client_thread_id_, 99 child_process_id, 100 #if defined(OS_WIN) 101 delegate, 102 #elif defined(OS_ANDROID) 103 ipcfd, 104 #elif defined(OS_POSIX) 105 use_zygote, 106 environ, 107 ipcfd, 108 #endif 109 cmd_line)); 110 } 111 112 #if defined(OS_ANDROID) 113 static void OnChildProcessStarted( 114 // |this_object| is NOT thread safe. Only use it to post a task back. 115 scoped_refptr<Context> this_object, 116 BrowserThread::ID client_thread_id, 117 const base::TimeTicks begin_launch_time, 118 base::ProcessHandle handle) { 119 RecordHistograms(begin_launch_time); 120 if (BrowserThread::CurrentlyOn(client_thread_id)) { 121 // This is always invoked on the UI thread which is commonly the 122 // |client_thread_id| so we can shortcut one PostTask. 123 this_object->Notify(handle); 124 } else { 125 BrowserThread::PostTask( 126 client_thread_id, FROM_HERE, 127 base::Bind( 128 &ChildProcessLauncher::Context::Notify, 129 this_object, 130 handle)); 131 } 132 } 133 #endif 134 135 void ResetClient() { 136 // No need for locking as this function gets called on the same thread that 137 // client_ would be used. 138 CHECK(BrowserThread::CurrentlyOn(client_thread_id_)); 139 client_ = NULL; 140 } 141 142 void set_terminate_child_on_shutdown(bool terminate_on_shutdown) { 143 terminate_child_on_shutdown_ = terminate_on_shutdown; 144 } 145 146 private: 147 friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; 148 friend class ChildProcessLauncher; 149 150 ~Context() { 151 Terminate(); 152 } 153 154 static void RecordHistograms(const base::TimeTicks begin_launch_time) { 155 base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; 156 if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) { 157 RecordLaunchHistograms(launch_time); 158 } else { 159 BrowserThread::PostTask( 160 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 161 base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms, 162 launch_time)); 163 } 164 } 165 166 static void RecordLaunchHistograms(const base::TimeDelta launch_time) { 167 // Log the launch time, separating out the first one (which will likely be 168 // slower due to the rest of the browser initializing at the same time). 169 static bool done_first_launch = false; 170 if (done_first_launch) { 171 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time); 172 } else { 173 UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time); 174 done_first_launch = true; 175 } 176 } 177 178 static void LaunchInternal( 179 // |this_object| is NOT thread safe. Only use it to post a task back. 180 scoped_refptr<Context> this_object, 181 BrowserThread::ID client_thread_id, 182 int child_process_id, 183 #if defined(OS_WIN) 184 SandboxedProcessLauncherDelegate* delegate, 185 #elif defined(OS_ANDROID) 186 int ipcfd, 187 #elif defined(OS_POSIX) 188 bool use_zygote, 189 const base::EnvironmentVector& env, 190 int ipcfd, 191 #endif 192 CommandLine* cmd_line) { 193 scoped_ptr<CommandLine> cmd_line_deleter(cmd_line); 194 base::TimeTicks begin_launch_time = base::TimeTicks::Now(); 195 196 #if defined(OS_WIN) 197 scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); 198 base::ProcessHandle handle = StartSandboxedProcess(delegate, cmd_line); 199 #elif defined(OS_ANDROID) 200 // Android WebView runs in single process, ensure that we never get here 201 // when running in single process mode. 202 CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); 203 204 std::string process_type = 205 cmd_line->GetSwitchValueASCII(switches::kProcessType); 206 std::vector<FileDescriptorInfo> files_to_register; 207 files_to_register.push_back( 208 FileDescriptorInfo(kPrimaryIPCChannel, 209 base::FileDescriptor(ipcfd, false))); 210 211 GetContentClient()->browser()-> 212 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id, 213 &files_to_register); 214 215 StartChildProcess(cmd_line->argv(), files_to_register, 216 base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted, 217 this_object, client_thread_id, begin_launch_time)); 218 219 #elif defined(OS_POSIX) 220 base::ProcessHandle handle = base::kNullProcessHandle; 221 // We need to close the client end of the IPC channel to reliably detect 222 // child termination. 223 file_util::ScopedFD ipcfd_closer(&ipcfd); 224 225 std::string process_type = 226 cmd_line->GetSwitchValueASCII(switches::kProcessType); 227 std::vector<FileDescriptorInfo> files_to_register; 228 files_to_register.push_back( 229 FileDescriptorInfo(kPrimaryIPCChannel, 230 base::FileDescriptor(ipcfd, false))); 231 232 #if !defined(OS_MACOSX) 233 GetContentClient()->browser()-> 234 GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id, 235 &files_to_register); 236 if (use_zygote) { 237 handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(), 238 files_to_register, 239 process_type); 240 } else 241 // Fall through to the normal posix case below when we're not zygoting. 242 #endif // !defined(OS_MACOSX) 243 { 244 // Convert FD mapping to FileHandleMappingVector 245 base::FileHandleMappingVector fds_to_map; 246 for (size_t i = 0; i < files_to_register.size(); ++i) { 247 fds_to_map.push_back(std::make_pair( 248 files_to_register[i].fd.fd, 249 files_to_register[i].id + 250 base::GlobalDescriptors::kBaseDescriptor)); 251 } 252 253 #if !defined(OS_MACOSX) 254 if (process_type == switches::kRendererProcess) { 255 const int sandbox_fd = 256 RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); 257 fds_to_map.push_back(std::make_pair( 258 sandbox_fd, 259 kSandboxIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); 260 } 261 #endif // defined(OS_MACOSX) 262 263 // Actually launch the app. 264 base::LaunchOptions options; 265 options.environ = &env; 266 options.fds_to_remap = &fds_to_map; 267 268 #if defined(OS_MACOSX) 269 // Hold the MachBroker lock for the duration of LaunchProcess. The child 270 // will send its task port to the parent almost immediately after startup. 271 // The Mach message will be delivered to the parent, but updating the 272 // record of the launch will wait until after the placeholder PID is 273 // inserted below. This ensures that while the child process may send its 274 // port to the parent prior to the parent leaving LaunchProcess, the 275 // order in which the record in MachBroker is updated is correct. 276 MachBroker* broker = MachBroker::GetInstance(); 277 broker->GetLock().Acquire(); 278 279 // Make sure the MachBroker is running, and inform it to expect a 280 // check-in from the new process. 281 broker->EnsureRunning(); 282 #endif // defined(OS_MACOSX) 283 284 bool launched = base::LaunchProcess(*cmd_line, options, &handle); 285 286 #if defined(OS_MACOSX) 287 if (launched) 288 broker->AddPlaceholderForPid(handle); 289 290 // After updating the broker, release the lock and let the child's 291 // messasge be processed on the broker's thread. 292 broker->GetLock().Release(); 293 #endif // defined(OS_MACOSX) 294 295 if (!launched) 296 handle = base::kNullProcessHandle; 297 } 298 #endif // else defined(OS_POSIX) 299 #if !defined(OS_ANDROID) 300 if (handle) 301 RecordHistograms(begin_launch_time); 302 BrowserThread::PostTask( 303 client_thread_id, FROM_HERE, 304 base::Bind( 305 &Context::Notify, 306 this_object.get(), 307 #if defined(OS_POSIX) && !defined(OS_MACOSX) 308 use_zygote, 309 #endif 310 handle)); 311 #endif // !defined(OS_ANDROID) 312 } 313 314 void Notify( 315 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 316 bool zygote, 317 #endif 318 base::ProcessHandle handle) { 319 #if defined(OS_ANDROID) 320 // Finally close the ipcfd 321 file_util::ScopedFD ipcfd_closer(&ipcfd_); 322 #endif 323 starting_ = false; 324 process_.set_handle(handle); 325 if (!handle) 326 LOG(ERROR) << "Failed to launch child process"; 327 328 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 329 zygote_ = zygote; 330 #endif 331 if (client_) { 332 client_->OnProcessLaunched(); 333 } else { 334 Terminate(); 335 } 336 } 337 338 void Terminate() { 339 if (!process_.handle()) 340 return; 341 342 if (!terminate_child_on_shutdown_) 343 return; 344 345 // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So 346 // don't this on the UI/IO threads. 347 BrowserThread::PostTask( 348 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 349 base::Bind( 350 &Context::TerminateInternal, 351 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 352 zygote_, 353 #endif 354 process_.handle())); 355 process_.set_handle(base::kNullProcessHandle); 356 } 357 358 static void SetProcessBackgrounded(base::ProcessHandle handle, 359 bool background) { 360 base::Process process(handle); 361 process.SetProcessBackgrounded(background); 362 } 363 364 static void TerminateInternal( 365 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 366 bool zygote, 367 #endif 368 base::ProcessHandle handle) { 369 #if defined(OS_ANDROID) 370 LOG(INFO) << "ChromeProcess: Stopping process with handle " << handle; 371 StopChildProcess(handle); 372 #else 373 base::Process process(handle); 374 // Client has gone away, so just kill the process. Using exit code 0 375 // means that UMA won't treat this as a crash. 376 process.Terminate(RESULT_CODE_NORMAL_EXIT); 377 // On POSIX, we must additionally reap the child. 378 #if defined(OS_POSIX) 379 #if !defined(OS_MACOSX) 380 if (zygote) { 381 // If the renderer was created via a zygote, we have to proxy the reaping 382 // through the zygote process. 383 ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle); 384 } else 385 #endif // !OS_MACOSX 386 { 387 base::EnsureProcessTerminated(handle); 388 } 389 #endif // OS_POSIX 390 process.Close(); 391 #endif // defined(OS_ANDROID) 392 } 393 394 Client* client_; 395 BrowserThread::ID client_thread_id_; 396 base::Process process_; 397 base::TerminationStatus termination_status_; 398 int exit_code_; 399 bool starting_; 400 // Controls whether the child process should be terminated on browser 401 // shutdown. Default behavior is to terminate the child. 402 bool terminate_child_on_shutdown_; 403 #if defined(OS_ANDROID) 404 // The fd to close after creating the process. 405 int ipcfd_; 406 #elif defined(OS_POSIX) && !defined(OS_MACOSX) 407 bool zygote_; 408 #endif 409 }; 410 411 412 ChildProcessLauncher::ChildProcessLauncher( 413 #if defined(OS_WIN) 414 SandboxedProcessLauncherDelegate* delegate, 415 #elif defined(OS_POSIX) 416 bool use_zygote, 417 const base::EnvironmentVector& environ, 418 int ipcfd, 419 #endif 420 CommandLine* cmd_line, 421 int child_process_id, 422 Client* client) { 423 context_ = new Context(); 424 context_->Launch( 425 #if defined(OS_WIN) 426 delegate, 427 #elif defined(OS_ANDROID) 428 ipcfd, 429 #elif defined(OS_POSIX) 430 use_zygote, 431 environ, 432 ipcfd, 433 #endif 434 cmd_line, 435 child_process_id, 436 client); 437 } 438 439 ChildProcessLauncher::~ChildProcessLauncher() { 440 context_->ResetClient(); 441 } 442 443 bool ChildProcessLauncher::IsStarting() { 444 return context_->starting_; 445 } 446 447 base::ProcessHandle ChildProcessLauncher::GetHandle() { 448 DCHECK(!context_->starting_); 449 return context_->process_.handle(); 450 } 451 452 base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( 453 bool known_dead, 454 int* exit_code) { 455 base::ProcessHandle handle = context_->process_.handle(); 456 if (handle == base::kNullProcessHandle) { 457 // Process is already gone, so return the cached termination status. 458 if (exit_code) 459 *exit_code = context_->exit_code_; 460 return context_->termination_status_; 461 } 462 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 463 if (context_->zygote_) { 464 context_->termination_status_ = ZygoteHostImpl::GetInstance()-> 465 GetTerminationStatus(handle, known_dead, &context_->exit_code_); 466 } else 467 #endif 468 { 469 context_->termination_status_ = 470 base::GetTerminationStatus(handle, &context_->exit_code_); 471 } 472 473 if (exit_code) 474 *exit_code = context_->exit_code_; 475 476 // POSIX: If the process crashed, then the kernel closed the socket 477 // for it and so the child has already died by the time we get 478 // here. Since GetTerminationStatus called waitpid with WNOHANG, 479 // it'll reap the process. However, if GetTerminationStatus didn't 480 // reap the child (because it was still running), we'll need to 481 // Terminate via ProcessWatcher. So we can't close the handle here. 482 if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) 483 context_->process_.Close(); 484 485 return context_->termination_status_; 486 } 487 488 void ChildProcessLauncher::SetProcessBackgrounded(bool background) { 489 BrowserThread::PostTask( 490 BrowserThread::PROCESS_LAUNCHER, FROM_HERE, 491 base::Bind( 492 &ChildProcessLauncher::Context::SetProcessBackgrounded, 493 GetHandle(), background)); 494 } 495 496 void ChildProcessLauncher::SetTerminateChildOnShutdown( 497 bool terminate_on_shutdown) { 498 if (context_.get()) 499 context_->set_terminate_child_on_shutdown(terminate_on_shutdown); 500 } 501 502 } // namespace content 503