Move the TaskRunner for process launching to ChildProcessLauncherHelper.

ServiceManager may need to launch child processes before a BrowserMainLoop
has been created, and therefore before any BrowserThreads exists. We
therefore replace the BrowserThread::PROCESS_LAUNCHER with a global
TaskScheduler sequence, created on-demand when the ServiceManager or
ChildProcessLauncherHelper first need it.

Under Windows we must use a single-thread TaskRunner, while on other
platforms we are able to use a normal TaskScheduler sequence. File
crbug.com/820200 to track that.

Bug: 815225
Change-Id: Ia0f46461fb9cc92fddacf81ee96b764de8477d11
Reviewed-on: https://chromium-review.googlesource.com/941264
Commit-Queue: Xi Han <[email protected]>
Reviewed-by: Ken Rockot <[email protected]>
Reviewed-by: John Abd-El-Malek <[email protected]>
Reviewed-by: Wez <[email protected]>
Cr-Commit-Position: refs/heads/master@{#542212}
diff --git a/content/browser/child_process_launcher_helper.cc b/content/browser/child_process_launcher_helper.cc
index 7ee3df4..e924b12d 100644
--- a/content/browser/child_process_launcher_helper.cc
+++ b/content/browser/child_process_launcher_helper.cc
@@ -6,18 +6,28 @@
 
 #include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/single_thread_task_runner_thread_mode.h"
+#include "base/task_scheduler/task_traits.h"
 #include "content/browser/child_process_launcher.h"
+#include "content/public/browser/child_process_launcher_utils.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 
+#if defined(OS_ANDROID)
+#include "content/browser/android/launcher_thread.h"
+#endif
+
 namespace content {
 namespace internal {
 
 namespace {
 
 void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
-  DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
+  DCHECK(CurrentlyOnProcessLauncherTaskRunner());
   // 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;
@@ -85,14 +95,14 @@
     mojo_client_handle_ = channel_pair.PassClientHandle();
   }
 
-  BrowserThread::PostTask(
-      BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+  GetProcessLauncherTaskRunner()->PostTask(
+      FROM_HERE,
       base::BindOnce(&ChildProcessLauncherHelper::LaunchOnLauncherThread,
                      this));
 }
 
 void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
-  DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
+  DCHECK(CurrentlyOnProcessLauncherTaskRunner());
 
   begin_launch_time_ = base::TimeTicks::Now();
 
@@ -167,18 +177,52 @@
 // static
 void ChildProcessLauncherHelper::ForceNormalProcessTerminationAsync(
     ChildProcessLauncherHelper::Process process) {
-  if (BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)) {
+  if (CurrentlyOnProcessLauncherTaskRunner()) {
     ForceNormalProcessTerminationSync(std::move(process));
     return;
   }
   // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep!
   // So don't do this on the UI/IO threads.
-  BrowserThread::PostTask(
-      BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+  GetProcessLauncherTaskRunner()->PostTask(
+      FROM_HERE,
       base::BindOnce(
           &ChildProcessLauncherHelper::ForceNormalProcessTerminationSync,
           std::move(process)));
 }
 
 }  // namespace internal
+
+// static
+base::SingleThreadTaskRunner* GetProcessLauncherTaskRunner() {
+#if defined(OS_ANDROID)
+  // Android specializes Launcher thread so it is accessible in java.
+  // Note Android never does clean shutdown, so shutdown use-after-free
+  // concerns are not a problem in practice.
+  // This process launcher thread will use the Java-side process-launching
+  // thread, instead of creating its own separate thread on C++ side. Note
+  // that means this thread will not be joined on shutdown, and may cause
+  // use-after-free if anything tries to access objects deleted by
+  // AtExitManager, such as non-leaky LazyInstance.
+  static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>>
+      launcher_task_runner(
+          android::LauncherThread::GetMessageLoop()->task_runner());
+#else   // defined(OS_ANDROID)
+  constexpr base::TaskTraits task_traits = {
+      base::MayBlock(), base::WithBaseSyncPrimitives(),
+      base::TaskPriority::USER_BLOCKING,
+      base::TaskShutdownBehavior::BLOCK_SHUTDOWN};
+  // TODO(wez): Investigates whether we could use SequencedTaskRunner on
+  // platforms other than Windows. http://crbug.com/820200.
+  static base::NoDestructor<scoped_refptr<base::SingleThreadTaskRunner>>
+      launcher_task_runner(base::CreateSingleThreadTaskRunnerWithTraits(
+          task_traits, base::SingleThreadTaskRunnerThreadMode::DEDICATED));
+#endif  // defined(OS_ANDROID)
+  return (*launcher_task_runner).get();
+}
+
+// static
+bool CurrentlyOnProcessLauncherTaskRunner() {
+  return GetProcessLauncherTaskRunner()->RunsTasksInCurrentSequence();
+}
+
 }  // namespace content