summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrockot <rockot@chromium.org>2015-06-04 17:30:52 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-05 00:32:18 +0000
commitb814a5850da5aa473ad526eef4b41a82b05037a0 (patch)
treed1730ed4fccfc7fda63bd51f30891a95e61ba915
parent87c39e56c03c089751e4ae22dcea9ca7cf17c741 (diff)
downloadchromium_src-b814a5850da5aa473ad526eef4b41a82b05037a0.zip
chromium_src-b814a5850da5aa473ad526eef4b41a82b05037a0.tar.gz
chromium_src-b814a5850da5aa473ad526eef4b41a82b05037a0.tar.bz2
Embed a mojo ApplicationManager in content/browser
This embeds mojo/shell's ApplicationManager in content/browser and provides a way for arbitrary browser code to connect to Mojo apps as if the browser itself were a Mojo app. This is a basic implementation of Mojo app support which only loads static apps either in the browser process or a (per-app) utility process. Future CLs will address connection to apps from arbitrary render frames (i.e. connection requests which include the requestor's origin) as well as refactoring the utility process code further so that it serves strictly as a Mojo app runner. BUG=492422 Review URL: https://codereview.chromium.org/1149833007 Cr-Commit-Position: refs/heads/master@{#332974}
-rw-r--r--content/browser/BUILD.gn6
-rw-r--r--content/browser/browser_main_loop.cc5
-rw-r--r--content/browser/browser_main_loop.h2
-rw-r--r--content/browser/mojo/mojo_app_connection_impl.cc28
-rw-r--r--content/browser/mojo/mojo_app_connection_impl.h34
-rw-r--r--content/browser/mojo/mojo_shell_context.cc178
-rw-r--r--content/browser/mojo/mojo_shell_context.h70
-rw-r--r--content/browser/mojo_shell_browsertest.cc60
-rw-r--r--content/common/BUILD.gn3
-rw-r--r--content/common/process_control.mojom12
-rw-r--r--content/content.gyp1
-rw-r--r--content/content_browser.gypi10
-rw-r--r--content/content_common_mojo_bindings.gyp1
-rw-r--r--content/content_shell.gypi2
-rw-r--r--content/content_tests.gypi19
-rw-r--r--content/content_utility.gypi8
-rw-r--r--content/public/browser/BUILD.gn1
-rw-r--r--content/public/browser/content_browser_client.h11
-rw-r--r--content/public/browser/mojo_app_connection.h43
-rw-r--r--content/public/test/DEPS1
-rw-r--r--content/public/test/test_mojo_app.cc43
-rw-r--r--content/public/test/test_mojo_app.h50
-rw-r--r--content/public/test/test_mojo_service.mojom9
-rw-r--r--content/public/utility/BUILD.gn11
-rw-r--r--content/public/utility/content_utility_client.h16
-rw-r--r--content/shell/BUILD.gn2
-rw-r--r--content/shell/app/shell_main_delegate.cc6
-rw-r--r--content/shell/app/shell_main_delegate.h3
-rw-r--r--content/shell/utility/DEPS3
-rw-r--r--content/shell/utility/shell_content_utility_client.cc31
-rw-r--r--content/shell/utility/shell_content_utility_client.h22
-rw-r--r--content/test/BUILD.gn10
-rw-r--r--content/utility/BUILD.gn6
-rw-r--r--content/utility/DEPS2
-rw-r--r--content/utility/utility_process_control_impl.cc54
-rw-r--r--content/utility/utility_process_control_impl.h48
-rw-r--r--content/utility/utility_thread_impl.cc12
-rw-r--r--content/utility/utility_thread_impl.h13
-rw-r--r--mojo/application/public/cpp/BUILD.gn21
-rw-r--r--mojo/application/public/cpp/application_runner.h7
-rw-r--r--mojo/application/public/cpp/lib/application_runner.cc34
-rw-r--r--mojo/application/public/cpp/lib/init_commandline.cc22
-rw-r--r--mojo/mojo_base.gyp11
-rw-r--r--mojo/mojo_services.gyp11
-rw-r--r--mojo/mojo_shell.gyp7
-rw-r--r--mojo/shell/BUILD.gn2
-rw-r--r--mojo/shell/static_application_loader.cc95
-rw-r--r--mojo/shell/static_application_loader.h69
48 files changed, 1081 insertions, 34 deletions
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 71083b9..a8bcd7a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -29,14 +29,20 @@ source_set("browser") {
"//content/browser/service_worker:service_worker_proto",
"//content/browser/speech/proto",
"//content/public/common:common_sources",
+ "//content/public/common:mojo_bindings",
"//crypto",
"//device/battery",
"//device/vibration",
"//google_apis",
+ "//mojo/application/public/cpp:cpp_for_chromium",
+ "//mojo/application/public/interfaces",
+ "//mojo/common",
+ "//mojo/shell",
"//net",
"//net:extras",
"//skia",
"//sql",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
"//third_party/npapi",
"//third_party/re2",
"//third_party/WebKit/public:blink_headers",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 04640a8..2a92285 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -39,6 +39,7 @@
#include "content/browser/histogram_synchronizer.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/media/media_internals.h"
+#include "content/browser/mojo/mojo_shell_context.h"
#include "content/browser/net/browser_online_state_observer.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/speech/speech_recognition_manager_impl.h"
@@ -897,6 +898,8 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
true));
+ mojo_shell_context_.reset();
+
#if !defined(OS_IOS)
if (RenderProcessHost::run_renderer_in_process())
RenderProcessHostImpl::ShutDownInProcessRenderer();
@@ -1253,6 +1256,8 @@ int BrowserMainLoop::BrowserThreadsStarted() {
#endif // !defined(OS_IOS)
+ mojo_shell_context_.reset(new MojoShellContext);
+
return result_code_;
}
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 9eba81d..14478ec 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -45,6 +45,7 @@ class BrowserOnlineStateObserver;
class BrowserShutdownImpl;
class BrowserThreadImpl;
class MediaStreamManager;
+class MojoShellContext;
class ResourceDispatcherHostImpl;
class SpeechRecognitionManagerImpl;
class StartupTaskRunner;
@@ -231,6 +232,7 @@ class CONTENT_EXPORT BrowserMainLoop {
// Members initialized in |BrowserThreadsStarted()| --------------------------
scoped_ptr<base::Thread> indexed_db_thread_;
+ scoped_ptr<MojoShellContext> mojo_shell_context_;
// |user_input_monitor_| has to outlive |audio_manager_|, so declared first.
scoped_ptr<media::UserInputMonitor> user_input_monitor_;
diff --git a/content/browser/mojo/mojo_app_connection_impl.cc b/content/browser/mojo/mojo_app_connection_impl.cc
new file mode 100644
index 0000000..d643bbf
--- /dev/null
+++ b/content/browser/mojo/mojo_app_connection_impl.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 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/browser/mojo/mojo_app_connection_impl.h"
+
+#include "content/browser/mojo/mojo_shell_context.h"
+
+namespace content {
+
+scoped_ptr<MojoAppConnection> MojoAppConnection::Create(const GURL& url) {
+ return scoped_ptr<MojoAppConnection>(new MojoAppConnectionImpl(url));
+}
+
+MojoAppConnectionImpl::MojoAppConnectionImpl(const GURL& url) {
+ MojoShellContext::ConnectToApplication(url, mojo::GetProxy(&services_));
+}
+
+MojoAppConnectionImpl::~MojoAppConnectionImpl() {
+}
+
+void MojoAppConnectionImpl::ConnectToService(
+ const std::string& service_name,
+ mojo::ScopedMessagePipeHandle handle) {
+ services_->ConnectToService(service_name, handle.Pass());
+}
+
+} // namespace content
diff --git a/content/browser/mojo/mojo_app_connection_impl.h b/content/browser/mojo/mojo_app_connection_impl.h
new file mode 100644
index 0000000..4628acc
--- /dev/null
+++ b/content/browser/mojo/mojo_app_connection_impl.h
@@ -0,0 +1,34 @@
+// Copyright 2015 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 CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
+#define CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
+
+#include "base/macros.h"
+#include "content/public/browser/mojo_app_connection.h"
+#include "mojo/application/public/interfaces/service_provider.mojom.h"
+
+class GURL;
+
+namespace content {
+
+// Implementation of the app connection mechanism provided to browser code.
+class MojoAppConnectionImpl : public MojoAppConnection {
+ public:
+ explicit MojoAppConnectionImpl(const GURL& url);
+ ~MojoAppConnectionImpl() override;
+
+ private:
+ // MojoAppConnection:
+ void ConnectToService(const std::string& service_name,
+ mojo::ScopedMessagePipeHandle handle) override;
+
+ mojo::ServiceProviderPtr services_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoAppConnectionImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
new file mode 100644
index 0000000..49e66a9
--- /dev/null
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -0,0 +1,178 @@
+// Copyright 2015 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/browser/mojo/mojo_shell_context.h"
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/common/process_control.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/utility_process_host.h"
+#include "content/public/browser/utility_process_host_client.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/service_registry.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/common/url_type_converters.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+#include "mojo/shell/application_loader.h"
+#include "mojo/shell/static_application_loader.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/string.h"
+
+namespace content {
+
+namespace {
+
+// Virtual app URL to use as the requestor identity when connecting from browser
+// code to a Mojo app via the shell proxy.
+const char kBrowserAppUrl[] = "system:content_browser";
+
+// An extra set of apps to register on initialization, if set by a test.
+const MojoShellContext::StaticApplicationMap* g_applications_for_test;
+
+void StartProcessOnIOThread(mojo::InterfaceRequest<ProcessControl> request) {
+ UtilityProcessHost* process_host =
+ UtilityProcessHost::Create(nullptr, nullptr);
+ // TODO(rockot): Make it possible for the embedder to associate app URLs with
+ // app names so we can have more meaningful process names here.
+ process_host->SetName(base::UTF8ToUTF16("Mojo Application"));
+ process_host->StartMojoMode();
+ ServiceRegistry* services = process_host->GetServiceRegistry();
+ services->ConnectToRemoteService(request.Pass());
+}
+
+void OnApplicationLoaded(const GURL& url, bool success) {
+ if (!success)
+ LOG(ERROR) << "Failed to launch Mojo application for " << url.spec();
+}
+
+// The default loader to use for all applications. This launches a utility
+// process and forwards the Load request the ProcessControl service there.
+class UtilityProcessLoader : public mojo::shell::ApplicationLoader {
+ public:
+ UtilityProcessLoader() {}
+ ~UtilityProcessLoader() override {}
+
+ private:
+ // mojo::shell::ApplicationLoader:
+ void Load(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::Application> application_request) override {
+ ProcessControlPtr process_control;
+ auto process_request = mojo::GetProxy(&process_control);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&StartProcessOnIOThread, base::Passed(&process_request)));
+ process_control->LoadApplication(url.spec(), application_request.Pass(),
+ base::Bind(&OnApplicationLoaded, url));
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader);
+};
+
+} // namespace
+
+// Thread-safe proxy providing access to the shell context from any thread.
+class MojoShellContext::Proxy {
+ public:
+ Proxy(MojoShellContext* shell_context)
+ : shell_context_(shell_context),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
+ ~Proxy() {}
+
+ void ConnectToApplication(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+ if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
+ if (shell_context_)
+ shell_context_->ConnectToApplicationOnOwnThread(url, request.Pass());
+ } else {
+ // |shell_context_| outlives the main MessageLoop, so it's safe for it to
+ // be unretained here.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread,
+ base::Unretained(shell_context_), url,
+ base::Passed(&request)));
+ }
+ }
+
+ private:
+ MojoShellContext* shell_context_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(Proxy);
+};
+
+// static
+base::LazyInstance<scoped_ptr<MojoShellContext::Proxy>>
+ MojoShellContext::proxy_ = LAZY_INSTANCE_INITIALIZER;
+
+void MojoShellContext::SetApplicationsForTest(
+ const StaticApplicationMap* apps) {
+ g_applications_for_test = apps;
+}
+
+MojoShellContext::MojoShellContext()
+ : application_manager_(new mojo::shell::ApplicationManager(this)) {
+ proxy_.Get().reset(new Proxy(this));
+ application_manager_->set_default_loader(
+ scoped_ptr<mojo::shell::ApplicationLoader>(new UtilityProcessLoader));
+
+ StaticApplicationMap apps;
+ GetContentClient()->browser()->RegisterMojoApplications(&apps);
+ if (g_applications_for_test) {
+ // Add testing apps to the map, potentially overwriting whatever the
+ // browser client registered.
+ for (const auto& entry : *g_applications_for_test)
+ apps[entry.first] = entry.second;
+ }
+ for (const auto& entry : apps) {
+ application_manager_->SetLoaderForURL(
+ scoped_ptr<mojo::shell::ApplicationLoader>(
+ new mojo::shell::StaticApplicationLoader(entry.second)),
+ entry.first);
+ }
+}
+
+MojoShellContext::~MojoShellContext() {
+}
+
+// static
+void MojoShellContext::ConnectToApplication(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+ proxy_.Get()->ConnectToApplication(url, request.Pass());
+}
+
+void MojoShellContext::ConnectToApplicationOnOwnThread(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+ mojo::URLRequestPtr url_request = mojo::URLRequest::New();
+ url_request->url = mojo::String::From(url);
+ application_manager_->ConnectToApplication(
+ url_request.Pass(), GURL(kBrowserAppUrl), request.Pass(),
+ mojo::ServiceProviderPtr(), base::Bind(&base::DoNothing));
+}
+
+GURL MojoShellContext::ResolveMappings(const GURL& url) {
+ return url;
+}
+
+GURL MojoShellContext::ResolveMojoURL(const GURL& url) {
+ return url;
+}
+
+bool MojoShellContext::CreateFetcher(
+ const GURL& url,
+ const mojo::shell::Fetcher::FetchCallback& loader_callback) {
+ return false;
+}
+
+} // namespace content
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h
new file mode 100644
index 0000000..b0ac5b1
--- /dev/null
+++ b/content/browser/mojo/mojo_shell_context.h
@@ -0,0 +1,70 @@
+// Copyright 2015 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 CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
+#define CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
+
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "mojo/shell/application_manager.h"
+
+class GURL;
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
+namespace content {
+
+// MojoShellContext hosts the browser's ApplicationManager, coordinating
+// app registration and interconnection.
+class CONTENT_EXPORT MojoShellContext
+ : public NON_EXPORTED_BASE(mojo::shell::ApplicationManager::Delegate) {
+ public:
+ using StaticApplicationMap =
+ std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
+ MojoShellContext();
+ ~MojoShellContext() override;
+
+ // Connects an application at |url| and gets a handle to its exposed services.
+ // This is only intended for use in browser code that's not part of some Mojo
+ // application. May be called from any thread.
+ static void ConnectToApplication(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> request);
+
+ static void SetApplicationsForTest(const StaticApplicationMap* apps);
+
+ private:
+ class Proxy;
+ friend class Proxy;
+
+ void ConnectToApplicationOnOwnThread(
+ const GURL& url,
+ mojo::InterfaceRequest<mojo::ServiceProvider> request);
+
+ // mojo::shell::ApplicationManager::Delegate:
+ GURL ResolveMappings(const GURL& url) override;
+ GURL ResolveMojoURL(const GURL& url) override;
+ bool CreateFetcher(
+ const GURL& url,
+ const mojo::shell::Fetcher::FetchCallback& loader_callback) override;
+
+ static base::LazyInstance<scoped_ptr<Proxy>> proxy_;
+
+ scoped_ptr<mojo::shell::ApplicationManager> application_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoShellContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
diff --git a/content/browser/mojo_shell_browsertest.cc b/content/browser/mojo_shell_browsertest.cc
new file mode 100644
index 0000000..3dcde73
--- /dev/null
+++ b/content/browser/mojo_shell_browsertest.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 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 "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "content/browser/mojo/mojo_shell_context.h"
+#include "content/public/browser/mojo_app_connection.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_mojo_app.h"
+#include "content/public/test/test_mojo_service.mojom.h"
+#include "url/gurl.h"
+
+namespace content {
+
+const char kInProcessTestMojoAppUrl[] = "system:content_in_process_test_app";
+
+class MojoShellTest : public ContentBrowserTest {
+ public:
+ MojoShellTest() {
+ test_apps_[GURL(kInProcessTestMojoAppUrl)] = base::Bind(&CreateTestApp);
+ MojoShellContext::SetApplicationsForTest(&test_apps_);
+ }
+
+ private:
+ static scoped_ptr<mojo::ApplicationDelegate> CreateTestApp() {
+ return scoped_ptr<mojo::ApplicationDelegate>(new TestMojoApp);
+ }
+
+ MojoShellContext::StaticApplicationMap test_apps_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoShellTest);
+};
+
+IN_PROC_BROWSER_TEST_F(MojoShellTest, TestBrowserConnection) {
+ auto test_app = MojoAppConnection::Create(GURL(kInProcessTestMojoAppUrl));
+ TestMojoServicePtr test_service;
+ test_app->ConnectToService(&test_service);
+
+ base::RunLoop run_loop;
+ test_service->DoSomething(run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(MojoShellTest, TestUtilityConnection) {
+ // With no loader registered at this URL, the shell should spawn a utility
+ // process and connect us to it. content_shell's utility process always hosts
+ // a TestMojoApp at |kTestMojoAppUrl|.
+ auto test_app = MojoAppConnection::Create(GURL(kTestMojoAppUrl));
+ TestMojoServicePtr test_service;
+ test_app->ConnectToService(&test_service);
+
+ base::RunLoop run_loop;
+ test_service->DoSomething(run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+} // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index ecfe362..09f7a4a 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -486,9 +486,12 @@ mojom("mojo_bindings") {
"geolocation_service.mojom",
"permission_service.mojom",
"presentation/presentation_service.mojom",
+ "process_control.mojom",
"render_frame_setup.mojom",
]
+ import_dirs = [ "//mojo/services" ]
+
deps = [
"//content/public/common:mojo_bindings",
"//mojo/application/public/interfaces",
diff --git a/content/common/process_control.mojom b/content/common/process_control.mojom
new file mode 100644
index 0000000..4b3237a
--- /dev/null
+++ b/content/common/process_control.mojom
@@ -0,0 +1,12 @@
+// Copyright 2015 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.
+
+module content;
+
+import "mojo/application/public/interfaces/application.mojom";
+
+interface ProcessControl {
+ LoadApplication(string url, mojo.Application& request) => (bool success);
+};
+
diff --git a/content/content.gyp b/content/content.gyp
index de5327e..13a8385 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -287,6 +287,7 @@
'dependencies': [
'content_child',
'content_common',
+ 'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
],
},
],
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 6b8e555..74260af 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -11,10 +11,15 @@
'../device/vibration/vibration.gyp:device_vibration',
'../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
'../google_apis/google_apis.gyp:google_apis',
+ '../mojo/mojo_base.gyp:mojo_application_base',
+ '../mojo/mojo_base.gyp:mojo_url_type_converters',
+ '../mojo/mojo_services.gyp:network_service_bindings_lib',
+ '../mojo/mojo_shell.gyp:mojo_shell_lib',
'../net/net.gyp:net',
'../net/net.gyp:net_extras',
'../skia/skia.gyp:skia',
'../sql/sql.gyp:sql',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../third_party/re2/re2.gyp:re2',
'../third_party/zlib/google/zip.gyp:zip',
'../third_party/zlib/zlib.gyp:zlib',
@@ -165,6 +170,7 @@
'public/browser/media_device_id.h',
'public/browser/message_port_delegate.h',
'public/browser/message_port_provider.h',
+ 'public/browser/mojo_app_connection.h',
'public/browser/native_web_keyboard_event.h',
'public/browser/navigation_controller.cc',
'public/browser/navigation_controller.h',
@@ -1030,8 +1036,12 @@
'browser/message_port_service.h',
'browser/mime_registry_message_filter.cc',
'browser/mime_registry_message_filter.h',
+ 'browser/mojo/mojo_app_connection_impl.cc',
+ 'browser/mojo/mojo_app_connection_impl.h',
'browser/mojo/mojo_application_host.cc',
'browser/mojo/mojo_application_host.h',
+ 'browser/mojo/mojo_shell_context.cc',
+ 'browser/mojo/mojo_shell_context.h',
'browser/mojo/service_registrar_android.cc',
'browser/mojo/service_registrar_android.h',
'browser/mojo/service_registry_android.cc',
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index dc2df70..4f01043 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -16,6 +16,7 @@
'common/geolocation_service.mojom',
'common/permission_service.mojom',
'common/presentation/presentation_service.mojom',
+ 'common/process_control.mojom',
'common/render_frame_setup.mojom',
# NOTE: Sources duplicated in
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 75cf4c3..2f30de3 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -234,6 +234,8 @@
'shell/renderer/shell_content_renderer_client.h',
'shell/renderer/shell_render_view_observer.cc',
'shell/renderer/shell_render_view_observer.h',
+ 'shell/utility/shell_content_utility_client.cc',
+ 'shell/utility/shell_content_utility_client.h',
],
'msvs_settings': {
'VCLinkerTool': {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 24483e6..0dfc8ca 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -83,6 +83,8 @@
'public/test/test_file_system_options.h',
'public/test/test_launcher.cc',
'public/test/test_launcher.h',
+ 'public/test/test_mojo_app.cc',
+ 'public/test/test_mojo_app.h',
'public/test/test_navigation_observer.cc',
'public/test/test_navigation_observer.h',
'public/test/test_notification_tracker.cc',
@@ -222,6 +224,7 @@
'browser/media/media_canplaytype_browsertest.cc',
'browser/media/media_source_browsertest.cc',
'browser/message_port_provider_browsertest.cc',
+ 'browser/mojo_shell_browsertest.cc',
'browser/net_info_browsertest.cc',
'browser/plugin_browsertest.cc',
'browser/renderer_host/input/touch_action_browsertest.cc',
@@ -788,6 +791,7 @@
'target_name': 'test_support_content',
'type': 'static_library',
'dependencies': [
+ '../mojo/mojo_base.gyp:mojo_application_base',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../net/net.gyp:net_test_support',
'../skia/skia.gyp:skia',
@@ -795,6 +799,7 @@
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../ui/accessibility/accessibility.gyp:ax_gen',
'../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
'../ui/base/ui_base.gyp:ui_base',
@@ -862,6 +867,7 @@
}],
],
'dependencies': [
+ 'content_test_mojo_bindings',
'content.gyp:content_child',
'content.gyp:content_common',
'content.gyp:content_gpu',
@@ -880,6 +886,8 @@
'../media/blink/media_blink.gyp:media_blink',
'../media/media.gyp:media',
'../media/midi/midi.gyp:midi',
+ '../mojo/mojo_base.gyp:mojo_application_base',
+ '../mojo/mojo_base.gyp:mojo_environment_chromium',
'../ppapi/ppapi_internal.gyp:ppapi_host',
'../ppapi/ppapi_internal.gyp:ppapi_proxy',
'../ppapi/ppapi_internal.gyp:ppapi_shared',
@@ -887,6 +895,7 @@
'../storage/storage_browser.gyp:storage',
'../storage/storage_common.gyp:storage_common',
'../third_party/WebKit/public/blink.gyp:blink',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../ui/compositor/compositor.gyp:compositor_test_support',
'../ui/surface/surface.gyp:surface',
'../v8/tools/gyp/v8.gyp:v8',
@@ -1314,6 +1323,15 @@
],
},
{
+ # GN version: //content/test:test_mojo_bindings
+ 'target_name': 'content_test_mojo_bindings',
+ 'type': 'static_library',
+ 'sources': [
+ 'public/test/test_mojo_service.mojom',
+ ],
+ 'includes': [ '../third_party/mojo/mojom_bindings_generator.gypi' ],
+ },
+ {
# GN version: //content/test:web_ui_test_mojo_bindings
'target_name': 'web_ui_test_mojo_bindings',
'type': 'static_library',
@@ -1352,6 +1370,7 @@
'../ipc/ipc.gyp:test_support_ipc',
'../media/media.gyp:media_test_support',
'../media/media.gyp:shared_memory_support',
+ '../mojo/mojo_base.gyp:mojo_application_base',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../net/net.gyp:net_test_support',
'../ppapi/ppapi_internal.gyp:ppapi_host',
diff --git a/content/content_utility.gypi b/content/content_utility.gypi
index bbdfd4f..96d81f8 100644
--- a/content/content_utility.gypi
+++ b/content/content_utility.gypi
@@ -6,6 +6,12 @@
'dependencies': [
'../base/base.gyp:base',
'../courgette/courgette.gyp:courgette_lib',
+ '../mojo/mojo_base.gyp:mojo_application_base',
+ '../mojo/mojo_base.gyp:mojo_application_bindings',
+ '../mojo/mojo_base.gyp:mojo_common_lib',
+ '../mojo/mojo_shell.gyp:mojo_shell_lib',
+ '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '../url/url.gyp:url_lib',
],
'variables': {
'utility_sources': [
@@ -14,6 +20,8 @@
'utility/utility_blink_platform_impl.cc',
'utility/utility_blink_platform_impl.h',
'utility/utility_main.cc',
+ 'utility/utility_process_control_impl.cc',
+ 'utility/utility_process_control_impl.h',
'utility/utility_thread_impl.cc',
'utility/utility_thread_impl.h',
'utility/webthread_impl_for_utility_thread.cc',
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index a0c7f91..ebe488e 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -50,6 +50,7 @@ source_set("browser_sources") {
# We expose skia headers in the public API.
"//skia",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
"//third_party/mojo/src/mojo/public/cpp/system",
]
deps = [
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index eff374d..579b9f8 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -53,6 +53,10 @@ namespace gfx {
class ImageSkia;
}
+namespace mojo {
+class ApplicationDelegate;
+}
+
namespace net {
class CookieOptions;
class NetLog;
@@ -578,6 +582,13 @@ class CONTENT_EXPORT ContentBrowserClient {
ServiceRegistry* registry,
RenderFrameHost* render_frame_host) {}
+ using StaticMojoApplicationMap =
+ std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
+ // Registers in-process Mojo application loaders with the browser's global
+ // Mojo shell.
+ virtual void RegisterMojoApplications(StaticMojoApplicationMap* apps) {}
+
// Registers additional navigator.connect service factories available in a
// particular NavigatorConnectContext.
virtual void GetAdditionalNavigatorConnectServices(
diff --git a/content/public/browser/mojo_app_connection.h b/content/public/browser/mojo_app_connection.h
new file mode 100644
index 0000000..f7c0272
--- /dev/null
+++ b/content/public/browser/mojo_app_connection.h
@@ -0,0 +1,43 @@
+// Copyright 2015 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 CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
+#define CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+
+class GURL;
+
+namespace content {
+
+// This provides a way for arbitrary browser code to connect to Mojo apps. These
+// objects are not thread-safe but may be constructed and used on any single
+// thread.
+class CONTENT_EXPORT MojoAppConnection {
+ public:
+ virtual ~MojoAppConnection() {}
+
+ // Creates a new connection to the application at |url|. This may be called
+ // from any thread.
+ static scoped_ptr<MojoAppConnection> Create(const GURL& url);
+
+ // Connects to a service within the application.
+ template <typename Interface>
+ void ConnectToService(mojo::InterfacePtr<Interface>* proxy) {
+ ConnectToService(Interface::Name_, mojo::GetProxy(proxy).PassMessagePipe());
+ }
+
+ virtual void ConnectToService(const std::string& service_name,
+ mojo::ScopedMessagePipeHandle handle) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index fbe84ed..88c3916 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"-content",
"+content/public",
+ "+mojo/application",
"+v8/include/v8.h",
]
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
new file mode 100644
index 0000000..bebb7a7
--- /dev/null
+++ b/content/public/test/test_mojo_app.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 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/public/test/test_mojo_app.h"
+
+#include "base/logging.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+
+namespace content {
+
+const char kTestMojoAppUrl[] = "system:content_mojo_test";
+
+TestMojoApp::TestMojoApp() : service_binding_(this), app_(nullptr) {
+}
+
+TestMojoApp::~TestMojoApp() {
+}
+
+void TestMojoApp::Initialize(mojo::ApplicationImpl* app) {
+ app_ = app;
+}
+
+bool TestMojoApp::ConfigureIncomingConnection(
+ mojo::ApplicationConnection* connection) {
+ connection->AddService<TestMojoService>(this);
+ return true;
+}
+
+void TestMojoApp::Create(mojo::ApplicationConnection* connection,
+ mojo::InterfaceRequest<TestMojoService> request) {
+ DCHECK(!service_binding_.is_bound());
+ service_binding_.Bind(request.Pass());
+}
+
+void TestMojoApp::DoSomething(const DoSomethingCallback& callback) {
+ callback.Run();
+ DCHECK(app_);
+ app_->Terminate();
+}
+
+} // namespace content
diff --git a/content/public/test/test_mojo_app.h b/content/public/test/test_mojo_app.h
new file mode 100644
index 0000000..e01e7b5
--- /dev/null
+++ b/content/public/test/test_mojo_app.h
@@ -0,0 +1,50 @@
+// Copyright 2015 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 CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
+#define CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
+
+#include "base/macros.h"
+#include "content/public/test/test_mojo_service.mojom.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/interface_factory.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+extern const char kTestMojoAppUrl[];
+
+// Simple Mojo app which provides a TestMojoService impl. The app terminates
+// itself after its TestService fulfills a single DoSomething call.
+class TestMojoApp : public mojo::ApplicationDelegate,
+ public mojo::InterfaceFactory<TestMojoService>,
+ public TestMojoService {
+ public:
+ TestMojoApp();
+ ~TestMojoApp() override;
+
+ private:
+ // mojo::ApplicationDelegate:
+ void Initialize(mojo::ApplicationImpl* app) override;
+ bool ConfigureIncomingConnection(
+ mojo::ApplicationConnection* connection) override;
+
+ // mojo::InterfaceFactory<TestMojoService>:
+ void Create(mojo::ApplicationConnection* connection,
+ mojo::InterfaceRequest<TestMojoService> request) override;
+
+ // TestMojoService:
+ void DoSomething(const DoSomethingCallback& callback) override;
+
+ mojo::Binding<TestMojoService> service_binding_;
+
+ // Not owned.
+ mojo::ApplicationImpl* app_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMojoApp);
+};
+
+} // namespace
+
+#endif // CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
diff --git a/content/public/test/test_mojo_service.mojom b/content/public/test/test_mojo_service.mojom
new file mode 100644
index 0000000..e417916
--- /dev/null
+++ b/content/public/test/test_mojo_service.mojom
@@ -0,0 +1,9 @@
+// Copyright 2015 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.
+
+module content;
+
+interface TestMojoService {
+ DoSomething() => ();
+};
diff --git a/content/public/utility/BUILD.gn b/content/public/utility/BUILD.gn
index 999549a..1f3e987 100644
--- a/content/public/utility/BUILD.gn
+++ b/content/public/utility/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//content/utility/utility.gni")
+
# See //content/BUILD.gn for how this works.
group("utility") {
if (is_component_build) {
@@ -18,12 +20,9 @@ group("utility") {
source_set("utility_sources") {
visibility = [ "//content/*" ]
- sources = [
- "content_utility_client.cc",
- "content_utility_client.h",
- "utility_thread.cc",
- "utility_thread.h",
- ]
+ sources = rebase_path(content_utility_gypi_values.public_utility_sources,
+ ".",
+ "//content")
configs += [ "//content:content_implementation" ]
diff --git a/content/public/utility/content_utility_client.h b/content/public/utility/content_utility_client.h
index 8a333e7..b326eae 100644
--- a/content/public/utility/content_utility_client.h
+++ b/content/public/utility/content_utility_client.h
@@ -5,8 +5,18 @@
#ifndef CONTENT_PUBLIC_UTILITY_CONTENT_UTILITY_CLIENT_H_
#define CONTENT_PUBLIC_UTILITY_CONTENT_UTILITY_CLIENT_H_
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
#include "content/public/common/content_client.h"
+class GURL;
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
namespace content {
class ServiceRegistry;
@@ -14,6 +24,9 @@ class ServiceRegistry;
// Embedder API for participating in renderer logic.
class CONTENT_EXPORT ContentUtilityClient {
public:
+ using StaticMojoApplicationMap =
+ std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
virtual ~ContentUtilityClient() {}
// Notifies us that the UtilityThread has been created.
@@ -24,6 +37,9 @@ class CONTENT_EXPORT ContentUtilityClient {
// Registers Mojo services.
virtual void RegisterMojoServices(ServiceRegistry* registry) {}
+
+ // Registers Mojo applications.
+ virtual void RegisterMojoApplications(StaticMojoApplicationMap* apps) {}
};
} // namespace content
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 6066718..d505da3 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -170,6 +170,8 @@ static_library("content_shell_lib") {
"renderer/shell_content_renderer_client.h",
"renderer/shell_render_view_observer.cc",
"renderer/shell_render_view_observer.h",
+ "utility/shell_content_utility_client.cc",
+ "utility/shell_content_utility_client.h",
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 42fb382..5858071 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -27,6 +27,7 @@
#include "content/shell/common/shell_switches.h"
#include "content/shell/renderer/layout_test/layout_test_content_renderer_client.h"
#include "content/shell/renderer/shell_content_renderer_client.h"
+#include "content/shell/utility/shell_content_utility_client.h"
#include "media/base/media_switches.h"
#include "media/base/mime_util.h"
#include "net/cookies/cookie_monster.h"
@@ -346,4 +347,9 @@ ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() {
return renderer_client_.get();
}
+ContentUtilityClient* ShellMainDelegate::CreateContentUtilityClient() {
+ utility_client_.reset(new ShellContentUtilityClient);
+ return utility_client_.get();
+}
+
} // namespace content
diff --git a/content/shell/app/shell_main_delegate.h b/content/shell/app/shell_main_delegate.h
index 930009c..f8439bc 100644
--- a/content/shell/app/shell_main_delegate.h
+++ b/content/shell/app/shell_main_delegate.h
@@ -13,6 +13,7 @@
namespace content {
class ShellContentBrowserClient;
class ShellContentRendererClient;
+class ShellContentUtilityClient;
#if defined(OS_ANDROID)
class BrowserMainRunner;
@@ -33,12 +34,14 @@ class ShellMainDelegate : public ContentMainDelegate {
#endif
ContentBrowserClient* CreateContentBrowserClient() override;
ContentRendererClient* CreateContentRendererClient() override;
+ ContentUtilityClient* CreateContentUtilityClient() override;
static void InitializeResourceBundle();
private:
scoped_ptr<ShellContentBrowserClient> browser_client_;
scoped_ptr<ShellContentRendererClient> renderer_client_;
+ scoped_ptr<ShellContentUtilityClient> utility_client_;
ShellContentClient content_client_;
#if defined(OS_ANDROID)
diff --git a/content/shell/utility/DEPS b/content/shell/utility/DEPS
new file mode 100644
index 0000000..72513eb
--- /dev/null
+++ b/content/shell/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/shell",
+]
diff --git a/content/shell/utility/shell_content_utility_client.cc b/content/shell/utility/shell_content_utility_client.cc
new file mode 100644
index 0000000..d6c2982
--- /dev/null
+++ b/content/shell/utility/shell_content_utility_client.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 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/shell/utility/shell_content_utility_client.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/test/test_mojo_app.h"
+#include "mojo/shell/static_application_loader.h"
+
+namespace content {
+
+namespace {
+
+scoped_ptr<mojo::ApplicationDelegate> CreateTestApp() {
+ return scoped_ptr<mojo::ApplicationDelegate>(new TestMojoApp);
+}
+
+} // namespace
+
+ShellContentUtilityClient::~ShellContentUtilityClient() {
+}
+
+void ShellContentUtilityClient::RegisterMojoApplications(
+ StaticMojoApplicationMap* apps) {
+ apps->insert(
+ std::make_pair(GURL(kTestMojoAppUrl), base::Bind(&CreateTestApp)));
+}
+
+} // namespace content
diff --git a/content/shell/utility/shell_content_utility_client.h b/content/shell/utility/shell_content_utility_client.h
new file mode 100644
index 0000000..2479f58
--- /dev/null
+++ b/content/shell/utility/shell_content_utility_client.h
@@ -0,0 +1,22 @@
+// Copyright 2015 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 CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
+#define CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
+
+#include "content/public/utility/content_utility_client.h"
+
+namespace content {
+
+class ShellContentUtilityClient : public ContentUtilityClient {
+ public:
+ ~ShellContentUtilityClient() override;
+
+ // ContentUtilityClient:
+ void RegisterMojoApplications(StaticMojoApplicationMap* apps) override;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 848dea1..c254b4e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -55,6 +55,7 @@ source_set("test_support") {
public_deps += [ "//third_party/WebKit/public:blink" ]
deps += [
+ ":content_test_mojo_bindings",
"//components/scheduler:scheduler",
"//components/scheduler:test_support",
"//content/browser/speech/proto",
@@ -68,6 +69,8 @@ source_set("test_support") {
"//cc:test_support",
"//ipc/mojo",
"//media",
+ "//mojo/application/public/cpp:cpp_for_chromium",
+ "//mojo/environment:chromium",
"//ppapi/host",
"//ppapi/proxy",
"//ppapi/proxy:test_support",
@@ -201,6 +204,12 @@ source_set("browsertest_support") {
}
}
+mojom("content_test_mojo_bindings") {
+ sources = [
+ "../public/test/test_mojo_service.mojom",
+ ]
+}
+
mojom("web_ui_test_mojo_bindings") {
sources = [
"data/web_ui_test_mojo_bindings.mojom",
@@ -279,6 +288,7 @@ if (!is_mac) {
"//media/audio:test_support",
"//media/base:test_support",
"//media:shared_memory_support",
+ "//mojo/application/public/cpp:cpp_for_chromium",
"//mojo/environment:chromium",
"//net:test_support",
"//ppapi/host",
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn
index 5767b98..93dae8f 100644
--- a/content/utility/BUILD.gn
+++ b/content/utility/BUILD.gn
@@ -19,8 +19,14 @@ source_set("utility") {
"//content:export",
"//content/public/child:child_sources",
"//content/public/common:common_sources",
+ "//content/public/common:mojo_bindings",
"//courgette:courgette_lib",
+ "//mojo/application/public/cpp:cpp_for_chromium",
"//mojo/application/public/interfaces",
+ "//mojo/common",
+ "//mojo/shell",
"//third_party/WebKit/public:blink_headers",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
+ "//url",
]
}
diff --git a/content/utility/DEPS b/content/utility/DEPS
index 47166e2..8b49f0f 100644
--- a/content/utility/DEPS
+++ b/content/utility/DEPS
@@ -2,5 +2,7 @@ include_rules = [
"+components/scheduler/child",
"+content/child",
"+content/public/utility",
+ "+mojo/application",
+ "+mojo/shell",
"+sandbox/win/src",
]
diff --git a/content/utility/utility_process_control_impl.cc b/content/utility/utility_process_control_impl.cc
new file mode 100644
index 0000000..5d12a2e
--- /dev/null
+++ b/content/utility/utility_process_control_impl.cc
@@ -0,0 +1,54 @@
+// Copyright 2015 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/utility/utility_process_control_impl.h"
+
+#include "base/bind.h"
+#include "base/stl_util.h"
+#include "content/public/common/content_client.h"
+#include "content/public/utility/content_utility_client.h"
+#include "content/public/utility/utility_thread.h"
+#include "mojo/shell/static_application_loader.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+// Called when a static application terminates.
+void QuitProcess() {
+ UtilityThread::Get()->ReleaseProcessIfNeeded();
+}
+
+} // namespace
+
+UtilityProcessControlImpl::UtilityProcessControlImpl() {
+ ContentUtilityClient::StaticMojoApplicationMap apps;
+ GetContentClient()->utility()->RegisterMojoApplications(&apps);
+ for (const auto& entry : apps) {
+ url_to_loader_map_[entry.first] = new mojo::shell::StaticApplicationLoader(
+ entry.second, base::Bind(&QuitProcess));
+ }
+}
+
+UtilityProcessControlImpl::~UtilityProcessControlImpl() {
+ STLDeleteValues(&url_to_loader_map_);
+}
+
+void UtilityProcessControlImpl::LoadApplication(
+ const mojo::String& url,
+ mojo::InterfaceRequest<mojo::Application> request,
+ const LoadApplicationCallback& callback) {
+ GURL application_url = GURL(url.To<std::string>());
+ auto it = url_to_loader_map_.find(application_url);
+ if (it == url_to_loader_map_.end()) {
+ callback.Run(false);
+ return;
+ }
+
+ callback.Run(true);
+ it->second->Load(application_url, request.Pass());
+}
+
+} // namespace content
diff --git a/content/utility/utility_process_control_impl.h b/content/utility/utility_process_control_impl.h
new file mode 100644
index 0000000..dcc0a4d
--- /dev/null
+++ b/content/utility/utility_process_control_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2015 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 UTILITY_PROCESS_CONTROL_IMPL_H_
+#define UTILITY_PROCESS_CONTROL_IMPL_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/process_control.mojom.h"
+#include "mojo/application/public/interfaces/application.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+class GURL;
+
+namespace mojo {
+namespace shell {
+class ApplicationLoader;
+} // namespace shell
+} // namespace mojo
+
+namespace content {
+
+// Implementation of the ProcessControl interface. Exposed to the browser via
+// the utility process's ServiceRegistry.
+class UtilityProcessControlImpl : public ProcessControl {
+ public:
+ UtilityProcessControlImpl();
+ ~UtilityProcessControlImpl() override;
+
+ using URLToLoaderMap = std::map<GURL, mojo::shell::ApplicationLoader*>;
+
+ // ProcessControl:
+ void LoadApplication(const mojo::String& url,
+ mojo::InterfaceRequest<mojo::Application> request,
+ const LoadApplicationCallback& callback) override;
+
+ private:
+ URLToLoaderMap url_to_loader_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(UtilityProcessControlImpl);
+};
+
+} // namespace content
+
+#endif // UTILITY_PROCESS_CONTROL_IMPL_H_
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index 1a020ea..00ebc6e 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -15,6 +15,7 @@
#include "content/public/common/content_switches.h"
#include "content/public/utility/content_utility_client.h"
#include "content/utility/utility_blink_platform_impl.h"
+#include "content/utility/utility_process_control_impl.h"
#include "ipc/ipc_sync_channel.h"
#include "third_party/WebKit/public/web/WebKit.h"
@@ -85,6 +86,11 @@ void UtilityThreadImpl::Init() {
blink::initialize(blink_platform_impl_.get());
}
GetContentClient()->utility()->UtilityThreadStarted();
+
+ process_control_.reset(new UtilityProcessControlImpl);
+ service_registry()->AddService(base::Bind(
+ &UtilityThreadImpl::BindProcessControlRequest, base::Unretained(this)));
+
GetContentClient()->utility()->RegisterMojoServices(service_registry());
}
@@ -135,4 +141,10 @@ void UtilityThreadImpl::OnLoadPlugins(
}
#endif
+void UtilityThreadImpl::BindProcessControlRequest(
+ mojo::InterfaceRequest<ProcessControl> request) {
+ DCHECK(process_control_);
+ process_control_bindings_.AddBinding(process_control_.get(), request.Pass());
+}
+
} // namespace content
diff --git a/content/utility/utility_thread_impl.h b/content/utility/utility_thread_impl.h
index 3b1d66d..74908ca 100644
--- a/content/utility/utility_thread_impl.h
+++ b/content/utility/utility_thread_impl.h
@@ -10,9 +10,12 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "content/child/child_thread_impl.h"
#include "content/common/content_export.h"
+#include "content/common/process_control.mojom.h"
#include "content/public/utility/utility_thread.h"
+#include "mojo/common/weak_binding_set.h"
namespace base {
class FilePath;
@@ -21,6 +24,7 @@ class FilePath;
namespace content {
class BlinkPlatformImpl;
class UtilityBlinkPlatformImpl;
+class UtilityProcessControlImpl;
#if defined(COMPILER_MSVC)
// See explanation for other RenderViewHostImpl which is the same issue.
@@ -54,11 +58,20 @@ class UtilityThreadImpl : public UtilityThread,
void OnLoadPlugins(const std::vector<base::FilePath>& plugin_paths);
#endif
+ void BindProcessControlRequest(
+ mojo::InterfaceRequest<content::ProcessControl> request);
+
// True when we're running in batch mode.
bool batch_mode_;
scoped_ptr<UtilityBlinkPlatformImpl> blink_platform_impl_;
+ // Process control for Mojo application hosting.
+ scoped_ptr<UtilityProcessControlImpl> process_control_;
+
+ // Bindings to the ProcessControl impl.
+ mojo::WeakBindingSet<ProcessControl> process_control_bindings_;
+
DISALLOW_COPY_AND_ASSIGN(UtilityThreadImpl);
};
diff --git a/mojo/application/public/cpp/BUILD.gn b/mojo/application/public/cpp/BUILD.gn
index e393615..809abd9 100644
--- a/mojo/application/public/cpp/BUILD.gn
+++ b/mojo/application/public/cpp/BUILD.gn
@@ -6,6 +6,21 @@ import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
# GYP version: mojo/mojo_base.gyp:mojo_application_base
source_set("cpp") {
+ deps = [
+ ":sources",
+ ":init_commandline",
+ ]
+}
+
+# Like the target above, but without special commandline initialization that
+# apps use.
+source_set("cpp_for_chromium") {
+ deps = [
+ ":sources",
+ ]
+}
+
+source_set("sources") {
sources = [
"app_lifetime_helper.h",
"application_connection.h",
@@ -40,6 +55,12 @@ source_set("cpp") {
]
}
+source_set("init_commandline") {
+ sources = [
+ "lib/init_commandline.cc",
+ ]
+}
+
source_set("content_handler") {
sources = [
"content_handler_factory.h",
diff --git a/mojo/application/public/cpp/application_runner.h b/mojo/application/public/cpp/application_runner.h
index 0341c90..90329a9 100644
--- a/mojo/application/public/cpp/application_runner.h
+++ b/mojo/application/public/cpp/application_runner.h
@@ -37,6 +37,13 @@ class ApplicationRunner {
// Once the various parameters have been set above, use Run to initialize an
// ApplicationImpl wired to the provided delegate, and run a MessageLoop until
// the application exits.
+ //
+ // Iff |init_base| is true, the runner will perform some initialization of
+ // base globals (e.g. CommandLine and AtExitManager) before starting the
+ // application.
+ MojoResult Run(MojoHandle shell_handle, bool init_base);
+
+ // Calls Run above with |init_base| set to |true|.
MojoResult Run(MojoHandle shell_handle);
private:
diff --git a/mojo/application/public/cpp/lib/application_runner.cc b/mojo/application/public/cpp/lib/application_runner.cc
index 5afd825a..cacead2 100644
--- a/mojo/application/public/cpp/lib/application_runner.cc
+++ b/mojo/application/public/cpp/lib/application_runner.cc
@@ -13,20 +13,11 @@
#include "mojo/application/public/cpp/application_impl.h"
#include "mojo/common/message_pump_mojo.h"
-int g_argc;
-const char* const* g_argv;
-#if !defined(OS_WIN)
-extern "C" {
-__attribute__((visibility("default"))) void InitCommandLineArgs(
- int argc, const char* const* argv) {
- g_argc = argc;
- g_argv = argv;
-}
-}
-#endif
-
namespace mojo {
+int g_application_runner_argc;
+const char* const* g_application_runner_argv;
+
ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate)
: delegate_(scoped_ptr<ApplicationDelegate>(delegate)),
message_loop_type_(base::MessageLoop::TYPE_CUSTOM),
@@ -35,7 +26,7 @@ ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate)
ApplicationRunner::~ApplicationRunner() {}
void ApplicationRunner::InitBaseCommandLine() {
- base::CommandLine::Init(g_argc, g_argv);
+ base::CommandLine::Init(g_application_runner_argc, g_application_runner_argv);
}
void ApplicationRunner::set_message_loop_type(base::MessageLoop::Type type) {
@@ -45,16 +36,19 @@ void ApplicationRunner::set_message_loop_type(base::MessageLoop::Type type) {
message_loop_type_ = type;
}
-MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle,
+ bool init_base) {
DCHECK(!has_run_);
has_run_ = true;
- InitBaseCommandLine();
- base::AtExitManager at_exit;
-
+ scoped_ptr<base::AtExitManager> at_exit;
+ if (init_base) {
+ InitBaseCommandLine();
+ at_exit.reset(new base::AtExitManager);
#ifndef NDEBUG
- base::debug::EnableInProcessStackDumping();
+ base::debug::EnableInProcessStackDumping();
#endif
+ }
{
scoped_ptr<base::MessageLoop> loop;
@@ -79,4 +73,8 @@ MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
return MOJO_RESULT_OK;
}
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
+ return Run(application_request_handle, true);
+}
+
} // namespace mojo
diff --git a/mojo/application/public/cpp/lib/init_commandline.cc b/mojo/application/public/cpp/lib/init_commandline.cc
new file mode 100644
index 0000000..a61797b
--- /dev/null
+++ b/mojo/application/public/cpp/lib/init_commandline.cc
@@ -0,0 +1,22 @@
+// Copyright 2014 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 "build/build_config.h"
+
+namespace mojo {
+
+extern int g_application_runner_argc;
+extern const char* const* g_application_runner_argv;
+
+}
+
+#if !defined(OS_WIN)
+extern "C" {
+__attribute__((visibility("default"))) void InitCommandLineArgs(
+ int argc, const char* const* argv) {
+ mojo::g_application_runner_argc = argc;
+ mojo::g_application_runner_argv = argv;
+}
+}
+#endif
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 3e7ced6..70948a1 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -185,10 +185,10 @@
],
},
'dependencies': [
- 'mojo_services.gyp:network_service_bindings_mojom',
+ 'mojo_services.gyp:network_service_bindings_generation',
],
'export_dependent_settings': [
- 'mojo_services.gyp:network_service_bindings_mojom',
+ 'mojo_services.gyp:network_service_bindings_generation',
],
'includes': [ '../third_party/mojo/mojom_bindings_generator_explicit.gypi' ],
},
@@ -221,9 +221,7 @@
],
'dependencies': [
'mojo_application_bindings',
- ],
- 'export_dependent_settings': [
- 'mojo_application_bindings',
+ 'mojo_common_lib',
],
},
{
@@ -232,10 +230,11 @@
'type': 'static_library',
'dependencies': [
'mojo_application_bindings_mojom',
+ 'mojo_services.gyp:network_service_bindings_lib',
'../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
],
'export_dependent_settings': [
- '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ 'mojo_services.gyp:network_service_bindings_lib',
],
},
{
diff --git a/mojo/mojo_services.gyp b/mojo/mojo_services.gyp
index 00d789d..2e7b206 100644
--- a/mojo/mojo_services.gyp
+++ b/mojo/mojo_services.gyp
@@ -29,10 +29,19 @@
],
}, {
# GN version: //mojo/services/network/public/interfaces
- 'target_name': 'network_service_bindings_libs',
+ 'target_name': 'network_service_bindings_lib',
'type': 'static_library',
'dependencies': [
'network_service_bindings_mojom',
],
+ }, {
+ # Target used to depend only on the bindings generation action, not on any
+ # outputs.
+ 'target_name': 'network_service_bindings_generation',
+ 'type': 'none',
+ 'hard_dependency': 1,
+ 'dependencies': [
+ 'network_service_bindings_mojom',
+ ],
}],
}
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp
index d39652c..0569a6b 100644
--- a/mojo/mojo_shell.gyp
+++ b/mojo/mojo_shell.gyp
@@ -25,6 +25,8 @@
'shell/query_util.h',
'shell/shell_impl.cc',
'shell/shell_impl.h',
+ 'shell/static_application_loader.cc',
+ 'shell/static_application_loader.h',
'shell/switches.cc',
'shell/switches.h',
'util/filename_util.cc',
@@ -34,12 +36,12 @@
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'<(DEPTH)/crypto/crypto.gyp:crypto',
- '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings_mojom',
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
'<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
'<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium',
'<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
'<(DEPTH)/mojo/mojo_services.gyp:network_service_bindings_lib',
- '<(DEPTH)/third_party/mojo/mojo_edk.gyp:mojo_system_impl',
'<(DEPTH)/url/url.gyp:url_lib',
],
}, {
@@ -58,7 +60,6 @@
'<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium',
'<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
'<(DEPTH)/third_party/mojo/mojo_edk.gyp:mojo_run_all_unittests',
- '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_application_base',
'<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/url/url.gyp:url_lib',
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn
index 331af9a..2e599b6f 100644
--- a/mojo/shell/BUILD.gn
+++ b/mojo/shell/BUILD.gn
@@ -26,6 +26,8 @@ source_set("shell") {
"query_util.h",
"shell_impl.cc",
"shell_impl.h",
+ "static_application_loader.cc",
+ "static_application_loader.h",
"switches.cc",
"switches.h",
]
diff --git a/mojo/shell/static_application_loader.cc b/mojo/shell/static_application_loader.cc
new file mode 100644
index 0000000..a0f90a8
--- /dev/null
+++ b/mojo/shell/static_application_loader.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 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 "mojo/shell/static_application_loader.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/simple_thread.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_runner.h"
+#include "mojo/application/public/interfaces/application.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace mojo {
+namespace shell {
+
+namespace {
+
+class RunnerThread : public base::SimpleThread {
+ public:
+ RunnerThread(const GURL& url,
+ InterfaceRequest<Application> request,
+ scoped_refptr<base::TaskRunner> exit_task_runner,
+ const base::Closure& exit_callback,
+ const StaticApplicationLoader::ApplicationFactory& factory)
+ : base::SimpleThread("Mojo Application: " + url.spec()),
+ request_(request.Pass()),
+ exit_task_runner_(exit_task_runner),
+ exit_callback_(exit_callback),
+ factory_(factory) {}
+
+ void Run() override {
+ scoped_ptr<ApplicationRunner> runner(
+ new ApplicationRunner(factory_.Run().release()));
+ runner->Run(request_.PassMessagePipe().release().value(),
+ false /* init_base */);
+ exit_task_runner_->PostTask(FROM_HERE, exit_callback_);
+ }
+
+ private:
+ InterfaceRequest<Application> request_;
+ scoped_refptr<base::TaskRunner> exit_task_runner_;
+ base::Closure exit_callback_;
+ StaticApplicationLoader::ApplicationFactory factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RunnerThread);
+};
+
+} // namespace
+
+StaticApplicationLoader::StaticApplicationLoader(
+ const ApplicationFactory& factory)
+ : StaticApplicationLoader(factory, base::Closure()) {
+}
+
+StaticApplicationLoader::StaticApplicationLoader(
+ const ApplicationFactory& factory,
+ const base::Closure& quit_callback)
+ : factory_(factory), quit_callback_(quit_callback), weak_factory_(this) {
+}
+
+StaticApplicationLoader::~StaticApplicationLoader() {
+ if (thread_)
+ StopAppThread();
+}
+
+void StaticApplicationLoader::Load(const GURL& url,
+ InterfaceRequest<Application> request) {
+ if (thread_)
+ return;
+
+ // If the application's thread quits on its own before this loader dies, we
+ // reset the Thread object, allowing future Load requests to be fulfilled
+ // with a new app instance.
+ auto exit_callback = base::Bind(&StaticApplicationLoader::StopAppThread,
+ weak_factory_.GetWeakPtr());
+ thread_.reset(
+ new RunnerThread(url, request.Pass(), base::ThreadTaskRunnerHandle::Get(),
+ exit_callback, factory_));
+ thread_->Start();
+}
+
+void StaticApplicationLoader::StopAppThread() {
+ thread_->Join();
+ thread_.reset();
+ if (!quit_callback_.is_null())
+ quit_callback_.Run();
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/shell/static_application_loader.h b/mojo/shell/static_application_loader.h
new file mode 100644
index 0000000..cbf611a
--- /dev/null
+++ b/mojo/shell/static_application_loader.h
@@ -0,0 +1,69 @@
+// Copyright 2015 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 MOJO_SHELL_STATIC_APPLICATION_LOADER_H_
+#define MOJO_SHELL_STATIC_APPLICATION_LOADER_H_
+
+#include <list>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/shell/application_loader.h"
+
+namespace base {
+class SimpleThread;
+}
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
+namespace mojo {
+namespace shell {
+
+// An ApplicationLoader which loads a single type of app from a given
+// ApplicationDelegate factory. A Load() request is fulfilled by creating an
+// instance of the app on a new thread. Only one instance of the app will run at
+// a time. Any Load requests received while the app is running will be dropped.
+class StaticApplicationLoader : public mojo::shell::ApplicationLoader {
+ public:
+ using ApplicationFactory =
+ base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>;
+
+ // Constructs a static loader for |factory|.
+ explicit StaticApplicationLoader(const ApplicationFactory& factory);
+
+ // Constructs a static loader for |factory| with a closure that will be called
+ // when the loaded application quits.
+ StaticApplicationLoader(const ApplicationFactory& factory,
+ const base::Closure& quit_callback);
+
+ ~StaticApplicationLoader() override;
+
+ // mojo::shell::ApplicationLoader:
+ void Load(const GURL& url,
+ mojo::InterfaceRequest<mojo::Application> request) override;
+
+ private:
+ void StopAppThread();
+
+ // The factory used t create new instances of the application delegate.
+ ApplicationFactory factory_;
+
+ // If not null, this is run when the loaded application quits.
+ base::Closure quit_callback_;
+
+ // Thread for the application if currently running.
+ scoped_ptr<base::SimpleThread> thread_;
+
+ base::WeakPtrFactory<StaticApplicationLoader> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticApplicationLoader);
+};
+
+} // namespace shell
+} // namespace mojo
+
+#endif // MOJO_SHELL_STATIC_APPLICATION_LOADER_H_