| 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..6970d248feaae5d83716e9eee6dee0c0d243d81a 100644
|
| --- a/content/browser/child_process_launcher.cc
|
| +++ b/content/browser/child_process_launcher.cc
|
| @@ -4,386 +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
|
| - // slower due to the rest of the browser initializing at the same time).
|
| - static bool done_first_launch = false;
|
| - if (done_first_launch) {
|
| - UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchSubsequent", launch_time);
|
| - } else {
|
| - UMA_HISTOGRAM_TIMES("MPArch.ChildProcessLaunchFirst", launch_time);
|
| - done_first_launch = true;
|
| - }
|
| -}
|
| -
|
| -#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
|
| +using internal::ChildProcessLauncherHelper;
|
|
|
| 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,
|
| @@ -392,7 +29,6 @@ ChildProcessLauncher::ChildProcessLauncher(
|
| : client_(client),
|
| termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
|
| exit_code_(RESULT_CODE_NORMAL_EXIT),
|
| - zygote_(nullptr),
|
| starting_(true),
|
| process_error_callback_(process_error_callback),
|
| #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
|
| @@ -406,148 +42,48 @@ 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 ChildProcessLauncherHelper(
|
| + child_process_id, client_thread_id_,
|
| + std::move(command_line), std::move(delegate),
|
| + weak_factory_.GetWeakPtr(), terminate_on_shutdown);
|
| + helper_->StartLaunchOnClientThread();
|
| }
|
|
|
| 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_.process.IsValid() && terminate_child_on_shutdown_) {
|
| + // Client has gone away, so just kill the process.
|
| + ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
|
| + std::move(process_));
|
| }
|
| }
|
|
|
| -void ChildProcessLauncher::Launch(
|
| - std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
| - std::unique_ptr<base::CommandLine> cmd_line,
|
| - int child_process_id) {
|
| +void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
|
| DCHECK(CalledOnValidThread());
|
| -
|
| -#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;
|
| -
|
| - // Non-sandboxed utility or renderer process are currently not supported.
|
| - DCHECK(process_type == switches::kGpuProcess ||
|
| - !cmd_line->HasSwitch(switches::kNoSandbox));
|
| -
|
| -#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
|
| - {
|
| - mojo::edk::PlatformChannelPair channel_pair;
|
| - server_handle = channel_pair.PassServerHandle();
|
| - client_handle = channel_pair.PassClientHandle();
|
| - }
|
| - NotifyCallback reply_callback(base::Bind(&ChildProcessLauncher::DidLaunch,
|
| - weak_factory_.GetWeakPtr(),
|
| - terminate_child_on_shutdown_,
|
| - base::Passed(&server_handle)));
|
| + base::Process to_pass = process_.process.Duplicate();
|
| 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)));
|
| -}
|
| -
|
| -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;
|
| - } else {
|
| -#else
|
| - {
|
| -#endif
|
| - termination_status_ =
|
| - base::GetTerminationStatus(process_.Handle(), &exit_code_);
|
| - }
|
| -}
|
| -
|
| -void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
|
| - DCHECK(CalledOnValidThread());
|
| - base::Process to_pass = process_.Duplicate();
|
| - BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
|
| - base::Bind(&SetProcessBackgroundedOnLauncherThread,
|
| - base::Passed(&to_pass), background));
|
| + base::Bind(
|
| + &ChildProcessLauncherHelper::SetProcessBackgroundedOnLauncherThread,
|
| + base::Passed(&to_pass),
|
| + background));
|
| }
|
|
|
| -void ChildProcessLauncher::DidLaunch(
|
| - base::WeakPtr<ChildProcessLauncher> instance,
|
| - bool terminate_on_shutdown,
|
| +void ChildProcessLauncher::Notify(
|
| + ChildProcessLauncherHelper::Process process,
|
| 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,
|
| - int error_code) {
|
| DCHECK(CalledOnValidThread());
|
| starting_ = false;
|
| process_ = std::move(process);
|
|
|
| - if (process_.IsValid()) {
|
| + if (process_.process.IsValid()) {
|
| // Set up Mojo IPC to the new process.
|
| - mojo::edk::ChildProcessLaunched(process_.Handle(), std::move(server_handle),
|
| - mojo_child_token_, process_error_callback_);
|
| - }
|
| -
|
| -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
|
| - zygote_ = zygote;
|
| -#endif
|
| - if (process_.IsValid()) {
|
| + mojo::edk::ChildProcessLaunched(process_.process.Handle(),
|
| + std::move(server_handle),
|
| + mojo_child_token_,
|
| + process_error_callback_);
|
| client_->OnProcessLaunched();
|
| } else {
|
| mojo::edk::ChildProcessLaunchFailed(mojo_child_token_);
|
| @@ -565,36 +101,50 @@ bool ChildProcessLauncher::IsStarting() {
|
| const base::Process& ChildProcessLauncher::GetProcess() const {
|
| // TODO(crbug.com/469248): This fails in some tests.
|
| // DCHECK(CalledOnValidThread());
|
| - return process_;
|
| + return process_.process;
|
| }
|
|
|
| base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
|
| bool known_dead,
|
| int* exit_code) {
|
| DCHECK(CalledOnValidThread());
|
| - if (!process_.IsValid()) {
|
| + if (!process_.process.IsValid()) {
|
| // Process is already gone, so return the cached termination status.
|
| if (exit_code)
|
| *exit_code = exit_code_;
|
| return termination_status_;
|
| }
|
|
|
| - UpdateTerminationStatus(known_dead);
|
| + termination_status_ = ChildProcessLauncherHelper::GetTerminationStatus(
|
| + process_, known_dead, &exit_code_);
|
| 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();
|
| + process_.process.Close();
|
|
|
| return termination_status_;
|
| }
|
|
|
| +bool ChildProcessLauncher::Terminate(int exit_code, bool wait) {
|
| + return IsStarting() ? false
|
| + : ChildProcessLauncherHelper::TerminateProcess(
|
| + GetProcess(), exit_code, wait);
|
| +}
|
| +
|
| +// static
|
| +bool ChildProcessLauncher::TerminateProcess(const base::Process& process,
|
| + int exit_code,
|
| + bool wait) {
|
| + return ChildProcessLauncherHelper::TerminateProcess(process, exit_code, wait);
|
| +}
|
| +
|
| ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
|
| Client* client) {
|
| Client* ret = client_;
|
|
|