Change the NaCl loader and broker processes to use the ServiceManager.

This is the first child process outside of content to be connected to
the ServiceManager so this CL adds a way for content embedders to
provide additional service manifests via ContentBrowserClient. This
would introduce an unnecessary string copy when obtaining service
manifest overlays, so this changes that API to take a StringPiece.

BUG=666605
[email protected]

Review-Url: https://codereview.chromium.org/2501913002
Cr-Commit-Position: refs/heads/master@{#440299}
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index b87bb97..efe69357 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -533,8 +533,8 @@
   return new AwDevToolsManagerDelegate();
 }
 
-std::unique_ptr<base::Value>
-AwContentBrowserClient::GetServiceManifestOverlay(const std::string& name) {
+std::unique_ptr<base::Value> AwContentBrowserClient::GetServiceManifestOverlay(
+    base::StringPiece name) {
   int id = -1;
   if (name == content::mojom::kBrowserServiceName)
     id = IDR_AW_BROWSER_MANIFEST_OVERLAY;
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index a3472c5..e53659f 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -131,7 +131,7 @@
       content::NavigationHandle* navigation_handle) override;
   content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name) override;
+      base::StringPiece name) override;
   void RegisterRenderFrameMojoInterfaces(
       service_manager::InterfaceRegistry* registry,
       content::RenderFrameHost* render_frame_host) override;
diff --git a/blimp/engine/app/blimp_content_browser_client.cc b/blimp/engine/app/blimp_content_browser_client.cc
index 5e8c42b3..e3a5d01 100644
--- a/blimp/engine/app/blimp_content_browser_client.cc
+++ b/blimp/engine/app/blimp_content_browser_client.cc
@@ -53,8 +53,7 @@
 }
 
 std::unique_ptr<base::Value>
-BlimpContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& name) {
+BlimpContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   int id = -1;
   if (name == content::mojom::kBrowserServiceName) {
diff --git a/blimp/engine/app/blimp_content_browser_client.h b/blimp/engine/app/blimp_content_browser_client.h
index d843da0..20a2a7d 100644
--- a/blimp/engine/app/blimp_content_browser_client.h
+++ b/blimp/engine/app/blimp_content_browser_client.h
@@ -32,7 +32,7 @@
       service_manager::InterfaceRegistry* registry,
       content::RenderProcessHost* render_process_host) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name) override;
+      base::StringPiece name) override;
 
   BlimpBrowserContext* GetBrowserContext();
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index ebb38e3f..974c2ff0 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -612,6 +612,10 @@
       <include name="IDR_CHROME_CONTENT_PLUGIN_MANIFEST_OVERLAY" file="chrome_content_plugin_manifest_overlay.json" type="BINDATA" />
       <include name="IDR_CHROME_CONTENT_RENDERER_MANIFEST_OVERLAY" file="chrome_content_renderer_manifest_overlay.json" type="BINDATA" />
       <include name="IDR_CHROME_CONTENT_UTILITY_MANIFEST_OVERLAY" file="chrome_content_utility_manifest_overlay.json" type="BINDATA" />
+      <include name="IDR_NACL_LOADER_MANIFEST" file="../../components/nacl/loader/nacl_loader_manifest.json" type="BINDATA" />
+      <if expr="is_win">
+        <include name="IDR_NACL_BROKER_MANIFEST" file="../../components/nacl/broker/nacl_broker_manifest.json" type="BINDATA" />
+      </if>
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dbdaad2..7bfe7f13 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -134,6 +134,7 @@
 #include "components/google/core/browser/google_util.h"
 #include "components/metrics/call_stack_profile_collector.h"
 #include "components/metrics/client_info.h"
+#include "components/nacl/common/nacl_constants.h"
 #include "components/net_log/chrome_net_log.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "components/payments/payment_request.mojom.h"
@@ -3095,8 +3096,7 @@
 }
 
 std::unique_ptr<base::Value>
-ChromeContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& name) {
+ChromeContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   int id = -1;
   if (name == content::mojom::kBrowserServiceName)
@@ -3117,6 +3117,18 @@
   return base::JSONReader::Read(manifest_contents);
 }
 
+std::vector<content::ContentBrowserClient::ServiceManifestInfo>
+ChromeContentBrowserClient::GetExtraServiceManifests() {
+  return std::vector<content::ContentBrowserClient::ServiceManifestInfo>({
+#if !defined(DISABLE_NACL)
+    {nacl::kNaClLoaderServiceName, IDR_NACL_LOADER_MANIFEST},
+#if defined(OS_WIN)
+        {nacl::kNaClBrokerServiceName, IDR_NACL_BROKER_MANIFEST},
+#endif  // defined(OS_WIN)
+#endif  // !defined(DISABLE_NACL)
+  });
+}
+
 void ChromeContentBrowserClient::OpenURL(
     content::BrowserContext* browser_context,
     const content::OpenURLParams& params,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 509a4c5..b76e82eb 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -294,7 +294,9 @@
   void RegisterOutOfProcessServices(
       OutOfProcessServiceMap* services) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name) override;
+      base::StringPiece name) override;
+  std::vector<content::ContentBrowserClient::ServiceManifestInfo>
+  GetExtraServiceManifests() override;
   void OpenURL(content::BrowserContext* browser_context,
                const content::OpenURLParams& params,
                const base::Callback<void(content::WebContents*)>& callback)
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index 5d5b1e9..e217999 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -43,9 +43,11 @@
         ]
       },
       "requires": {
+        "accessibility_autoclick": [ "ash:autoclick" ],
         "ash": [ "ash" ],
         "image_decoder": [ "decode" ],
-        "accessibility_autoclick": [ "ash:autoclick" ],
+        "nacl_broker": [ "browser" ],
+        "nacl_loader": [ "browser" ],
         "preferences": [ "preferences_manager" ],
         "ui": [ "ime_registrar" ]
       }
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 7d9e4a3..8a80ee92 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -434,7 +434,7 @@
 
 std::unique_ptr<base::Value>
 CastContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& service_name) {
+    base::StringPiece service_name) {
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   if (service_name != content::mojom::kBrowserServiceName)
     return nullptr;
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 0ed31c1..6df56aa50 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -154,7 +154,7 @@
       content::RenderProcessHost* render_process_host) override;
   void RegisterInProcessServices(StaticServiceMap* services) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& service_name) override;
+      base::StringPiece service_name) override;
 #if defined(OS_ANDROID)
   void GetAdditionalMappedFilesForChildProcess(
       const base::CommandLine& command_line,
diff --git a/components/nacl/DEPS b/components/nacl/DEPS
index a5b0e6ab..a5cd353 100644
--- a/components/nacl/DEPS
+++ b/components/nacl/DEPS
@@ -2,4 +2,5 @@
   "+content/public/common",
   "+ipc",
   "+mojo/public",
+  "+services/service_manager/public",
 ]
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn
index 08e4489..3a2b360 100644
--- a/components/nacl/broker/BUILD.gn
+++ b/components/nacl/broker/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/features.gni")
 import("//build/config/compiler/compiler.gni")
+import("//services/service_manager/public/service_manifest.gni")
 
 # This file builds nacl64.exe, which is a 64-bit x86 Windows executable
 # used only in the 32-bit x86 Windows build.  The :broker code runs both
@@ -29,6 +30,7 @@
     "//ipc",
     "//mojo/edk/system",
     "//sandbox",
+    "//services/service_manager/public/cpp",
   ]
 
   if (current_cpu == target_cpu) {
@@ -36,6 +38,10 @@
   } else {
     deps += [ ":content_dummy" ]
   }
+
+  data_deps = [
+    ":nacl_broker_manifest",
+  ]
 }
 
 # This exists just to make 'gn check' happy with :broker.  It can't depend
@@ -169,3 +175,8 @@
     ]
   }
 }
+
+service_manifest("nacl_broker_manifest") {
+  name = "nacl_broker"
+  source = "nacl_broker_manifest.json"
+}
diff --git a/components/nacl/broker/OWNERS b/components/nacl/broker/OWNERS
new file mode 100644
index 0000000..39ccc030
--- /dev/null
+++ b/components/nacl/broker/OWNERS
@@ -0,0 +1,3 @@
+# Mojo manifests
+per-file *manifest.json=set noparent
+per-file *manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/components/nacl/broker/nacl_broker_listener.cc b/components/nacl/broker/nacl_broker_listener.cc
index c928b001..6161d66 100644
--- a/components/nacl/broker/nacl_broker_listener.cc
+++ b/components/nacl/broker/nacl_broker_listener.cc
@@ -19,6 +19,7 @@
 #include "components/nacl/common/nacl_cmd_line.h"
 #include "components/nacl/common/nacl_debug_exception_handler_win.h"
 #include "components/nacl/common/nacl_messages.h"
+#include "components/nacl/common/nacl_service.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/mojo_channel_switches.h"
@@ -28,6 +29,7 @@
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "sandbox/win/src/sandbox_policy.h"
+#include "services/service_manager/public/cpp/service_context.h"
 
 namespace {
 
@@ -42,14 +44,12 @@
 NaClBrokerListener::~NaClBrokerListener() = default;
 
 void NaClBrokerListener::Listen() {
-  mojo::ScopedMessagePipeHandle handle(
-      mojo::edk::CreateChildMessagePipe(
-          base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-              switches::kMojoChannelToken)));
-  DCHECK(handle.is_valid());
-  IPC::ChannelHandle channel_handle(handle.release());
+  mojo::ScopedMessagePipeHandle channel_handle;
+  std::unique_ptr<service_manager::ServiceContext> service_context =
+      CreateNaClServiceContext(base::ThreadTaskRunnerHandle::Get(),
+                               &channel_handle);
 
-  channel_ = IPC::Channel::CreateClient(channel_handle, this);
+  channel_ = IPC::Channel::CreateClient(channel_handle.release(), this);
   CHECK(channel_->Connect());
   run_loop_.Run();
 }
@@ -138,7 +138,7 @@
     mojo::ScopedMessagePipeHandle host_message_pipe =
         mojo::edk::CreateParentMessagePipe(mojo_channel_token,
                                            mojo_child_token);
-    cmd_line->AppendSwitchASCII(switches::kMojoChannelToken,
+    cmd_line->AppendSwitchASCII(switches::kServiceRequestChannelToken,
                                 mojo_channel_token);
     CHECK_EQ(MOJO_RESULT_OK,
              mojo::FuseMessagePipes(std::move(loader_message_pipe),
diff --git a/components/nacl/broker/nacl_broker_manifest.json b/components/nacl/broker/nacl_broker_manifest.json
new file mode 100644
index 0000000..8a56b79
--- /dev/null
+++ b/components/nacl/broker/nacl_broker_manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "nacl_broker",
+  "display_name": "NaCl broker",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "browser": [
+          "IPC::mojom::ChannelBootstrap"
+        ]
+      }
+    }
+  }
+}
diff --git a/components/nacl/browser/nacl_broker_host_win.cc b/components/nacl/browser/nacl_broker_host_win.cc
index 4b2e9a0..fb6cd81 100644
--- a/components/nacl/browser/nacl_broker_host_win.cc
+++ b/components/nacl/browser/nacl_broker_host_win.cc
@@ -10,6 +10,7 @@
 #include "components/nacl/browser/nacl_broker_service_win.h"
 #include "components/nacl/browser/nacl_browser.h"
 #include "components/nacl/common/nacl_cmd_line.h"
+#include "components/nacl/common/nacl_constants.h"
 #include "components/nacl/common/nacl_messages.h"
 #include "components/nacl/common/nacl_process_type.h"
 #include "components/nacl/common/nacl_switches.h"
@@ -47,17 +48,12 @@
 }
 
 bool NaClBrokerHost::Init() {
-  const std::string mojo_child_token = mojo::edk::GenerateRandomToken();
   DCHECK(!process_);
   process_.reset(content::BrowserChildProcessHost::Create(
       static_cast<content::ProcessType>(PROCESS_TYPE_NACL_BROKER), this,
-      mojo_child_token));
+      kNaClBrokerServiceName));
 
-  // Create the channel that will be used for communicating with the broker.
-  const std::string mojo_channel_token =
-      process_->GetHost()->CreateChannelMojo(mojo_child_token);
-  if (mojo_channel_token.empty())
-    return false;
+  process_->GetHost()->CreateChannelMojo();
 
   // Create the path to the nacl broker/loader executable.
   base::FilePath nacl_path;
@@ -69,7 +65,6 @@
 
   cmd_line->AppendSwitchASCII(switches::kProcessType,
                               switches::kNaClBrokerProcess);
-  cmd_line->AppendSwitchASCII(switches::kMojoChannelToken, mojo_channel_token);
   if (NaClBrowser::GetDelegate()->DialogsAreSuppressed())
     cmd_line->AppendSwitch(switches::kNoErrorDialogs);
 
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index f788ae4f..f8b4711 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -37,6 +37,7 @@
 #include "components/nacl/browser/nacl_browser_delegate.h"
 #include "components/nacl/browser/nacl_host_message_filter.h"
 #include "components/nacl/common/nacl_cmd_line.h"
+#include "components/nacl/common/nacl_constants.h"
 #include "components/nacl/common/nacl_host_messages.h"
 #include "components/nacl/common/nacl_messages.h"
 #include "components/nacl/common/nacl_process_type.h"
@@ -228,11 +229,10 @@
       process_type_(process_type),
       profile_directory_(profile_directory),
       render_view_id_(render_view_id),
-      mojo_child_token_(mojo::edk::GenerateRandomToken()),
       weak_factory_(this) {
   process_.reset(content::BrowserChildProcessHost::Create(
       static_cast<content::ProcessType>(PROCESS_TYPE_NACL_LOADER), this,
-      mojo_child_token_));
+      kNaClLoaderServiceName));
 
   // Set the display name so the user knows what plugin the process is running.
   // We aren't on the UI thread so getting the pref locale for language
@@ -500,15 +500,7 @@
 }
 
 bool NaClProcessHost::LaunchSelLdr() {
-  DCHECK(!mojo_child_token_.empty());
-  std::string mojo_channel_token =
-      process_->GetHost()->CreateChannelMojo(mojo_child_token_);
-  // |mojo_child_token_| is no longer used.
-  base::STLClearObject(&mojo_child_token_);
-  if (mojo_channel_token.empty()) {
-    SendErrorToRenderer("CreateChannelMojo() failed");
-    return false;
-  }
+  process_->GetHost()->CreateChannelMojo();
 
   // Build command line for nacl.
 
@@ -566,7 +558,6 @@
                               (uses_nonsfi_mode_ ?
                                switches::kNaClLoaderNonSfiProcess :
                                switches::kNaClLoaderProcess));
-  cmd_line->AppendSwitchASCII(switches::kMojoChannelToken, mojo_channel_token);
   if (NaClBrowser::GetDelegate()->DialogsAreSuppressed())
     cmd_line->AppendSwitch(switches::kNoErrorDialogs);
 
@@ -578,7 +569,8 @@
 #if defined(OS_WIN)
   if (RunningOnWOW64()) {
     if (!NaClBrokerService::GetInstance()->LaunchLoader(
-            weak_factory_.GetWeakPtr(), mojo_channel_token)) {
+            weak_factory_.GetWeakPtr(),
+            process_->GetServiceRequestChannelToken())) {
       SendErrorToRenderer("broker service did not launch process");
       return false;
     }
diff --git a/components/nacl/browser/nacl_process_host.h b/components/nacl/browser/nacl_process_host.h
index 6d2c06d..d3fd57a 100644
--- a/components/nacl/browser/nacl_process_host.h
+++ b/components/nacl/browser/nacl_process_host.h
@@ -257,9 +257,6 @@
   // reporting crash information.
   base::SharedMemory crash_info_shmem_;
 
-  // Randomly generated token identifying the child process to Mojo.
-  std::string mojo_child_token_;
-
   base::WeakPtrFactory<NaClProcessHost> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NaClProcessHost);
diff --git a/components/nacl/common/BUILD.gn b/components/nacl/common/BUILD.gn
index 36a0dba..de3d469 100644
--- a/components/nacl/common/BUILD.gn
+++ b/components/nacl/common/BUILD.gn
@@ -17,6 +17,8 @@
       "nacl_messages.h",
       "nacl_process_type.h",
       "nacl_sandbox_type.h",
+      "nacl_service.cc",
+      "nacl_service.h",
       "nacl_types.cc",
       "nacl_types.h",
       "nacl_types_param_traits.cc",
@@ -24,15 +26,19 @@
     ]
 
     public_deps = [
+      ":minimal_content_dummy",
       ":switches",
     ]
 
     deps = [
-      ":minimal_content_dummy",
       ":nacl_error_code",
       "//base",
       "//base:base_static",
+      "//content/public/common:service_names",
       "//ipc",
+      "//ipc:mojom",
+      "//mojo/edk/system",
+      "//services/service_manager/public/cpp",
     ]
   }
 
@@ -43,7 +49,9 @@
   source_set("minimal_content_dummy") {
     check_includes = false
     sources = [
+      "//content/public/common/content_descriptors.h",
       "//content/public/common/content_switches.h",
+      "//content/public/common/mojo_channel_switches.h",
       "//content/public/common/process_type.h",
       "//content/public/common/sandbox_type.h",
     ]
diff --git a/components/nacl/common/DEPS b/components/nacl/common/DEPS
index 3b9fcea..c95ab33 100644
--- a/components/nacl/common/DEPS
+++ b/components/nacl/common/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+native_client/src/public",
   "+native_client/src/trusted/service_runtime/nacl_error_code.h",
+  "+mojo/edk/embedder",
+  "+mojo/public",
 ]
diff --git a/components/nacl/common/nacl_constants.cc b/components/nacl/common/nacl_constants.cc
index d3a8a63..81979f2 100644
--- a/components/nacl/common/nacl_constants.cc
+++ b/components/nacl/common/nacl_constants.cc
@@ -21,4 +21,7 @@
 const base::FilePath::CharType kInternalNaClPluginFileName[] =
     FILE_PATH_LITERAL("internal-nacl-plugin");
 
+const char kNaClBrokerServiceName[] = "nacl_broker";
+const char kNaClLoaderServiceName[] = "nacl_loader";
+
 }  // namespace nacl
diff --git a/components/nacl/common/nacl_constants.h b/components/nacl/common/nacl_constants.h
index 2b18e0e6..09df003 100644
--- a/components/nacl/common/nacl_constants.h
+++ b/components/nacl/common/nacl_constants.h
@@ -20,6 +20,9 @@
 
 extern const base::FilePath::CharType kInternalNaClPluginFileName[];
 
+extern const char kNaClBrokerServiceName[];
+extern const char kNaClLoaderServiceName[];
+
 }  // namespace nacl
 
 #endif  // COMPONENTS_NACL_COMMON_NACL_CONSTANTS_H_
diff --git a/components/nacl/common/nacl_service.cc b/components/nacl/common/nacl_service.cc
new file mode 100644
index 0000000..ac22e57
--- /dev/null
+++ b/components/nacl/common/nacl_service.cc
@@ -0,0 +1,113 @@
+// Copyright 2016 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 "components/nacl/common/nacl_service.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "content/public/common/mojo_channel_switches.h"
+#include "content/public/common/service_names.mojom.h"
+#include "ipc/ipc.mojom.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/scoped_ipc_support.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_info.h"
+
+#if defined(OS_POSIX)
+#include "base/posix/global_descriptors.h"
+#include "content/public/common/content_descriptors.h"
+#elif defined(OS_WIN)
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#endif
+
+namespace {
+
+void EstablishMojoConnection() {
+#if defined(OS_WIN)
+  mojo::edk::ScopedPlatformHandle platform_channel(
+      mojo::edk::PlatformChannelPair::PassClientHandleFromParentProcess(
+          *base::CommandLine::ForCurrentProcess()));
+#else
+  mojo::edk::ScopedPlatformHandle platform_channel(mojo::edk::PlatformHandle(
+      base::GlobalDescriptors::GetInstance()->Get(kMojoIPCChannel)));
+#endif
+  DCHECK(platform_channel.is_valid());
+  mojo::edk::SetParentPipeHandle(std::move(platform_channel));
+}
+
+service_manager::mojom::ServiceRequest ConnectToServiceManager() {
+  const std::string service_request_channel_token =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kServiceRequestChannelToken);
+  DCHECK(!service_request_channel_token.empty());
+  mojo::ScopedMessagePipeHandle parent_handle =
+      mojo::edk::CreateChildMessagePipe(service_request_channel_token);
+  DCHECK(parent_handle.is_valid());
+  return mojo::MakeRequest<service_manager::mojom::Service>(
+      std::move(parent_handle));
+}
+
+void ConnectBootstrapChannel(IPC::mojom::ChannelBootstrapPtrInfo ptr,
+                             IPC::mojom::ChannelBootstrapRequest request) {
+  mojo::FuseInterface(std::move(request), std::move(ptr));
+}
+
+class NaClService : public service_manager::Service {
+ public:
+  NaClService(IPC::mojom::ChannelBootstrapPtrInfo bootstrap,
+              std::unique_ptr<mojo::edk::ScopedIPCSupport> ipc_support);
+  ~NaClService() override;
+
+  // Service overrides.
+  bool OnConnect(const service_manager::ServiceInfo& remote_info,
+                 service_manager::InterfaceRegistry* registry) override;
+
+ private:
+  IPC::mojom::ChannelBootstrapPtrInfo ipc_channel_bootstrap_;
+  std::unique_ptr<mojo::edk::ScopedIPCSupport> ipc_support_;
+  bool connected_ = false;
+};
+
+NaClService::NaClService(
+    IPC::mojom::ChannelBootstrapPtrInfo bootstrap,
+    std::unique_ptr<mojo::edk::ScopedIPCSupport> ipc_support)
+    : ipc_channel_bootstrap_(std::move(bootstrap)),
+      ipc_support_(std::move(ipc_support)) {}
+
+NaClService::~NaClService() = default;
+
+bool NaClService::OnConnect(const service_manager::ServiceInfo& remote_info,
+                            service_manager::InterfaceRegistry* registry) {
+  if (remote_info.identity.name() != content::mojom::kBrowserServiceName)
+    return false;
+
+  if (connected_)
+    return false;
+
+  connected_ = true;
+  registry->AddInterface(base::Bind(&ConnectBootstrapChannel,
+                                    base::Passed(&ipc_channel_bootstrap_)));
+  return true;
+}
+
+}  // namespace
+
+std::unique_ptr<service_manager::ServiceContext> CreateNaClServiceContext(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    mojo::ScopedMessagePipeHandle* ipc_channel) {
+  auto ipc_support =
+      base::MakeUnique<mojo::edk::ScopedIPCSupport>(std::move(io_task_runner));
+  EstablishMojoConnection();
+
+  IPC::mojom::ChannelBootstrapPtr bootstrap;
+  *ipc_channel = mojo::MakeRequest(&bootstrap).PassMessagePipe();
+  return base::MakeUnique<service_manager::ServiceContext>(
+      base::MakeUnique<NaClService>(bootstrap.PassInterface(),
+                                    std::move(ipc_support)),
+      ConnectToServiceManager());
+}
diff --git a/components/nacl/common/nacl_service.h b/components/nacl/common/nacl_service.h
new file mode 100644
index 0000000..887dfdda
--- /dev/null
+++ b/components/nacl/common/nacl_service.h
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+#ifndef COMPONENTS_NACL_COMMON_NACL_SERVICE_H_
+#define COMPONENTS_NACL_COMMON_NACL_SERVICE_H_
+
+#include <memory>
+
+#include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace service_manager {
+class ServiceContext;
+}
+
+std::unique_ptr<service_manager::ServiceContext> CreateNaClServiceContext(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    mojo::ScopedMessagePipeHandle* ipc_channel);
+
+#endif  // COMPONENTS_NACL_COMMON_NACL_SERVICE_H_
diff --git a/components/nacl/loader/BUILD.gn b/components/nacl/loader/BUILD.gn
index 6fa48361..e770d17b 100644
--- a/components/nacl/loader/BUILD.gn
+++ b/components/nacl/loader/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//build/config/features.gni")
 import("//build/config/nacl/config.gni")
+import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 assert(enable_nacl)
@@ -39,6 +40,7 @@
     "//ppapi/c",
     "//ppapi/proxy:ipc",
     "//sandbox",
+    "//services/service_manager/public/cpp",
   ]
 }
 
@@ -50,10 +52,7 @@
   check_includes = false
   sources = [
     "//content/public/common/child_process_sandbox_support_linux.h",
-    "//content/public/common/content_descriptors.h",
-    "//content/public/common/content_switches.h",
     "//content/public/common/main_function_params.h",
-    "//content/public/common/mojo_channel_switches.h",
     "//content/public/common/sandbox_init.h",
   ]
 
@@ -71,9 +70,11 @@
     "//components/nacl/common",
     "//content/public/common",
     "//ppapi/shared_impl",
+    "//services/service_manager/public/cpp",
   ]
 
   data_deps = [
+    ":nacl_loader_manifest",
     "//ppapi/native_client:irt",
     "//ppapi/native_client/src/untrusted/pnacl_support_extension",
   ]
@@ -196,13 +197,6 @@
     output_name = "nacl_helper_nonsfi"
     set_sources_assignment_filter([])
     sources = [
-      # TODO(brettw) can this just depend on //components/nacl/common?
-      "../common/nacl_messages.cc",
-      "../common/nacl_messages.h",
-      "../common/nacl_types.cc",
-      "../common/nacl_types.h",
-      "../common/nacl_types_param_traits.cc",
-      "../common/nacl_types_param_traits.h",
       "nacl_helper_linux.cc",
       "nacl_helper_linux.h",
       "nacl_trusted_listener.cc",
@@ -215,6 +209,7 @@
     deps = [
       ":nacl_helper_nonsfi_sandbox",
       "//base",
+      "//components/nacl/common:minimal",
       "//components/nacl/common:mojo_bindings",
       "//components/nacl/common:switches",
       "//components/tracing",
@@ -232,6 +227,7 @@
       "//native_client/src/untrusted/nacl",
       "//ppapi/proxy",
       "//sandbox/linux:sandbox",
+      "//services/service_manager/public/cpp",
     ]
   }
 
@@ -245,6 +241,7 @@
     ]
     deps = [
       "//base",
+      "//components/nacl/common:minimal",
       "//components/nacl/common:switches",
       "//content",
       "//sandbox/linux:sandbox",
@@ -297,3 +294,8 @@
     ]
   }
 }
+
+service_manifest("nacl_loader_manifest") {
+  name = "nacl_loader"
+  source = "nacl_loader_manifest.json"
+}
diff --git a/components/nacl/loader/OWNERS b/components/nacl/loader/OWNERS
new file mode 100644
index 0000000..39ccc030
--- /dev/null
+++ b/components/nacl/loader/OWNERS
@@ -0,0 +1,3 @@
+# Mojo manifests
+per-file *manifest.json=set noparent
+per-file *manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc
index cdbbafd0..df24f6d 100644
--- a/components/nacl/loader/nacl_helper_linux.cc
+++ b/components/nacl/loader/nacl_helper_linux.cc
@@ -152,7 +152,7 @@
       child_fds[content::ZygoteForkDelegate::kPIDOracleFDIndex].get()));
 
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kMojoChannelToken, channel_id);
+      switches::kServiceRequestChannelToken, channel_id);
 
   // Save the browser socket and close the rest.
   base::ScopedFD browser_fd(
diff --git a/components/nacl/loader/nacl_helper_win_64.cc b/components/nacl/loader/nacl_helper_win_64.cc
index a17fe888..fb2ebe5 100644
--- a/components/nacl/loader/nacl_helper_win_64.cc
+++ b/components/nacl/loader/nacl_helper_win_64.cc
@@ -26,8 +26,6 @@
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/sandbox_init.h"
 #include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
 #include "sandbox/win/src/sandbox_types.h"
 
 extern int NaClMain(const content::MainFunctionParams&);
@@ -40,12 +38,6 @@
   base::PlatformThread::SetName("CrNaClBrokerMain");
 
   mojo::edk::Init();
-  mojo::edk::ScopedIPCSupport mojo_ipc_support(main_message_loop.task_runner());
-  mojo::edk::ScopedPlatformHandle platform_channel(
-      mojo::edk::PlatformChannelPair::PassClientHandleFromParentProcess(
-          *base::CommandLine::ForCurrentProcess()));
-  DCHECK(platform_channel.is_valid());
-  mojo::edk::SetParentPipeHandle(std::move(platform_channel));
 
   std::unique_ptr<base::PowerMonitorSource> power_monitor_source(
       new base::PowerMonitorDeviceSource());
diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc
index 8cf5a31..ecefbb8 100644
--- a/components/nacl/loader/nacl_listener.cc
+++ b/components/nacl/loader/nacl_listener.cc
@@ -26,6 +26,7 @@
 #include "build/build_config.h"
 #include "components/nacl/common/nacl.mojom.h"
 #include "components/nacl/common/nacl_messages.h"
+#include "components/nacl/common/nacl_service.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "components/nacl/loader/nacl_ipc_adapter.h"
 #include "components/nacl/loader/nacl_validation_db.h"
@@ -34,16 +35,10 @@
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_sync_channel.h"
 #include "ipc/ipc_sync_message_filter.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
 #include "native_client/src/public/chrome_main.h"
 #include "native_client/src/public/nacl_app.h"
 #include "native_client/src/public/nacl_desc.h"
-
-#if defined(OS_POSIX)
-#include "base/posix/global_descriptors.h"
-#include "content/public/common/content_descriptors.h"
-#endif
+#include "services/service_manager/public/cpp/service_context.h"
 
 #if defined(OS_LINUX)
 #include "content/public/common/child_process_sandbox_support_linux.h"
@@ -53,7 +48,6 @@
 #include <io.h>
 
 #include "content/public/common/sandbox_init.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
 #endif
 
 namespace {
@@ -174,20 +168,6 @@
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
   DCHECK(g_listener == NULL);
   g_listener = this;
-
-  mojo_ipc_support_ =
-      base::MakeUnique<mojo::edk::ScopedIPCSupport>(io_thread_.task_runner());
-#if defined(OS_WIN)
-  mojo::edk::ScopedPlatformHandle platform_channel(
-      mojo::edk::PlatformChannelPair::PassClientHandleFromParentProcess(
-          *base::CommandLine::ForCurrentProcess()));
-#else
-  mojo::edk::ScopedPlatformHandle platform_channel(
-      mojo::edk::PlatformHandle(
-          base::GlobalDescriptors::GetInstance()->Get(kMojoIPCChannel)));
-#endif
-  DCHECK(platform_channel.is_valid());
-  mojo::edk::SetParentPipeHandle(std::move(platform_channel));
 }
 
 NaClListener::~NaClListener() {
@@ -236,17 +216,14 @@
 };
 
 void NaClListener::Listen() {
-  mojo::ScopedMessagePipeHandle handle(
-      mojo::edk::CreateChildMessagePipe(
-          base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-              switches::kMojoChannelToken)));
-  DCHECK(handle.is_valid());
-
   channel_ = IPC::SyncChannel::Create(this, io_thread_.task_runner().get(),
                                       &shutdown_event_);
   filter_ = channel_->CreateSyncMessageFilter();
   channel_->AddFilter(new FileTokenMessageFilter());
-  channel_->Init(handle.release(), IPC::Channel::MODE_CLIENT, true);
+  mojo::ScopedMessagePipeHandle channel_handle;
+  std::unique_ptr<service_manager::ServiceContext> service_context =
+      CreateNaClServiceContext(io_thread_.task_runner(), &channel_handle);
+  channel_->Init(channel_handle.release(), IPC::Channel::MODE_CLIENT, true);
   main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
   base::RunLoop().Run();
 }
diff --git a/components/nacl/loader/nacl_listener.h b/components/nacl/loader/nacl_listener.h
index f0a9806..ed95cc37 100644
--- a/components/nacl/loader/nacl_listener.h
+++ b/components/nacl/loader/nacl_listener.h
@@ -28,12 +28,6 @@
 class SyncMessageFilter;
 }
 
-namespace mojo {
-namespace edk {
-class ScopedIPCSupport;
-}  // namespace edk
-}  // namespace mojo
-
 // The NaClListener is an IPC channel listener that waits for a
 // request to start a NaCl module.
 class NaClListener : public IPC::Listener {
@@ -125,8 +119,6 @@
 
   bool is_started_;
 
-  std::unique_ptr<mojo::edk::ScopedIPCSupport> mojo_ipc_support_;
-
   DISALLOW_COPY_AND_ASSIGN(NaClListener);
 };
 
diff --git a/components/nacl/loader/nacl_loader_manifest.json b/components/nacl/loader/nacl_loader_manifest.json
new file mode 100644
index 0000000..7598054
--- /dev/null
+++ b/components/nacl/loader/nacl_loader_manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "nacl_loader",
+  "display_name": "NaCl loader",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "browser": [
+          "IPC::mojom::ChannelBootstrap"
+        ]
+      }
+    }
+  }
+}
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.cc b/components/nacl/loader/nonsfi/nonsfi_listener.cc
index 4c992b8..b7a43aa 100644
--- a/components/nacl/loader/nonsfi/nonsfi_listener.cc
+++ b/components/nacl/loader/nonsfi/nonsfi_listener.cc
@@ -10,12 +10,12 @@
 #include "base/file_descriptor_posix.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/posix/global_descriptors.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
 #include "components/nacl/common/nacl.mojom.h"
 #include "components/nacl/common/nacl_messages.h"
+#include "components/nacl/common/nacl_service.h"
 #include "components/nacl/common/nacl_types.h"
 #include "components/nacl/loader/nacl_trusted_listener.h"
 #include "components/nacl/loader/nonsfi/nonsfi_main.h"
@@ -24,11 +24,10 @@
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_sync_channel.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
 #include "native_client/src/public/nonsfi/irt_random.h"
 #include "ppapi/nacl_irt/irt_manifest.h"
 #include "ppapi/nacl_irt/plugin_startup.h"
+#include "services/service_manager/public/cpp/service_context.h"
 
 #if !defined(OS_NACL_NONSFI)
 #error "This file must be built for nacl_helper_nonsfi."
@@ -44,34 +43,21 @@
       key_fd_map_(new std::map<std::string, int>) {
   io_thread_.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
-
-  mojo_ipc_support_ =
-      base::MakeUnique<mojo::edk::ScopedIPCSupport>(io_thread_.task_runner());
-  mojo::edk::ScopedPlatformHandle platform_channel(
-      mojo::edk::PlatformHandle(
-          base::GlobalDescriptors::GetInstance()->Get(kMojoIPCChannel)));
-  DCHECK(platform_channel.is_valid());
-  mojo::edk::SetParentPipeHandle(std::move(platform_channel));
 }
 
 NonSfiListener::~NonSfiListener() {
 }
 
 void NonSfiListener::Listen() {
-  mojo::ScopedMessagePipeHandle handle(
-      mojo::edk::CreateChildMessagePipe(
-          base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-              switches::kMojoChannelToken)));
-  DCHECK(handle.is_valid());
-  IPC::ChannelHandle channel_handle = IPC::ChannelHandle(handle.release());
-
-  channel_ = IPC::SyncChannel::Create(
-      channel_handle,
-      IPC::Channel::MODE_CLIENT,
-      this,  // As a Listener.
-      io_thread_.task_runner().get(),
-      true,  // Create pipe now.
-      &shutdown_event_);
+  mojo::ScopedMessagePipeHandle channel_handle;
+  std::unique_ptr<service_manager::ServiceContext> service_context =
+      CreateNaClServiceContext(io_thread_.task_runner(), &channel_handle);
+  channel_ = IPC::SyncChannel::Create(channel_handle.release(),
+                                      IPC::Channel::MODE_CLIENT,
+                                      this,  // As a Listener.
+                                      io_thread_.task_runner(),
+                                      true,  // Create pipe now.
+                                      &shutdown_event_);
   base::RunLoop().Run();
 }
 
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.h b/components/nacl/loader/nonsfi/nonsfi_listener.h
index 9b18cd84..d673c291 100644
--- a/components/nacl/loader/nonsfi/nonsfi_listener.h
+++ b/components/nacl/loader/nonsfi/nonsfi_listener.h
@@ -20,12 +20,6 @@
 class SyncChannel;
 }  // namespace IPC
 
-namespace mojo {
-namespace edk {
-class ScopedIPCSupport;
-}  // namespace edk
-}  // namespace mojo
-
 class NaClTrustedListener;
 
 namespace nacl {
@@ -52,7 +46,6 @@
   base::WaitableEvent shutdown_event_;
   std::unique_ptr<IPC::SyncChannel> channel_;
   std::unique_ptr<NaClTrustedListener> trusted_listener_;
-  std::unique_ptr<mojo::edk::ScopedIPCSupport> mojo_ipc_support_;
 
   std::unique_ptr<std::map<std::string, int>> key_fd_map_;
 
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 85f4a51..33c2d22 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -92,6 +92,7 @@
       "public/common/content_switches.cc",
       "public/common/content_switches.h",
       "public/common/mojo_channel_switches.cc",
+      "public/common/mojo_channel_switches.h",
     ]
     set_sources_assignment_filter(sources_assignment_filter)
 
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index d311660a..3bca51b7 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -297,6 +297,10 @@
   data_.handle = handle;
 }
 
+std::string BrowserChildProcessHostImpl::GetServiceRequestChannelToken() {
+  return child_connection_->service_token();
+}
+
 void BrowserChildProcessHostImpl::ForceShutdown() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   g_child_process_list.Get().remove(this);
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index 9ac631e..08521db 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -80,6 +80,7 @@
       override;
   void SetName(const base::string16& name) override;
   void SetHandle(base::ProcessHandle handle) override;
+  std::string GetServiceRequestChannelToken() override;
 
   // ChildProcessHostDelegate implementation:
   bool CanShutdown() override;
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 7eab342..c6076ce6 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -114,10 +114,31 @@
   BuiltinManifestProvider() {}
   ~BuiltinManifestProvider() override {}
 
-  void AddManifestValue(const std::string& name,
-                        std::unique_ptr<base::Value> manifest_contents) {
+  void AddServiceManifest(base::StringPiece name, int resource_id) {
+    std::string contents =
+        GetContentClient()
+            ->GetDataResource(resource_id, ui::ScaleFactor::SCALE_FACTOR_NONE)
+            .as_string();
+    DCHECK(!contents.empty());
+
+    std::unique_ptr<base::Value> manifest_value =
+        base::JSONReader::Read(contents);
+    DCHECK(manifest_value);
+
+    std::unique_ptr<base::Value> overlay_value =
+        GetContentClient()->browser()->GetServiceManifestOverlay(name);
+    if (overlay_value) {
+      base::DictionaryValue* manifest_dictionary = nullptr;
+      bool result = manifest_value->GetAsDictionary(&manifest_dictionary);
+      DCHECK(result);
+      base::DictionaryValue* overlay_dictionary = nullptr;
+      result = overlay_value->GetAsDictionary(&overlay_dictionary);
+      DCHECK(result);
+      MergeDictionary(manifest_dictionary, overlay_dictionary);
+    }
+
     auto result = manifests_.insert(
-        std::make_pair(name, std::move(manifest_contents)));
+        std::make_pair(name.as_string(), std::move(manifest_value)));
     DCHECK(result.second) << "Duplicate manifest entry: " << name;
   }
 
@@ -238,30 +259,13 @@
     };
 
     for (size_t i = 0; i < arraysize(kManifests); ++i) {
-      std::string contents = GetContentClient()->GetDataResource(
-          kManifests[i].resource_id,
-          ui::ScaleFactor::SCALE_FACTOR_NONE).as_string();
-      base::debug::Alias(&i);
-      CHECK(!contents.empty());
-
-      std::unique_ptr<base::Value> manifest_value =
-          base::JSONReader::Read(contents);
-      base::debug::Alias(&contents);
-      CHECK(manifest_value);
-
-      std::unique_ptr<base::Value> overlay_value =
-          GetContentClient()->browser()->GetServiceManifestOverlay(
-              kManifests[i].name);
-      if (overlay_value) {
-        base::DictionaryValue* manifest_dictionary = nullptr;
-        CHECK(manifest_value->GetAsDictionary(&manifest_dictionary));
-        base::DictionaryValue* overlay_dictionary = nullptr;
-        CHECK(overlay_value->GetAsDictionary(&overlay_dictionary));
-        MergeDictionary(manifest_dictionary, overlay_dictionary);
-      }
-
-      manifest_provider->AddManifestValue(kManifests[i].name,
-                                          std::move(manifest_value));
+      manifest_provider->AddServiceManifest(kManifests[i].name,
+                                            kManifests[i].resource_id);
+    }
+    for (const auto& manifest :
+         GetContentClient()->browser()->GetExtraServiceManifests()) {
+      manifest_provider->AddServiceManifest(manifest.name,
+                                            manifest.resource_id);
     }
     in_process_context_ = new InProcessServiceManagerContext;
     request = in_process_context_->Start(std::move(manifest_provider));
diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h
index 7b5b9025..7f8bb93 100644
--- a/content/public/browser/browser_child_process_host.h
+++ b/content/public/browser/browser_child_process_host.h
@@ -92,6 +92,9 @@
   // this object.
   virtual void SetHandle(base::ProcessHandle handle) = 0;
 
+  // Returns the child message pipe token for the service request.
+  virtual std::string GetServiceRequestChannelToken() = 0;
+
 #if defined(OS_MACOSX)
   // Returns a PortProvider used to get the task port for child processes.
   static base::PortProvider* GetPortProvider();
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 279bede..6db33e99e 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -420,10 +420,15 @@
 #endif  // defined(OS_WIN)
 
 std::unique_ptr<base::Value> ContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& name) {
+    base::StringPiece name) {
   return nullptr;
 }
 
+std::vector<ContentBrowserClient::ServiceManifestInfo>
+ContentBrowserClient::GetExtraServiceManifests() {
+  return std::vector<ContentBrowserClient::ServiceManifestInfo>();
+}
+
 std::unique_ptr<MemoryCoordinatorDelegate>
 ContentBrowserClient::GetMemoryCoordinatorDelegate() {
   return std::unique_ptr<MemoryCoordinatorDelegate>();
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 4c4c1cf6..9c78311 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -709,7 +709,19 @@
   // with content's own for |name|. Additional entries will be appended to their
   // respective sections.
   virtual std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name);
+      base::StringPiece name);
+
+  struct ServiceManifestInfo {
+    // The name of the service.
+    std::string name;
+
+    // The resource ID of the manifest.
+    int resource_id;
+  };
+
+  // Allows the embedder to provide extra service manifests to be registered
+  // with the service manager context.
+  virtual std::vector<ServiceManifestInfo> GetExtraServiceManifests();
 
   // Allows to override the visibility state of a RenderFrameHost.
   // |visibility_state| should not be null. It will only be set if needed.
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 2b44625..402b298 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -219,8 +219,7 @@
 }
 
 std::unique_ptr<base::Value>
-ShellContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& name) {
+ShellContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
   int id = -1;
   if (name == content::mojom::kBrowserServiceName)
     id = IDR_CONTENT_SHELL_BROWSER_MANIFEST_OVERLAY;
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index d1937bfb..7b9d9d8 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -39,7 +39,7 @@
   void RegisterInProcessServices(StaticServiceMap* services) override;
   void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name) override;
+      base::StringPiece name) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
   void ResourceDispatcherHostCreated() override;
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc
index c196a7fc..900463e4 100644
--- a/content/zygote/zygote_linux.cc
+++ b/content/zygote/zygote_linux.cc
@@ -562,8 +562,9 @@
   base::GlobalDescriptors::Mapping mapping;
   std::string process_type;
   std::string channel_id;
-  const std::string channel_id_prefix = std::string("--")
-      + switches::kMojoChannelToken + std::string("=");
+  const std::string channel_id_prefix = std::string("--") +
+                                        switches::kServiceRequestChannelToken +
+                                        std::string("=");
 
   if (!iter.ReadString(&process_type))
     return -1;
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 1bfe88ff..8ba656c 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -61,7 +61,7 @@
 
 std::unique_ptr<base::Value>
 HeadlessContentBrowserClient::GetServiceManifestOverlay(
-    const std::string& name) {
+    base::StringPiece name) {
   if (name != content::mojom::kBrowserServiceName ||
       browser_->options()->mojo_service_names.empty())
     return nullptr;
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h
index 511083bf..3f44381 100644
--- a/headless/lib/browser/headless_content_browser_client.h
+++ b/headless/lib/browser/headless_content_browser_client.h
@@ -23,7 +23,7 @@
                            content::WebPreferences* prefs) override;
   content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
-      const std::string& name) override;
+      base::StringPiece name) override;
 
  private:
   HeadlessBrowserImpl* browser_;  // Not owned.