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 |