Chromium Code Reviews| Index: content/browser/child_process_launcher.cc |
| diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc |
| index 51f5696d31456265c29fc75933f95628aada588b..434fae7b2315c375647810bec18fdf93bedad9b3 100644 |
| --- a/content/browser/child_process_launcher.cc |
| +++ b/content/browser/child_process_launcher.cc |
| @@ -4,75 +4,23 @@ |
| #include "content/browser/child_process_launcher.h" |
| -#include <memory> |
| -#include <utility> |
| - |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/i18n/icu_util.h" |
| #include "base/logging.h" |
| -#include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/process/launch.h" |
| -#include "base/process/process.h" |
| -#include "base/strings/string_number_conversions.h" |
| -#include "base/synchronization/lock.h" |
| -#include "base/threading/thread.h" |
| #include "build/build_config.h" |
| -#include "content/public/browser/content_browser_client.h" |
| -#include "content/public/common/content_descriptors.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/result_codes.h" |
| #include "content/public/common/sandboxed_process_launcher_delegate.h" |
| -#include "mojo/edk/embedder/embedder.h" |
| -#include "mojo/edk/embedder/named_platform_channel_pair.h" |
| #include "mojo/edk/embedder/platform_channel_pair.h" |
| -#include "mojo/edk/embedder/scoped_platform_handle.h" |
| -#include "ppapi/features/features.h" |
| - |
| -#if defined(OS_WIN) |
| -#include "base/files/file_path.h" |
| -#include "base/win/scoped_handle.h" |
| -#include "base/win/win_util.h" |
| -#include "content/common/sandbox_win.h" |
| -#include "content/public/common/sandbox_init.h" |
| -#include "sandbox/win/src/sandbox_types.h" |
| -#elif defined(OS_MACOSX) |
| -#include "content/browser/bootstrap_sandbox_manager_mac.h" |
| -#include "content/browser/mach_broker_mac.h" |
| -#include "sandbox/mac/bootstrap_sandbox.h" |
| -#include "sandbox/mac/pre_exec_delegate.h" |
| -#elif defined(OS_ANDROID) |
| -#include "base/android/jni_android.h" |
| -#include "content/browser/android/child_process_launcher_android.h" |
| -#elif defined(OS_POSIX) |
| -#include "base/memory/singleton.h" |
| -#include "content/browser/renderer_host/render_sandbox_host_linux.h" |
| -#include "content/browser/zygote_host/zygote_communication_linux.h" |
| -#include "content/browser/zygote_host/zygote_host_impl_linux.h" |
| -#include "content/common/child_process_sandbox_support_impl_linux.h" |
| -#include "content/public/browser/zygote_handle_linux.h" |
| -#endif |
| - |
| -#if defined(OS_POSIX) |
| -#include "base/posix/global_descriptors.h" |
| -#include "content/browser/file_descriptor_info_impl.h" |
| -#include "gin/v8_initializer.h" |
| -#endif |
| namespace content { |
| namespace { |
| -typedef base::Callback<void(ZygoteHandle, |
| -#if defined(OS_ANDROID) |
| - base::ScopedFD, |
| -#endif |
| - base::Process, |
| - int)> |
| - NotifyCallback; |
| - |
| void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
| DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| // Log the launch time, separating out the first one (which will likely be |
| @@ -86,304 +34,11 @@ void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) { |
| } |
| } |
| -#if defined(OS_ANDROID) |
| -// TODO(sievers): Remove this by defining better what happens on what |
| -// thread in the corresponding Java code. |
| -void OnChildProcessStartedAndroid(const NotifyCallback& callback, |
| - BrowserThread::ID client_thread_id, |
| - const base::TimeTicks begin_launch_time, |
| - base::ScopedFD mojo_fd, |
| - base::ProcessHandle handle) { |
| - int launch_result = (handle == base::kNullProcessHandle) |
| - ? LAUNCH_RESULT_FAILURE |
| - : LAUNCH_RESULT_SUCCESS; |
| - // This can be called on the launcher thread or UI thread. |
| - base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time; |
| - BrowserThread::PostTask( |
| - BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| - base::Bind(&RecordHistogramsOnLauncherThread, launch_time)); |
| - |
| - base::Closure callback_on_client_thread( |
| - base::Bind(callback, nullptr, base::Passed(&mojo_fd), |
| - base::Passed(base::Process(handle)), launch_result)); |
| - if (BrowserThread::CurrentlyOn(client_thread_id)) { |
| - callback_on_client_thread.Run(); |
| - } else { |
| - BrowserThread::PostTask( |
| - client_thread_id, FROM_HERE, callback_on_client_thread); |
| - } |
| -} |
| -#endif |
| - |
| -void LaunchOnLauncherThread( |
| - const NotifyCallback& callback, |
| - BrowserThread::ID client_thread_id, |
| - int child_process_id, |
| - std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| - mojo::edk::ScopedPlatformHandle client_handle, |
| - std::unique_ptr<base::CommandLine> cmd_line) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| -#if !defined(OS_ANDROID) |
| - ZygoteHandle zygote = nullptr; |
| - int launch_result = LAUNCH_RESULT_FAILURE; |
| -#endif |
| -#if defined(OS_WIN) |
| - bool launch_elevated = delegate->ShouldLaunchElevated(); |
| -#elif defined(OS_MACOSX) |
| - base::EnvironmentMap env = delegate->GetEnvironment(); |
| -#elif defined(OS_POSIX) && !defined(OS_ANDROID) |
| - base::EnvironmentMap env = delegate->GetEnvironment(); |
| -#endif |
| - base::TimeTicks begin_launch_time = base::TimeTicks::Now(); |
| - |
| - base::Process process; |
| -#if defined(OS_WIN) |
| - if (launch_elevated) { |
| - // When establishing a Mojo connection, the pipe path has already been added |
| - // to the command line. |
| - base::LaunchOptions options; |
| - options.start_hidden = true; |
| - process = base::LaunchElevatedProcess(*cmd_line, options); |
| - } else { |
| - base::HandlesToInheritVector handles; |
| - handles.push_back(client_handle.get().handle); |
| - base::FieldTrialList::AppendFieldTrialHandleIfNeeded(&handles); |
| - cmd_line->AppendSwitchASCII( |
| - mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch, |
| - base::UintToString(base::win::HandleToUint32(handles[0]))); |
| - launch_result = StartSandboxedProcess( |
| - delegate.get(), cmd_line.get(), handles, &process); |
| - } |
| -#elif defined(OS_POSIX) |
| - std::string process_type = |
| - cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| - std::unique_ptr<FileDescriptorInfo> files_to_register( |
| - FileDescriptorInfoImpl::Create()); |
| - |
| - base::ScopedFD mojo_fd(client_handle.release().handle); |
| - DCHECK(mojo_fd.is_valid()); |
| - |
| - int field_trial_handle = base::FieldTrialList::GetFieldTrialHandle(); |
| - if (field_trial_handle != base::kInvalidPlatformFile) |
| - files_to_register->Share(kFieldTrialDescriptor, field_trial_handle); |
| -#if defined(OS_ANDROID) |
| - files_to_register->Share(kMojoIPCChannel, mojo_fd.get()); |
| -#else |
| - files_to_register->Transfer(kMojoIPCChannel, std::move(mojo_fd)); |
| -#endif |
| -#endif |
| - |
| -#if defined(OS_POSIX) && !defined(OS_MACOSX) |
| - GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess( |
| - *cmd_line, child_process_id, files_to_register.get()); |
| -#if defined(V8_USE_EXTERNAL_STARTUP_DATA) |
| - bool snapshot_loaded = false; |
| - base::MemoryMappedFile::Region region; |
| -#if defined(OS_ANDROID) |
| - auto maybe_register = [®ion, &files_to_register](int key, int fd) { |
| - if (fd != -1) |
| - files_to_register->ShareWithRegion(key, fd, region); |
| - }; |
| - maybe_register( |
| - kV8NativesDataDescriptor, |
| - gin::V8Initializer::GetOpenNativesFileForChildProcesses(®ion)); |
| - maybe_register( |
| - kV8SnapshotDataDescriptor32, |
| - gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(®ion, true)); |
| - maybe_register( |
| - kV8SnapshotDataDescriptor64, |
| - gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(®ion, false)); |
| - |
| - snapshot_loaded = true; |
| -#else |
| - base::PlatformFile natives_pf = |
| - gin::V8Initializer::GetOpenNativesFileForChildProcesses(®ion); |
| - DCHECK_GE(natives_pf, 0); |
| - files_to_register->ShareWithRegion( |
| - kV8NativesDataDescriptor, natives_pf, region); |
| - |
| - base::PlatformFile snapshot_pf = |
| - gin::V8Initializer::GetOpenSnapshotFileForChildProcesses(®ion); |
| - // Failure to load the V8 snapshot is not necessarily an error. V8 can start |
| - // up (slower) without the snapshot. |
| - if (snapshot_pf != -1) { |
| - snapshot_loaded = true; |
| - files_to_register->ShareWithRegion( |
| - kV8SnapshotDataDescriptor, snapshot_pf, region); |
| - } |
| -#endif |
| - |
| - if (process_type != switches::kZygoteProcess) { |
| - cmd_line->AppendSwitch(::switches::kV8NativesPassedByFD); |
| - if (snapshot_loaded) { |
| - cmd_line->AppendSwitch(::switches::kV8SnapshotPassedByFD); |
| - } |
| - } |
| -#endif // defined(V8_USE_EXTERNAL_STARTUP_DATA) |
| -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) |
| - |
| -#if defined(OS_ANDROID) |
| -#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE |
| - base::MemoryMappedFile::Region icu_region; |
| - base::PlatformFile icu_pf = base::i18n::GetIcuDataFileHandle(&icu_region); |
| - files_to_register->ShareWithRegion( |
| - kAndroidICUDataDescriptor, icu_pf, icu_region); |
| -#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE |
| - |
| - // Android WebView runs in single process, ensure that we never get here |
| - // when running in single process mode. |
| - CHECK(!cmd_line->HasSwitch(switches::kSingleProcess)); |
| - |
| - StartChildProcess( |
| - cmd_line->argv(), child_process_id, std::move(files_to_register), |
| - base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id, |
| - begin_launch_time, base::Passed(&mojo_fd))); |
| - |
| -#elif defined(OS_POSIX) |
| - // We need to close the client end of the IPC channel to reliably detect |
| - // child termination. |
| - |
| -#if !defined(OS_MACOSX) |
| - ZygoteHandle* zygote_handle = |
| - !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote) |
| - ? delegate->GetZygote() |
| - : nullptr; |
| - // If |zygote_handle| is null, a zygote should not be used. |
| - if (zygote_handle) { |
| - // This code runs on the PROCESS_LAUNCHER thread so race conditions are not |
| - // an issue with the lazy initialization. |
| - if (*zygote_handle == nullptr) { |
| - *zygote_handle = CreateZygote(); |
| - } |
| - zygote = *zygote_handle; |
| - base::ProcessHandle handle = zygote->ForkRequest( |
| - cmd_line->argv(), std::move(files_to_register), process_type); |
| - process = base::Process(handle); |
| - } else |
| - // Fall through to the normal posix case below when we're not zygoting. |
| -#endif // !defined(OS_MACOSX) |
| - { |
| - // Convert FD mapping to FileHandleMappingVector |
| - base::FileHandleMappingVector fds_to_map = |
| - files_to_register->GetMappingWithIDAdjustment( |
| - base::GlobalDescriptors::kBaseDescriptor); |
| - |
| -#if !defined(OS_MACOSX) |
| - if (process_type == switches::kRendererProcess) { |
| - const int sandbox_fd = |
| - RenderSandboxHostLinux::GetInstance()->GetRendererSocket(); |
| - fds_to_map.push_back(std::make_pair( |
| - sandbox_fd, |
| - GetSandboxFD())); |
| - } |
| -#endif // defined(OS_MACOSX) |
| - |
| - // Actually launch the app. |
| - base::LaunchOptions options; |
| - options.environ = env; |
| - options.fds_to_remap = &fds_to_map; |
| - |
| -#if defined(OS_MACOSX) |
| - // Hold the MachBroker lock for the duration of LaunchProcess. The child |
| - // will send its task port to the parent almost immediately after startup. |
| - // The Mach message will be delivered to the parent, but updating the |
| - // record of the launch will wait until after the placeholder PID is |
| - // inserted below. This ensures that while the child process may send its |
| - // port to the parent prior to the parent leaving LaunchProcess, the |
| - // order in which the record in MachBroker is updated is correct. |
| - MachBroker* broker = MachBroker::GetInstance(); |
| - broker->GetLock().Acquire(); |
| - |
| - // Make sure the MachBroker is running, and inform it to expect a |
| - // check-in from the new process. |
| - broker->EnsureRunning(); |
| - |
| - const SandboxType sandbox_type = delegate->GetSandboxType(); |
| - std::unique_ptr<sandbox::PreExecDelegate> pre_exec_delegate; |
| - if (BootstrapSandboxManager::ShouldEnable()) { |
| - BootstrapSandboxManager* sandbox_manager = |
| - BootstrapSandboxManager::GetInstance(); |
| - if (sandbox_manager->EnabledForSandbox(sandbox_type)) { |
| - pre_exec_delegate = sandbox_manager->sandbox()->NewClient(sandbox_type); |
| - } |
| - } |
| - options.pre_exec_delegate = pre_exec_delegate.get(); |
| -#endif // defined(OS_MACOSX) |
| - |
| - process = base::LaunchProcess(*cmd_line, options); |
| - |
| -#if defined(OS_MACOSX) |
| - if (process.IsValid()) { |
| - broker->AddPlaceholderForPid(process.Pid(), child_process_id); |
| - } else { |
| - if (pre_exec_delegate) { |
| - BootstrapSandboxManager::GetInstance()->sandbox()->RevokeToken( |
| - pre_exec_delegate->sandbox_token()); |
| - } |
| - } |
| - |
| - // After updating the broker, release the lock and let the child's |
| - // message be processed on the broker's thread. |
| - broker->GetLock().Release(); |
| -#endif // defined(OS_MACOSX) |
| - } |
| -#endif // else defined(OS_POSIX) |
| -#if !defined(OS_ANDROID) |
| - if (process.IsValid()) { |
| - launch_result = LAUNCH_RESULT_SUCCESS; |
| - RecordHistogramsOnLauncherThread(base::TimeTicks::Now() - |
| - begin_launch_time); |
| - } |
| - BrowserThread::PostTask(client_thread_id, FROM_HERE, |
| - base::Bind(callback, zygote, base::Passed(&process), |
| - launch_result)); |
| -#endif // !defined(OS_ANDROID) |
| -} |
| - |
| -void TerminateOnLauncherThread(ZygoteHandle zygote, base::Process process) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| -#if defined(OS_ANDROID) |
| - VLOG(1) << "ChromeProcess: Stopping process with handle " |
| - << process.Handle(); |
| - StopChildProcess(process.Handle()); |
| -#else |
| - // Client has gone away, so just kill the process. Using exit code 0 |
| - // means that UMA won't treat this as a crash. |
| - process.Terminate(RESULT_CODE_NORMAL_EXIT, false); |
| - // On POSIX, we must additionally reap the child. |
| -#if defined(OS_POSIX) |
| -#if !defined(OS_MACOSX) |
| - if (zygote) { |
| - // If the renderer was created via a zygote, we have to proxy the reaping |
| - // through the zygote process. |
| - zygote->EnsureProcessTerminated(process.Handle()); |
| - } else |
| -#endif // !OS_MACOSX |
| - base::EnsureProcessTerminated(std::move(process)); |
| -#endif // OS_POSIX |
| -#endif // defined(OS_ANDROID) |
| -} |
| - |
| -void SetProcessBackgroundedOnLauncherThread(base::Process process, |
| - bool background) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| - if (process.CanBackgroundProcesses()) { |
| -#if defined(OS_MACOSX) |
| - process.SetProcessBackgrounded(MachBroker::GetInstance(), background); |
| -#else |
| - process.SetProcessBackgrounded(background); |
| -#endif // defined(OS_MACOSX) |
| - } |
| -#if defined(OS_ANDROID) |
| - SetChildProcessInForeground(process.Handle(), !background); |
| -#endif |
| -} |
| - |
| } // namespace |
| ChildProcessLauncher::ChildProcessLauncher( |
| std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| - std::unique_ptr<base::CommandLine> cmd_line, |
| + std::unique_ptr<base::CommandLine> command_line, |
| int child_process_id, |
| Client* client, |
| const std::string& mojo_child_token, |
| @@ -406,95 +61,118 @@ ChildProcessLauncher::ChildProcessLauncher( |
| weak_factory_(this) { |
| DCHECK(CalledOnValidThread()); |
| CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_)); |
| - Launch(std::move(delegate), std::move(cmd_line), child_process_id); |
| + |
| + helper_ = new Helper(child_process_id, client_thread_id_, |
| + std::move(command_line), std::move(delegate), |
| + weak_factory_.GetWeakPtr(), terminate_on_shutdown); |
| + helper_->LaunchOnClientThread(); |
| } |
| ChildProcessLauncher::~ChildProcessLauncher() { |
| DCHECK(CalledOnValidThread()); |
| - if (process_.IsValid() && terminate_child_on_shutdown_) { |
| - // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
| - // don't this on the UI/IO threads. |
| - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| - base::Bind(&TerminateOnLauncherThread, zygote_, |
| - base::Passed(&process_))); |
| - } |
| + if (process_.IsValid() && terminate_child_on_shutdown_) |
| + Terminate(zygote_, std::move(process_)); |
| } |
| -void ChildProcessLauncher::Launch( |
| +ChildProcessLauncher::Helper::Helper( |
|
boliu
2017/01/12 02:00:07
nit: group ChildProcessLauncher methods together a
Jay Civelli
2017/01/12 23:05:40
Done (they were defined in the order they were dec
|
| + int child_process_id, |
| + BrowserThread::ID client_thread_id, |
| + std::unique_ptr<base::CommandLine> command_line, |
| std::unique_ptr<SandboxedProcessLauncherDelegate> delegate, |
| - std::unique_ptr<base::CommandLine> cmd_line, |
| - int child_process_id) { |
| - DCHECK(CalledOnValidThread()); |
| + const base::WeakPtr<ChildProcessLauncher>& child_process_launcher, |
| + bool terminate_on_shutdown) |
| + : child_process_id_(child_process_id), |
| + client_thread_id_(client_thread_id), |
| + command_line_(std::move(command_line)), |
| + delegate_(std::move(delegate)), |
| + child_process_launcher_(child_process_launcher), |
| + terminate_on_shutdown_(terminate_on_shutdown) { |
| +} |
| -#if defined(OS_ANDROID) |
| - // Android only supports renderer, sandboxed utility and gpu. |
| - std::string process_type = |
| - cmd_line->GetSwitchValueASCII(switches::kProcessType); |
| - CHECK(process_type == switches::kGpuProcess || |
| - process_type == switches::kRendererProcess || |
| -#if BUILDFLAG(ENABLE_PLUGINS) |
| - process_type == switches::kPpapiPluginProcess || |
| -#endif |
| - process_type == switches::kUtilityProcess) |
| - << "Unsupported process type: " << process_type; |
| +ChildProcessLauncher::Helper::~Helper() {} |
| - // Non-sandboxed utility or renderer process are currently not supported. |
| - DCHECK(process_type == switches::kGpuProcess || |
| - !cmd_line->HasSwitch(switches::kNoSandbox)); |
| +void ChildProcessLauncher::Helper::LaunchOnClientThread() { |
| + DCHECK_CURRENTLY_ON(client_thread_id_); |
| -#endif |
| - mojo::edk::ScopedPlatformHandle server_handle; |
| - mojo::edk::ScopedPlatformHandle client_handle; |
| -#if defined(OS_WIN) |
| - if (delegate->ShouldLaunchElevated()) { |
| - mojo::edk::NamedPlatformChannelPair named_pair; |
| - server_handle = named_pair.PassServerHandle(); |
| - named_pair.PrepareToPassClientHandleToChildProcess(cmd_line.get()); |
| - } else |
| -#endif |
| - { |
| + BeforeLaunchOnClientThread(); |
| + |
| + mojo_server_handle_ = PrepareMojoPipeHandlesOnClientThread(); |
| + if (!mojo_server_handle_.is_valid()) { |
| mojo::edk::PlatformChannelPair channel_pair; |
| - server_handle = channel_pair.PassServerHandle(); |
| - client_handle = channel_pair.PassClientHandle(); |
| + mojo_server_handle_ = channel_pair.PassServerHandle(); |
| + mojo_client_handle_ = channel_pair.PassClientHandle(); |
| } |
| - NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch, |
| - weak_factory_.GetWeakPtr(), |
| - terminate_child_on_shutdown_, |
| - base::Passed(&server_handle))); |
| + |
| BrowserThread::PostTask( |
| BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| - base::Bind(&LaunchOnLauncherThread, reply_callback, client_thread_id_, |
| - child_process_id, base::Passed(&delegate), |
| - base::Passed(&client_handle), base::Passed(&cmd_line))); |
| + base::Bind(&Helper::LaunchOnLauncherThread, this)); |
| } |
| -void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) { |
| - DCHECK(CalledOnValidThread()); |
| -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| - if (zygote_) { |
| - termination_status_ = zygote_->GetTerminationStatus( |
| - process_.Handle(), known_dead, &exit_code_); |
| - } else if (known_dead) { |
| - termination_status_ = |
| - base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
| - } else { |
| -#elif defined(OS_MACOSX) |
| - if (known_dead) { |
| - termination_status_ = |
| - base::GetKnownDeadTerminationStatus(process_.Handle(), &exit_code_); |
| - } else { |
| -#elif defined(OS_ANDROID) |
| - if (IsChildProcessOomProtected(process_.Handle())) { |
| - termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED; |
| +void ChildProcessLauncher::Helper::LaunchOnLauncherThread() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); |
| + |
| + begin_launch_time_ = base::TimeTicks::Now(); |
| + |
| + std::unique_ptr<FileMappedForLaunch> files_to_register = GetFilesToMap(); |
| + |
| + base::Process process; |
| + ZygoteHandle zygote = nullptr; |
| + bool is_synchronous_launch = true; |
| + int launch_result = LAUNCH_RESULT_FAILURE; |
| + if (ShouldForkAsZygote()) { |
| + zygote = ForkAsZygote(std::move(files_to_register), &process); |
| + launch_result = LAUNCH_RESULT_SUCCESS; |
| } else { |
| -#else |
| - { |
| -#endif |
| - termination_status_ = |
| - base::GetTerminationStatus(process_.Handle(), &exit_code_); |
| + base::LaunchOptions options; |
| + BeforeLaunchOnLauncherThread(*files_to_register, &options); |
| + |
| + process = LaunchProcessOnLauncherThread(options, |
| + files_to_register.get(), |
| + &is_synchronous_launch, |
| + &launch_result); |
| + |
| + AfterLaunchOnLauncherThread(process, options); |
| + } |
| + |
| + if (is_synchronous_launch) { |
| + PostLaunchOnLauncherThread(std::move(process), zygote, launch_result); |
| } |
| } |
| +void ChildProcessLauncher::Helper::PostLaunchOnLauncherThread( |
| + base::Process process, |
| + ZygoteHandle zygote, |
| + int launch_result) { |
| + // Release the client handle now that the process has been started (the pipe |
| + // may not signal when the process dies otherwise and we would not detect the |
| + // child process died). |
| + mojo_client_handle_.reset(); |
| + |
| + if (process.IsValid()) { |
|
boliu
2017/01/12 02:00:07
on android, old code didn't check this to record h
Jay Civelli
2017/01/12 23:05:40
Yes, and that seemed wrong (the other platforms be
|
| + RecordHistogramsOnLauncherThread( |
| + base::TimeTicks::Now() - begin_launch_time_); |
| + } |
| + |
| + BrowserThread::PostTask( |
| + client_thread_id_, FROM_HERE, |
| + base::Bind(&Helper::PostLaunchOnClientThread, |
| + this, base::Passed(&process), zygote, launch_result)); |
| +} |
| + |
| +void ChildProcessLauncher::Helper::PostLaunchOnClientThread( |
| + base::Process process, ZygoteHandle zygote, int error_code) { |
| + if (child_process_launcher_) { |
| + child_process_launcher_->Notify(zygote, std::move(mojo_server_handle_), |
| + std::move(process), error_code); |
| + } else if (process.IsValid() && terminate_on_shutdown_) { |
| + ChildProcessLauncher::Terminate(zygote, std::move(process)); |
| + } |
| +} |
| + |
| +std::string ChildProcessLauncher::Helper::GetProcessType() { |
| + return command_line()->GetSwitchValueASCII(switches::kProcessType); |
| +} |
| + |
| void ChildProcessLauncher::SetProcessBackgrounded(bool background) { |
| DCHECK(CalledOnValidThread()); |
| base::Process to_pass = process_.Duplicate(); |
| @@ -503,33 +181,6 @@ void ChildProcessLauncher::SetProcessBackgrounded(bool background) { |
| base::Passed(&to_pass), background)); |
| } |
| -void ChildProcessLauncher::DidLaunch( |
| - base::WeakPtr<ChildProcessLauncher> instance, |
| - bool terminate_on_shutdown, |
| - mojo::edk::ScopedPlatformHandle server_handle, |
| - ZygoteHandle zygote, |
| -#if defined(OS_ANDROID) |
| - base::ScopedFD mojo_fd, |
| -#endif |
| - base::Process process, |
| - int error_code) { |
| - if (!process.IsValid()) |
| - LOG(ERROR) << "Failed to launch child process"; |
| - |
| - if (instance.get()) { |
| - instance->Notify(zygote, std::move(server_handle), |
| - std::move(process), error_code); |
| - } else { |
| - if (process.IsValid() && terminate_on_shutdown) { |
| - // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So |
| - // don't this on the UI/IO threads. |
| - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| - base::Bind(&TerminateOnLauncherThread, zygote, |
| - base::Passed(&process))); |
| - } |
| - } |
| -} |
| - |
| void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
| mojo::edk::ScopedPlatformHandle server_handle, |
| base::Process process, |
| @@ -544,9 +195,7 @@ void ChildProcessLauncher::Notify(ZygoteHandle zygote, |
| mojo_child_token_, process_error_callback_); |
| } |
| -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| zygote_ = zygote; |
| -#endif |
| if (process_.IsValid()) { |
| client_->OnProcessLaunched(); |
| } else { |
| @@ -564,7 +213,7 @@ bool ChildProcessLauncher::IsStarting() { |
| const base::Process& ChildProcessLauncher::GetProcess() const { |
| // TODO(crbug.com/469248): This fails in some tests. |
| - // DCHECK(CalledOnValidThread()); |
| + // DCHECK(CalledOnValidThread()); |
| return process_; |
| } |
| @@ -583,18 +232,22 @@ base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus( |
| if (exit_code) |
| *exit_code = exit_code_; |
| - // POSIX: If the process crashed, then the kernel closed the socket |
| - // for it and so the child has already died by the time we get |
| - // here. Since GetTerminationStatus called waitpid with WNOHANG, |
| - // it'll reap the process. However, if GetTerminationStatus didn't |
| - // reap the child (because it was still running), we'll need to |
| - // Terminate via ProcessWatcher. So we can't close the handle here. |
| + // POSIX: If the process crashed, then the kernel closed the socket for it and |
| + // so the child has already died by the time we get here. Since |
| + // GetTerminationStatus called waitpid with WNOHANG, it'll reap the process. |
| + // However, if GetTerminationStatus didn't reap the child (because it was |
| + // still running), we'll need to Terminate via ProcessWatcher. So we can't |
| + // close the handle here. |
| if (termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING) |
| process_.Close(); |
| return termination_status_; |
| } |
| +bool ChildProcessLauncher::Terminate(int exit_code, bool wait) { |
| + return IsStarting() ? false : TerminateProcess(GetProcess(), exit_code, wait); |
| +} |
| + |
| ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
| Client* client) { |
| Client* ret = client_; |
| @@ -602,4 +255,20 @@ ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest( |
| return ret; |
| } |
| +// static |
| +void ChildProcessLauncher::Terminate( |
| + ZygoteHandle zygote, base::Process process) { |
| + if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) { |
| + ChildProcessLauncher::TerminateOnLauncherThread(zygote, std::move(process)); |
| + return; |
| + } |
| + // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So don't |
| + // this on the UI/IO threads. |
| + BrowserThread::PostTask( |
| + BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| + base::Bind(&ChildProcessLauncher::TerminateOnLauncherThread, |
| + zygote, base::Passed(&process))); |
| +} |
| + |
| + |
| } // namespace content |