Change ServiceManagerConnectionImpl to run service request handlers on the IO thread.

Currently, ServiceManagerConnectionImpl posts to the main thread to run
service request handlers. This prevents services from being launched
before the main message loop starts. The pref service needs to launch
before the main message loop starts. This CL fixes this by running
service request handlers directly on the IO thread.

BUG=654988

Review-Url: https://codereview.chromium.org/2729733003
Cr-Original-Commit-Position: refs/heads/master@{#455295}
Committed: https://chromium.googlesource.com/chromium/src/+/072bd1f5e01408854503b640c9ad62216d9b6b76
Review-Url: https://codereview.chromium.org/2729733003
Cr-Commit-Position: refs/heads/master@{#456316}
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 338d2e8..add454a7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3231,6 +3231,7 @@
     content::ServiceInfo info;
     info.factory = base::Bind(&ash_util::CreateEmbeddedAshService,
                               base::ThreadTaskRunnerHandle::Get());
+    info.task_runner = base::ThreadTaskRunnerHandle::Get();
     services->insert(std::make_pair(ash::mojom::kServiceName, info));
   }
 #endif  // OS_CHROMEOS
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 08c55b8..638e0ecc2 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -450,7 +450,6 @@
 
     ServiceManagerConnection* connection =
         connection_holder->service_manager_connection();
-    connection->Start();
 
     // New embedded service factories should be added to |connection| here.
 
@@ -469,6 +468,7 @@
     for (const auto& entry : services) {
       connection->AddEmbeddedService(entry.first, entry.second);
     }
+    connection->Start();
   }
 }
 
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index a398ae9a..c400726c 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -53,40 +53,31 @@
 
 void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); }
 
-void StartUtilityProcessOnIOThread(
-    service_manager::mojom::ServiceFactoryRequest request,
+void StartServiceInUtilityProcess(
+    const std::string& service_name,
     const base::string16& process_name,
-    bool use_sandbox) {
+    bool use_sandbox,
+    service_manager::mojom::ServiceRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   UtilityProcessHost* process_host =
       UtilityProcessHost::Create(nullptr, nullptr);
   process_host->SetName(process_name);
   if (!use_sandbox)
     process_host->DisableSandbox();
   process_host->Start();
-  process_host->GetRemoteInterfaces()->GetInterface(std::move(request));
-}
-
-void StartServiceInUtilityProcess(
-    const std::string& service_name,
-    const base::string16& process_name,
-    bool use_sandbox,
-    service_manager::mojom::ServiceRequest request) {
   service_manager::mojom::ServiceFactoryPtr service_factory;
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&StartUtilityProcessOnIOThread,
-                 base::Passed(MakeRequest(&service_factory)), process_name,
-                 use_sandbox));
+  process_host->GetRemoteInterfaces()->GetInterface(
+      mojo::MakeRequest(&service_factory));
   service_factory->CreateService(std::move(request), service_name);
 }
 
 #if (ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
 
 // Request service_manager::mojom::ServiceFactory from GPU process host. Must be
-// called on
-// IO thread.
-void RequestGpuServiceFactory(
-    service_manager::mojom::ServiceFactoryRequest request) {
+// called on IO thread.
+void StartServiceInGpuProcess(const std::string& service_name,
+                              service_manager::mojom::ServiceRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   GpuProcessHost* process_host =
       GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED);
   if (!process_host) {
@@ -94,20 +85,13 @@
     return;
   }
 
+  service_manager::mojom::ServiceFactoryPtr service_factory;
   // TODO(xhwang): It's possible that |process_host| is non-null, but the actual
   // process is dead. In that case, |request| will be dropped and application
   // load requests through ServiceFactory will also fail. Make sure we handle
   // these cases correctly.
-  process_host->GetRemoteInterfaces()->GetInterface(std::move(request));
-}
-
-void StartServiceInGpuProcess(const std::string& service_name,
-                              service_manager::mojom::ServiceRequest request) {
-  service_manager::mojom::ServiceFactoryPtr service_factory;
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&RequestGpuServiceFactory,
-                 base::Passed(MakeRequest(&service_factory))));
+  process_host->GetRemoteInterfaces()->GetInterface(
+      mojo::MakeRequest(&service_factory));
   service_factory->CreateService(std::move(request), service_name);
 }
 
@@ -301,13 +285,12 @@
       std::move(root_browser_service), mojo::MakeRequest(&pid_receiver));
   pid_receiver->SetPID(base::GetCurrentProcId());
 
-  packaged_services_connection_->Start();
-  ServiceManagerConnection::GetForProcess()->Start();
 
   ServiceInfo device_info;
   device_info.factory =
       base::Bind(&device::CreateDeviceService,
                  BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE));
+  device_info.task_runner = base::ThreadTaskRunnerHandle::Get();
   packaged_services_connection_->AddEmbeddedService(device::mojom::kServiceName,
                                                     device_info);
 
@@ -351,6 +334,8 @@
   packaged_services_connection_->AddServiceRequestHandler(
       "media", base::Bind(&StartServiceInGpuProcess, "media"));
 #endif
+  packaged_services_connection_->Start();
+  ServiceManagerConnection::GetForProcess()->Start();
 }
 
 ServiceManagerContext::~ServiceManagerContext() {
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc
index 212ec813..5549c63 100644
--- a/content/common/service_manager/service_manager_connection_impl.cc
+++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -49,9 +49,6 @@
  public:
   using InitializeCallback =
       base::Callback<void(const service_manager::Identity&)>;
-  using ServiceFactoryCallback =
-      base::Callback<void(service_manager::mojom::ServiceRequest,
-                          const std::string&)>;
 
   IOThreadContext(
       service_manager::mojom::ServiceRequest service_request,
@@ -71,7 +68,6 @@
   void Start(
       const InitializeCallback& initialize_callback,
       const ServiceManagerConnection::OnConnectHandler& on_connect_callback,
-      const ServiceFactoryCallback& create_service_callback,
       const base::Closure& stop_callback) {
     DCHECK(!started_);
 
@@ -79,7 +75,6 @@
     callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
     initialize_handler_ = initialize_callback;
     on_connect_callback_ = on_connect_callback;
-    create_service_callback_ = create_service_callback;
     stop_callback_ = stop_callback;
     io_task_runner_->PostTask(
         FROM_HERE, base::Bind(&IOThreadContext::StartOnIOThread, this));
@@ -126,6 +121,21 @@
         base::ThreadTaskRunnerHandle::Get(), binder);
   }
 
+  void AddEmbeddedService(const std::string& name, const ServiceInfo& info) {
+    io_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&ServiceManagerConnectionImpl::IOThreadContext::
+                                  AddEmbeddedServiceRequestHandlerOnIoThread,
+                              this, name, info));
+  }
+
+  void AddServiceRequestHandler(const std::string& name,
+                                const ServiceRequestHandler& handler) {
+    io_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&ServiceManagerConnectionImpl::IOThreadContext::
+                                  AddServiceRequestHandlerOnIoThread,
+                              this, name, handler));
+  }
+
  private:
   friend class base::RefCountedThreadSafe<IOThreadContext>;
 
@@ -203,6 +213,9 @@
     service_context_.reset();
 
     ClearConnectionFiltersOnIOThread();
+
+    request_handlers_.clear();
+    embedded_services_.clear();
   }
 
   void ClearConnectionFiltersOnIOThread() {
@@ -224,6 +237,27 @@
     has_browser_connection_ = false;
   }
 
+  void AddEmbeddedServiceRequestHandlerOnIoThread(const std::string& name,
+                                                  const ServiceInfo& info) {
+    DCHECK(io_thread_checker_.CalledOnValidThread());
+    std::unique_ptr<EmbeddedServiceRunner> service(
+        new EmbeddedServiceRunner(name, info));
+    AddServiceRequestHandlerOnIoThread(
+        name, base::Bind(&EmbeddedServiceRunner::BindServiceRequest,
+                         base::Unretained(service.get())));
+    auto result =
+        embedded_services_.insert(std::make_pair(name, std::move(service)));
+    DCHECK(result.second);
+  }
+
+  void AddServiceRequestHandlerOnIoThread(
+      const std::string& name,
+      const ServiceRequestHandler& handler) {
+    DCHECK(io_thread_checker_.CalledOnValidThread());
+    auto result = request_handlers_.insert(std::make_pair(name, handler));
+    DCHECK(result.second);
+  }
+
   /////////////////////////////////////////////////////////////////////////////
   // service_manager::Service implementation
 
@@ -295,9 +329,10 @@
   void CreateService(service_manager::mojom::ServiceRequest request,
                      const std::string& name) override {
     DCHECK(io_thread_checker_.CalledOnValidThread());
-    callback_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(create_service_callback_, base::Passed(&request), name));
+    auto it = request_handlers_.find(name);
+    DCHECK(it != request_handlers_.end())
+        << "Can't create service " << name << ". No handler found.";
+    it->second.Run(std::move(request));
   }
 
   static void CallBinderOnTaskRunner(
@@ -329,9 +364,6 @@
   // Callback to run when a connection request is received.
   ServiceManagerConnection::OnConnectHandler on_connect_callback_;
 
-  // Callback to run when a new Service request is received.
-  ServiceFactoryCallback create_service_callback_;
-
   // Callback to run if the service is stopped by the service manager.
   base::Closure stop_callback_;
 
@@ -359,6 +391,10 @@
   base::Lock lock_;
   std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_;
 
+  std::unordered_map<std::string, std::unique_ptr<EmbeddedServiceRunner>>
+      embedded_services_;
+  std::unordered_map<std::string, ServiceRequestHandler> request_handlers_;
+
   base::WeakPtrFactory<IOThreadContext> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(IOThreadContext);
@@ -433,8 +469,6 @@
                  weak_factory_.GetWeakPtr()),
       base::Bind(&ServiceManagerConnectionImpl::OnConnect,
                  weak_factory_.GetWeakPtr()),
-      base::Bind(&ServiceManagerConnectionImpl::CreateService,
-                 weak_factory_.GetWeakPtr()),
       base::Bind(&ServiceManagerConnectionImpl::OnConnectionLost,
                  weak_factory_.GetWeakPtr()));
 }
@@ -476,21 +510,13 @@
 
 void ServiceManagerConnectionImpl::AddEmbeddedService(const std::string& name,
                                                       const ServiceInfo& info) {
-  std::unique_ptr<EmbeddedServiceRunner> service(
-      new EmbeddedServiceRunner(name, info));
-  AddServiceRequestHandler(
-      name, base::Bind(&EmbeddedServiceRunner::BindServiceRequest,
-                       base::Unretained(service.get())));
-  auto result =
-      embedded_services_.insert(std::make_pair(name, std::move(service)));
-  DCHECK(result.second);
+  context_->AddEmbeddedService(name, info);
 }
 
 void ServiceManagerConnectionImpl::AddServiceRequestHandler(
     const std::string& name,
     const ServiceRequestHandler& handler) {
-  auto result = request_handlers_.insert(std::make_pair(name, handler));
-  DCHECK(result.second);
+  context_->AddServiceRequestHandler(name, handler);
 }
 
 int ServiceManagerConnectionImpl::AddOnConnectHandler(
@@ -506,16 +532,6 @@
   on_connect_handlers_.erase(it);
 }
 
-void ServiceManagerConnectionImpl::CreateService(
-    service_manager::mojom::ServiceRequest request,
-    const std::string& name) {
-  auto it = request_handlers_.find(name);
-  DCHECK(it != request_handlers_.end())
-      << "Can't create service " << name << ". No handler found.";
-  if (it != request_handlers_.end())
-    it->second.Run(std::move(request));
-}
-
 void ServiceManagerConnectionImpl::OnContextInitialized(
     const service_manager::Identity& identity) {
   identity_ = identity;
diff --git a/content/common/service_manager/service_manager_connection_impl.h b/content/common/service_manager/service_manager_connection_impl.h
index 8f4f9bd5..4017d05c 100644
--- a/content/common/service_manager/service_manager_connection_impl.h
+++ b/content/common/service_manager/service_manager_connection_impl.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
+#include "content/common/content_export.h"
 #include "content/public/common/service_manager_connection.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/service_manager/public/cpp/identity.h"
@@ -22,9 +23,8 @@
 
 namespace content {
 
-class EmbeddedServiceRunner;
-
-class ServiceManagerConnectionImpl : public ServiceManagerConnection {
+class CONTENT_EXPORT ServiceManagerConnectionImpl
+    : public ServiceManagerConnection {
  public:
   explicit ServiceManagerConnectionImpl(
       service_manager::mojom::ServiceRequest request,
@@ -56,8 +56,6 @@
   void OnConnectionLost();
   void OnConnect(const service_manager::ServiceInfo& local_info,
                  const service_manager::ServiceInfo& remote_info);
-  void CreateService(service_manager::mojom::ServiceRequest request,
-                     const std::string& name);
   void GetInterface(service_manager::mojom::InterfaceProvider* provider,
                     const std::string& interface_name,
                     mojo::ScopedMessagePipeHandle request_handle);
@@ -71,9 +69,6 @@
 
   base::Closure connection_lost_handler_;
 
-  std::unordered_map<std::string, std::unique_ptr<EmbeddedServiceRunner>>
-      embedded_services_;
-  std::unordered_map<std::string, ServiceRequestHandler> request_handlers_;
   int next_on_connect_handler_id_ = 0;
   std::map<int, OnConnectHandler> on_connect_handlers_;
 
diff --git a/content/common/service_manager/service_manager_connection_impl_unittest.cc b/content/common/service_manager/service_manager_connection_impl_unittest.cc
new file mode 100644
index 0000000..ecca7a6
--- /dev/null
+++ b/content/common/service_manager/service_manager_connection_impl_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/service_manager/service_manager_connection_impl.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "services/service_manager/public/cpp/identity.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+namespace {
+
+constexpr char kTestServiceName[] = "test service";
+
+std::unique_ptr<service_manager::Service> LaunchService(
+    base::WaitableEvent* event) {
+  event->Signal();
+  return base::MakeUnique<service_manager::Service>();
+}
+
+}  // namespace
+
+TEST(ServiceManagerConnectionImplTest, ServiceLaunchThreading) {
+  base::MessageLoop message_loop;
+  base::Thread io_thread("ServiceManagerConnectionImplTest IO Thread");
+  io_thread.Start();
+  service_manager::mojom::ServicePtr service;
+  ServiceManagerConnectionImpl connection_impl(mojo::MakeRequest(&service),
+                                               io_thread.task_runner());
+  ServiceManagerConnection& connection = connection_impl;
+  ServiceInfo info;
+  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+                            base::WaitableEvent::InitialState::NOT_SIGNALED);
+  info.factory = base::Bind(&LaunchService, &event);
+  info.task_runner = io_thread.task_runner();
+  connection.AddEmbeddedService(kTestServiceName, info);
+  connection.Start();
+  service_manager::ServiceInfo source_info(
+      {service_manager::mojom::kServiceName,
+       service_manager::mojom::kRootUserID},
+      service_manager::InterfaceProviderSpecMap{});
+  service_manager::mojom::ServiceFactoryPtr factory;
+  service->OnBindInterface(source_info,
+                           service_manager::mojom::ServiceFactory::Name_,
+                           mojo::MakeRequest(&factory).PassMessagePipe(),
+                           base::Bind(&base::DoNothing));
+  service_manager::mojom::ServicePtr created_service;
+  factory->CreateService(mojo::MakeRequest(&created_service), kTestServiceName);
+  event.Wait();
+}
+
+}  // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d6a8786..02d9c0fe 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1365,6 +1365,7 @@
     "../common/sandbox_mac_system_access_unittest.mm",
     "../common/sandbox_mac_unittest_helper.h",
     "../common/sandbox_mac_unittest_helper.mm",
+    "../common/service_manager/service_manager_connection_impl_unittest.cc",
     "../common/service_worker/service_worker_utils_unittest.cc",
     "../common/webplugininfo_unittest.cc",
     "../public/test/referrer_unittest.cc",