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