Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(639)

Unified Diff: content/browser/child_process_launcher.cc

Issue 98603007: Launches a privileged utility process. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adds missing child_process_launcher files. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/child_process_launcher.cc
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 721cd5a88ede6cc6eeb7907bdecbfd35b7a5ff6d..29b7d6bb22a3fff59d8e83f82f0ca73f26268e5d 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -2,77 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "content/browser/child_process_launcher.h"
-
-#include <utility> // For std::pair.
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/process/process.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread.h"
-#include "content/public/browser/browser_thread.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"
-
-#if defined(OS_WIN)
-#include "base/files/file_path.h"
-#include "content/common/sandbox_win.h"
-#include "content/public/common/sandbox_init.h"
-#include "content/public/common/sandboxed_process_launcher_delegate.h"
-#elif defined(OS_MACOSX)
-#include "content/browser/mach_broker_mac.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_host_impl_linux.h"
-#include "content/common/child_process_sandbox_support_impl_linux.h"
-#endif
-
-#if defined(OS_POSIX)
-#include "base/posix/global_descriptors.h"
-#endif
+#include "content/browser/child_process_launcher.h"
+#include "content/browser/child_process_launcher_elevated.h"
+#include "content/browser/child_process_launcher_impl.h"
namespace content {
-// Having the functionality of ChildProcessLauncher be in an internal
-// ref counted object allows us to automatically terminate the process when the
-// parent class destructs, while still holding on to state that we need.
-class ChildProcessLauncher::Context
- : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> {
- public:
- Context()
- : client_(NULL),
- client_thread_id_(BrowserThread::UI),
- termination_status_(base::TERMINATION_STATUS_NORMAL_TERMINATION),
- exit_code_(RESULT_CODE_NORMAL_EXIT),
- starting_(true)
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- , zygote_(false)
-#endif
- {
-#if defined(OS_POSIX)
- terminate_child_on_shutdown_ = !CommandLine::ForCurrentProcess()->
- HasSwitch(switches::kChildCleanExit);
-#else
- terminate_child_on_shutdown_ = true;
-#endif
- }
-
- void Launch(
+ChildProcessLauncher* ChildProcessLauncher::Create(
#if defined(OS_WIN)
SandboxedProcessLauncherDelegate* delegate,
-#elif defined(OS_ANDROID)
- int ipcfd,
#elif defined(OS_POSIX)
bool use_zygote,
const base::EnvironmentMap& environ,
@@ -81,355 +20,12 @@ class ChildProcessLauncher::Context
CommandLine* cmd_line,
int child_process_id,
Client* client) {
- client_ = client;
-
- CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
-
-#if defined(OS_ANDROID)
- // We need to close the client end of the IPC channel to reliably detect
- // child termination. We will close this fd after we create the child
- // process which is asynchronous on Android.
- ipcfd_ = ipcfd;
-#endif
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(
- &Context::LaunchInternal,
- make_scoped_refptr(this),
- client_thread_id_,
- child_process_id,
-#if defined(OS_WIN)
- delegate,
-#elif defined(OS_ANDROID)
- ipcfd,
-#elif defined(OS_POSIX)
- use_zygote,
- environ,
- ipcfd,
-#endif
- cmd_line));
- }
-
-#if defined(OS_ANDROID)
- static void OnChildProcessStarted(
- // |this_object| is NOT thread safe. Only use it to post a task back.
- scoped_refptr<Context> this_object,
- BrowserThread::ID client_thread_id,
- const base::TimeTicks begin_launch_time,
- base::ProcessHandle handle) {
- RecordHistograms(begin_launch_time);
- if (BrowserThread::CurrentlyOn(client_thread_id)) {
- // This is always invoked on the UI thread which is commonly the
- // |client_thread_id| so we can shortcut one PostTask.
- this_object->Notify(handle);
- } else {
- BrowserThread::PostTask(
- client_thread_id, FROM_HERE,
- base::Bind(
- &ChildProcessLauncher::Context::Notify,
- this_object,
- handle));
- }
- }
-#endif
-
- void ResetClient() {
- // No need for locking as this function gets called on the same thread that
- // client_ would be used.
- CHECK(BrowserThread::CurrentlyOn(client_thread_id_));
- client_ = NULL;
- }
-
- void set_terminate_child_on_shutdown(bool terminate_on_shutdown) {
- terminate_child_on_shutdown_ = terminate_on_shutdown;
- }
-
- private:
- friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
- friend class ChildProcessLauncher;
-
- ~Context() {
- Terminate();
- }
-
- static void RecordHistograms(const base::TimeTicks begin_launch_time) {
- base::TimeDelta launch_time = base::TimeTicks::Now() - begin_launch_time;
- if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
- RecordLaunchHistograms(launch_time);
- } else {
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(&ChildProcessLauncher::Context::RecordLaunchHistograms,
- launch_time));
- }
- }
-
- static void RecordLaunchHistograms(const base::TimeDelta launch_time) {
- // 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;
- }
- }
-
- static void LaunchInternal(
- // |this_object| is NOT thread safe. Only use it to post a task back.
- scoped_refptr<Context> this_object,
- BrowserThread::ID client_thread_id,
- int child_process_id,
-#if defined(OS_WIN)
- SandboxedProcessLauncherDelegate* delegate,
-#elif defined(OS_ANDROID)
- int ipcfd,
-#elif defined(OS_POSIX)
- bool use_zygote,
- const base::EnvironmentMap& env,
- int ipcfd,
-#endif
- CommandLine* cmd_line) {
- scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
- base::TimeTicks begin_launch_time = base::TimeTicks::Now();
-
-#if defined(OS_WIN)
- scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
- base::ProcessHandle handle = StartSandboxedProcess(delegate, cmd_line);
-#elif defined(OS_ANDROID)
- // Android WebView runs in single process, ensure that we never get here
- // when running in single process mode.
- CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
-
- std::string process_type =
- cmd_line->GetSwitchValueASCII(switches::kProcessType);
- std::vector<FileDescriptorInfo> files_to_register;
- files_to_register.push_back(
- FileDescriptorInfo(kPrimaryIPCChannel,
- base::FileDescriptor(ipcfd, false)));
-
- GetContentClient()->browser()->
- GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
- &files_to_register);
-
- StartChildProcess(cmd_line->argv(), files_to_register,
- base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
- this_object, client_thread_id, begin_launch_time));
-
-#elif defined(OS_POSIX)
- base::ProcessHandle handle = base::kNullProcessHandle;
- // We need to close the client end of the IPC channel to reliably detect
- // child termination.
- file_util::ScopedFD ipcfd_closer(&ipcfd);
-
- std::string process_type =
- cmd_line->GetSwitchValueASCII(switches::kProcessType);
- std::vector<FileDescriptorInfo> files_to_register;
- files_to_register.push_back(
- FileDescriptorInfo(kPrimaryIPCChannel,
- base::FileDescriptor(ipcfd, false)));
-
-#if !defined(OS_MACOSX)
- GetContentClient()->browser()->
- GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
- &files_to_register);
- if (use_zygote) {
- handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(),
- files_to_register,
- process_type);
- } 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;
- for (size_t i = 0; i < files_to_register.size(); ++i) {
- fds_to_map.push_back(std::make_pair(
- files_to_register[i].fd.fd,
- files_to_register[i].id +
- 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();
-#endif // defined(OS_MACOSX)
-
- bool launched = base::LaunchProcess(*cmd_line, options, &handle);
-
-#if defined(OS_MACOSX)
- if (launched)
- broker->AddPlaceholderForPid(handle);
-
- // After updating the broker, release the lock and let the child's
- // messasge be processed on the broker's thread.
- broker->GetLock().Release();
-#endif // defined(OS_MACOSX)
-
- if (!launched)
- handle = base::kNullProcessHandle;
- }
-#endif // else defined(OS_POSIX)
-#if !defined(OS_ANDROID)
- if (handle)
- RecordHistograms(begin_launch_time);
- BrowserThread::PostTask(
- client_thread_id, FROM_HERE,
- base::Bind(
- &Context::Notify,
- this_object.get(),
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- use_zygote,
-#endif
- handle));
-#endif // !defined(OS_ANDROID)
- }
-
- void Notify(
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- bool zygote,
-#endif
- base::ProcessHandle handle) {
-#if defined(OS_ANDROID)
- // Finally close the ipcfd
- file_util::ScopedFD ipcfd_closer(&ipcfd_);
-#endif
- starting_ = false;
- process_.set_handle(handle);
- if (!handle)
- LOG(ERROR) << "Failed to launch child process";
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- zygote_ = zygote;
-#endif
- if (client_) {
- client_->OnProcessLaunched();
- } else {
- Terminate();
- }
- }
-
- void Terminate() {
- if (!process_.handle())
- return;
-
- if (!terminate_child_on_shutdown_)
- 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(
- &Context::TerminateInternal,
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- zygote_,
-#endif
- process_.handle()));
- process_.set_handle(base::kNullProcessHandle);
- }
-
- static void SetProcessBackgrounded(base::ProcessHandle handle,
- bool background) {
- base::Process process(handle);
- process.SetProcessBackgrounded(background);
- }
-
- static void TerminateInternal(
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- bool zygote,
-#endif
- base::ProcessHandle handle) {
-#if defined(OS_ANDROID)
- LOG(INFO) << "ChromeProcess: Stopping process with handle " << handle;
- StopChildProcess(handle);
-#else
- base::Process process(handle);
- // 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);
- // 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.
- ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle);
- } else
-#endif // !OS_MACOSX
- {
- base::EnsureProcessTerminated(handle);
- }
-#endif // OS_POSIX
- process.Close();
-#endif // defined(OS_ANDROID)
- }
-
- Client* client_;
- BrowserThread::ID client_thread_id_;
- base::Process process_;
- base::TerminationStatus termination_status_;
- int exit_code_;
- bool starting_;
- // Controls whether the child process should be terminated on browser
- // shutdown. Default behavior is to terminate the child.
- bool terminate_child_on_shutdown_;
-#if defined(OS_ANDROID)
- // The fd to close after creating the process.
- int ipcfd_;
-#elif defined(OS_POSIX) && !defined(OS_MACOSX)
- bool zygote_;
-#endif
-};
-
-
-ChildProcessLauncher::ChildProcessLauncher(
-#if defined(OS_WIN)
- SandboxedProcessLauncherDelegate* delegate,
-#elif defined(OS_POSIX)
- bool use_zygote,
- const base::EnvironmentMap& environ,
- int ipcfd,
-#endif
- CommandLine* cmd_line,
- int child_process_id,
- Client* client) {
- context_ = new Context();
- context_->Launch(
+ return new ChildProcessLauncherImpl(
#if defined(OS_WIN)
delegate,
-#elif defined(OS_ANDROID)
- ipcfd,
#elif defined(OS_POSIX)
use_zygote,
- environ,
+ base::EnvironmentMap& environ,
ipcfd,
#endif
cmd_line,
@@ -437,72 +33,16 @@ ChildProcessLauncher::ChildProcessLauncher(
client);
}
-ChildProcessLauncher::~ChildProcessLauncher() {
- context_->ResetClient();
-}
-
-bool ChildProcessLauncher::IsStarting() {
- return context_->starting_;
-}
-
-base::ProcessHandle ChildProcessLauncher::GetHandle() {
- DCHECK(!context_->starting_);
- return context_->process_.handle();
+#if defined(OS_WIN)
+ChildProcessLauncher* ChildProcessLauncher::CreateElevated(
+ CommandLine* cmd_line,
+ int child_process_id,
+ Client* client) {
+ return new ChildProcessLauncherElevated(
+ cmd_line,
+ child_process_id,
+ client);
}
-
-base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
- bool known_dead,
- int* exit_code) {
- base::ProcessHandle handle = context_->process_.handle();
- if (handle == base::kNullProcessHandle) {
- // Process is already gone, so return the cached termination status.
- if (exit_code)
- *exit_code = context_->exit_code_;
- return context_->termination_status_;
- }
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
- if (context_->zygote_) {
- context_->termination_status_ = ZygoteHostImpl::GetInstance()->
- GetTerminationStatus(handle, known_dead, &context_->exit_code_);
- } else
-#elif defined(OS_MACOSX)
- if (known_dead) {
- context_->termination_status_ =
- base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
- } else
#endif
- {
- context_->termination_status_ =
- base::GetTerminationStatus(handle, &context_->exit_code_);
- }
-
- if (exit_code)
- *exit_code = context_->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.
- if (context_->termination_status_ != base::TERMINATION_STATUS_STILL_RUNNING)
- context_->process_.Close();
-
- return context_->termination_status_;
-}
-
-void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(
- &ChildProcessLauncher::Context::SetProcessBackgrounded,
- GetHandle(), background));
-}
-
-void ChildProcessLauncher::SetTerminateChildOnShutdown(
- bool terminate_on_shutdown) {
- if (context_.get())
- context_->set_terminate_child_on_shutdown(terminate_on_shutdown);
-}
-} // namespace content
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698