summaryrefslogtreecommitdiff
path: root/chromium/services
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-07-14 17:41:05 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2016-08-04 12:37:36 +0000
commit399c965b6064c440ddcf4015f5f8e9d131c7a0a6 (patch)
tree6b06b60ff365abef0e13b3503d593a0df48d20e8 /chromium/services
parent7366110654eec46f21b6824f302356426f48cd74 (diff)
downloadqtwebengine-chromium-399c965b6064c440ddcf4015f5f8e9d131c7a0a6.tar.gz
BASELINE: Update Chromium to 52.0.2743.76 and Ninja to 1.7.1
Change-Id: I382f51b959689505a60f8b707255ecb344f7d8b4 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/services')
-rw-r--r--chromium/services/DEPS6
-rw-r--r--chromium/services/README.md38
-rw-r--r--chromium/services/catalog/BUILD.gn70
-rw-r--r--chromium/services/catalog/DEPS3
-rw-r--r--chromium/services/catalog/OWNERS2
-rw-r--r--chromium/services/catalog/catalog.cc159
-rw-r--r--chromium/services/catalog/catalog.h105
-rw-r--r--chromium/services/catalog/constants.cc11
-rw-r--r--chromium/services/catalog/constants.h14
-rw-r--r--chromium/services/catalog/data/capabilities11
-rw-r--r--chromium/services/catalog/data/instance7
-rw-r--r--chromium/services/catalog/data/malformed5
-rw-r--r--chromium/services/catalog/data/serialization18
-rw-r--r--chromium/services/catalog/data/simple6
-rw-r--r--chromium/services/catalog/data/wildcard_interfaces12
-rw-r--r--chromium/services/catalog/entry.cc298
-rw-r--r--chromium/services/catalog/entry.h85
-rw-r--r--chromium/services/catalog/entry_unittest.cc107
-rw-r--r--chromium/services/catalog/instance.cc179
-rw-r--r--chromium/services/catalog/instance.h93
-rw-r--r--chromium/services/catalog/manifest.json16
-rw-r--r--chromium/services/catalog/manifest_provider.h29
-rw-r--r--chromium/services/catalog/public/cpp/BUILD.gn18
-rw-r--r--chromium/services/catalog/public/cpp/resource_loader.cc63
-rw-r--r--chromium/services/catalog/public/cpp/resource_loader.h49
-rw-r--r--chromium/services/catalog/public/interfaces/BUILD.gn11
-rw-r--r--chromium/services/catalog/public/interfaces/OWNERS13
-rw-r--r--chromium/services/catalog/public/interfaces/catalog.mojom28
-rw-r--r--chromium/services/catalog/reader.cc216
-rw-r--r--chromium/services/catalog/reader.h70
-rw-r--r--chromium/services/catalog/store.cc30
-rw-r--r--chromium/services/catalog/store.h55
-rw-r--r--chromium/services/catalog/types.h22
-rw-r--r--chromium/services/navigation/BUILD.gn143
-rw-r--r--chromium/services/navigation/DEPS9
-rw-r--r--chromium/services/navigation/content_client/BUILD.gn24
-rw-r--r--chromium/services/navigation/content_client/browser_main_parts.cc43
-rw-r--r--chromium/services/navigation/content_client/browser_main_parts.h59
-rw-r--r--chromium/services/navigation/content_client/content_browser_client.cc52
-rw-r--r--chromium/services/navigation/content_client/content_browser_client.h36
-rw-r--r--chromium/services/navigation/content_client/main_delegate.cc44
-rw-r--r--chromium/services/navigation/content_client/main_delegate.h42
-rw-r--r--chromium/services/navigation/embedder_manifest.json6
-rw-r--r--chromium/services/navigation/main.cc53
-rw-r--r--chromium/services/navigation/manifest.json14
-rw-r--r--chromium/services/navigation/navigation.cc54
-rw-r--r--chromium/services/navigation/navigation.h57
-rw-r--r--chromium/services/navigation/navigation_unittest.cc77
-rw-r--r--chromium/services/navigation/public/interfaces/BUILD.gn17
-rw-r--r--chromium/services/navigation/public/interfaces/view.mojom42
-rw-r--r--chromium/services/navigation/unittest_manifest.json13
-rw-r--r--chromium/services/navigation/view_impl.cc139
-rw-r--r--chromium/services/navigation/view_impl.h89
-rw-r--r--chromium/services/shell/BUILD.gn58
-rw-r--r--chromium/services/shell/OWNERS5
-rw-r--r--chromium/services/shell/background/BUILD.gn42
-rw-r--r--chromium/services/shell/background/DEPS3
-rw-r--r--chromium/services/shell/background/background_shell.cc174
-rw-r--r--chromium/services/shell/background/background_shell.h67
-rw-r--r--chromium/services/shell/background/background_shell_main.cc41
-rw-r--r--chromium/services/shell/background/background_shell_main.h12
-rw-r--r--chromium/services/shell/connect_params.cc12
-rw-r--r--chromium/services/shell/connect_params.h77
-rw-r--r--chromium/services/shell/connect_util.cc31
-rw-r--r--chromium/services/shell/connect_util.h47
-rw-r--r--chromium/services/shell/manifest.json29
-rw-r--r--chromium/services/shell/mojo_shell_unittests.isolate23
-rw-r--r--chromium/services/shell/native_runner.h48
-rw-r--r--chromium/services/shell/native_runner_delegate.h29
-rw-r--r--chromium/services/shell/public/cpp/BUILD.gn89
-rw-r--r--chromium/services/shell/public/cpp/application_runner.h76
-rw-r--r--chromium/services/shell/public/cpp/capabilities.h77
-rw-r--r--chromium/services/shell/public/cpp/connect.h25
-rw-r--r--chromium/services/shell/public/cpp/connection.h147
-rw-r--r--chromium/services/shell/public/cpp/connector.h104
-rw-r--r--chromium/services/shell/public/cpp/identity.h60
-rw-r--r--chromium/services/shell/public/cpp/interface_binder.h30
-rw-r--r--chromium/services/shell/public/cpp/interface_factory.h28
-rw-r--r--chromium/services/shell/public/cpp/interface_factory_impl.h49
-rw-r--r--chromium/services/shell/public/cpp/interface_registry.h112
-rw-r--r--chromium/services/shell/public/cpp/lib/application_runner.cc91
-rw-r--r--chromium/services/shell/public/cpp/lib/capabilities.cc85
-rw-r--r--chromium/services/shell/public/cpp/lib/connection_impl.cc129
-rw-r--r--chromium/services/shell/public/cpp/lib/connection_impl.h84
-rw-r--r--chromium/services/shell/public/cpp/lib/connector_impl.cc94
-rw-r--r--chromium/services/shell/public/cpp/lib/connector_impl.h39
-rw-r--r--chromium/services/shell/public/cpp/lib/identity.cc65
-rw-r--r--chromium/services/shell/public/cpp/lib/init_commandline.cc22
-rw-r--r--chromium/services/shell/public/cpp/lib/initialize_base_and_icu.cc54
-rw-r--r--chromium/services/shell/public/cpp/lib/interface_factory_binder.h39
-rw-r--r--chromium/services/shell/public/cpp/lib/interface_registry.cc62
-rw-r--r--chromium/services/shell/public/cpp/lib/names.cc46
-rw-r--r--chromium/services/shell/public/cpp/lib/shell_client.cc22
-rw-r--r--chromium/services/shell/public/cpp/lib/shell_connection.cc105
-rw-r--r--chromium/services/shell/public/cpp/lib/shell_connection_ref.cc87
-rw-r--r--chromium/services/shell/public/cpp/lib/shell_test.cc81
-rw-r--r--chromium/services/shell/public/cpp/names.h56
-rw-r--r--chromium/services/shell/public/cpp/shell_client.h60
-rw-r--r--chromium/services/shell/public/cpp/shell_connection.h107
-rw-r--r--chromium/services/shell/public/cpp/shell_connection_ref.h59
-rw-r--r--chromium/services/shell/public/cpp/shell_test.h112
-rw-r--r--chromium/services/shell/public/interfaces/BUILD.gn22
-rw-r--r--chromium/services/shell/public/interfaces/OWNERS13
-rw-r--r--chromium/services/shell/public/interfaces/capabilities.mojom47
-rw-r--r--chromium/services/shell/public/interfaces/connector.mojom144
-rw-r--r--chromium/services/shell/public/interfaces/interface_provider.mojom17
-rw-r--r--chromium/services/shell/public/interfaces/shell.mojom41
-rw-r--r--chromium/services/shell/public/interfaces/shell_client.mojom78
-rw-r--r--chromium/services/shell/public/interfaces/shell_client_factory.mojom13
-rw-r--r--chromium/services/shell/public/interfaces/shell_resolver.mojom38
-rw-r--r--chromium/services/shell/public/java/BUILD.gn21
-rw-r--r--chromium/services/shell/runner/BUILD.gn25
-rw-r--r--chromium/services/shell/runner/child/BUILD.gn32
-rw-r--r--chromium/services/shell/runner/child/manifest.json10
-rw-r--r--chromium/services/shell/runner/child/test_native_main.cc70
-rw-r--r--chromium/services/shell/runner/child/test_native_main.h16
-rw-r--r--chromium/services/shell/runner/common/BUILD.gn23
-rw-r--r--chromium/services/shell/runner/common/client_util.cc36
-rw-r--r--chromium/services/shell/runner/common/client_util.h30
-rw-r--r--chromium/services/shell/runner/common/switches.cc21
-rw-r--r--chromium/services/shell/runner/common/switches.h18
-rw-r--r--chromium/services/shell/runner/host/BUILD.gn126
-rw-r--r--chromium/services/shell/runner/host/DEPS3
-rw-r--r--chromium/services/shell/runner/host/OWNERS1
-rw-r--r--chromium/services/shell/runner/host/child_process.cc126
-rw-r--r--chromium/services/shell/runner/host/child_process.h15
-rw-r--r--chromium/services/shell/runner/host/child_process_base.cc70
-rw-r--r--chromium/services/shell/runner/host/child_process_base.h21
-rw-r--r--chromium/services/shell/runner/host/child_process_host.cc210
-rw-r--r--chromium/services/shell/runner/host/child_process_host.h98
-rw-r--r--chromium/services/shell/runner/host/child_process_host_unittest.cc109
-rw-r--r--chromium/services/shell/runner/host/host_unittests.cc36
-rw-r--r--chromium/services/shell/runner/host/in_process_native_runner.cc95
-rw-r--r--chromium/services/shell/runner/host/in_process_native_runner.h70
-rw-r--r--chromium/services/shell/runner/host/in_process_native_runner_unittest.cc16
-rw-r--r--chromium/services/shell/runner/host/linux_sandbox.cc167
-rw-r--r--chromium/services/shell/runner/host/linux_sandbox.h51
-rw-r--r--chromium/services/shell/runner/host/mach_broker.cc43
-rw-r--r--chromium/services/shell/runner/host/mach_broker.h52
-rw-r--r--chromium/services/shell/runner/host/native_application_support.cc106
-rw-r--r--chromium/services/shell/runner/host/native_application_support.h38
-rw-r--r--chromium/services/shell/runner/host/out_of_process_native_runner.cc75
-rw-r--r--chromium/services/shell/runner/host/out_of_process_native_runner.h74
-rw-r--r--chromium/services/shell/runner/init.cc98
-rw-r--r--chromium/services/shell/runner/init.h23
-rw-r--r--chromium/services/shell/shell.cc792
-rw-r--r--chromium/services/shell/shell.gyp205
-rw-r--r--chromium/services/shell/shell.h172
-rw-r--r--chromium/services/shell/shell_public.gyp73
-rw-r--r--chromium/services/shell/standalone/BUILD.gn60
-rw-r--r--chromium/services/shell/standalone/DEPS5
-rw-r--r--chromium/services/shell/standalone/context.cc262
-rw-r--r--chromium/services/shell/standalone/context.h85
-rw-r--r--chromium/services/shell/standalone/desktop/launcher_process.cc57
-rw-r--r--chromium/services/shell/standalone/desktop/launcher_process.h17
-rw-r--r--chromium/services/shell/standalone/desktop/main.cc9
-rw-r--r--chromium/services/shell/standalone/desktop/main_helper.cc49
-rw-r--r--chromium/services/shell/standalone/desktop/main_helper.h15
-rw-r--r--chromium/services/shell/standalone/tracer.cc162
-rw-r--r--chromium/services/shell/standalone/tracer.h101
-rw-r--r--chromium/services/shell/switches.cc17
-rw-r--r--chromium/services/shell/switches.h22
-rw-r--r--chromium/services/tracing/BUILD.gn47
-rw-r--r--chromium/services/tracing/OWNERS1
-rw-r--r--chromium/services/tracing/main.cc12
-rw-r--r--chromium/services/tracing/manifest.json16
-rw-r--r--chromium/services/tracing/public/cpp/BUILD.gn21
-rw-r--r--chromium/services/tracing/public/cpp/switches.cc22
-rw-r--r--chromium/services/tracing/public/cpp/switches.h24
-rw-r--r--chromium/services/tracing/public/cpp/trace_provider_impl.cc102
-rw-r--r--chromium/services/tracing/public/cpp/trace_provider_impl.h51
-rw-r--r--chromium/services/tracing/public/cpp/tracing_impl.cc75
-rw-r--r--chromium/services/tracing/public/cpp/tracing_impl.h52
-rw-r--r--chromium/services/tracing/public/interfaces/BUILD.gn11
-rw-r--r--chromium/services/tracing/public/interfaces/OWNERS13
-rw-r--r--chromium/services/tracing/public/interfaces/tracing.mojom62
-rw-r--r--chromium/services/tracing/trace_data_sink.cc32
-rw-r--r--chromium/services/tracing/trace_data_sink.h31
-rw-r--r--chromium/services/tracing/trace_recorder_impl.cc31
-rw-r--r--chromium/services/tracing/trace_recorder_impl.h43
-rw-r--r--chromium/services/tracing/tracing.gyp61
-rw-r--r--chromium/services/tracing/tracing_app.cc186
-rw-r--r--chromium/services/tracing/tracing_app.h82
-rw-r--r--chromium/services/user/BUILD.gn42
-rw-r--r--chromium/services/user/DEPS5
-rw-r--r--chromium/services/user/OWNERS1
-rw-r--r--chromium/services/user/manifest.json11
-rw-r--r--chromium/services/user/public/cpp/BUILD.gn10
-rw-r--r--chromium/services/user/public/cpp/constants.cc11
-rw-r--r--chromium/services/user/public/cpp/constants.h14
-rw-r--r--chromium/services/user/public/interfaces/BUILD.gn15
-rw-r--r--chromium/services/user/public/interfaces/OWNERS13
-rw-r--r--chromium/services/user/public/interfaces/user_service.mojom23
-rw-r--r--chromium/services/user/user.gyp95
-rw-r--r--chromium/services/user/user_id_map.cc29
-rw-r--r--chromium/services/user/user_id_map.h31
-rw-r--r--chromium/services/user/user_service.cc57
-rw-r--r--chromium/services/user/user_service.h44
-rw-r--r--chromium/services/user/user_shell_client.cc126
-rw-r--r--chromium/services/user/user_shell_client.h68
200 files changed, 11967 insertions, 0 deletions
diff --git a/chromium/services/DEPS b/chromium/services/DEPS
new file mode 100644
index 00000000000..0322d918202
--- /dev/null
+++ b/chromium/services/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+mojo", # By definition.
+
+ "-services", # Services have to list which other services they depend on.
+ "+services/shell/public", # Every service talks to shell.
+]
diff --git a/chromium/services/README.md b/chromium/services/README.md
new file mode 100644
index 00000000000..32fc82030a7
--- /dev/null
+++ b/chromium/services/README.md
@@ -0,0 +1,38 @@
+Chrome Platform Services
+====
+
+### Overview
+
+This directory contains Chrome Platform Services. If you think of Chrome as a
+"portable OS," Chrome Platform Services can be thought of as that OS' "system
+services".
+
+Roughly each subdirectory here corresponds to a service that:
+
+ * is a client of `//services/shell` with its own unique Identity.
+ * could logically run a standalone process for security/performance isolation
+ benefits depending on the constraints of the host OS.
+
+### Service Directory Structure
+
+Individual services are structured like so:
+
+ //services/foo/ <-- Implementation code, may have subdirs.
+ /public/
+ /cpp/ <-- C++ client libraries (optional)
+ /interfaces/ <-- Mojom interfaces
+
+### Dependencies
+
+Code within `//services` may only depend on each other via each other's
+`/public/` directories, i.e. implementation code cannot be shared directly.
+
+Service code should also take care to tightly limit the dependencies on static
+libraries from outside of `//services`. Dependencies to large platform
+layers like `//content`, `//chrome` or `//third_party/WebKit` must be avoided.
+
+### Physical Packaging
+
+Note that while it may be possible to build a discrete physical package (DSO)
+for each service, products consuming these services may package them
+differently, e.g. by combining them into a single package.
diff --git a/chromium/services/catalog/BUILD.gn b/chromium/services/catalog/BUILD.gn
new file mode 100644
index 00000000000..43a65e4d879
--- /dev/null
+++ b/chromium/services/catalog/BUILD.gn
@@ -0,0 +1,70 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+import("//testing/test.gni")
+
+group("catalog") {
+ testonly = true
+ deps = [
+ ":lib",
+ ]
+}
+
+source_set("lib") {
+ sources = [
+ "catalog.cc",
+ "catalog.h",
+ "constants.cc",
+ "constants.h",
+ "entry.cc",
+ "entry.h",
+ "instance.cc",
+ "instance.h",
+ "manifest_provider.h",
+ "reader.cc",
+ "reader.h",
+ "store.cc",
+ "store.h",
+ "types.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/filesystem:lib",
+ "//services/catalog/public/interfaces",
+ "//services/shell/public/cpp",
+ ]
+
+ public_deps = [
+ # directory.mojom.h is #included by catalog.h
+ "//components/filesystem/public/interfaces",
+ ]
+
+ data_deps = [
+ ":manifest",
+ ]
+}
+
+mojo_application_manifest("manifest") {
+ application_name = "catalog"
+ source = "manifest.json"
+}
+
+source_set("unittests") {
+ testonly = true
+ sources = [
+ "entry_unittest.cc",
+ ]
+ data = [
+ "//services/catalog/data/",
+ ]
+ deps = [
+ ":lib",
+ "//base",
+ "//services/shell/public/cpp",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/services/catalog/DEPS b/chromium/services/catalog/DEPS
new file mode 100644
index 00000000000..46b0331153e
--- /dev/null
+++ b/chromium/services/catalog/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/filesystem"
+]
diff --git a/chromium/services/catalog/OWNERS b/chromium/services/catalog/OWNERS
new file mode 100644
index 00000000000..041852810f7
--- /dev/null
+++ b/chromium/services/catalog/OWNERS
@@ -0,0 +1,2 @@
+ben@chromium.org
+rockot@chromium.org
diff --git a/chromium/services/catalog/catalog.cc b/chromium/services/catalog/catalog.cc
new file mode 100644
index 00000000000..52b7361992d
--- /dev/null
+++ b/chromium/services/catalog/catalog.cc
@@ -0,0 +1,159 @@
+// 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 "services/catalog/catalog.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "components/filesystem/directory_impl.h"
+#include "components/filesystem/lock_table.h"
+#include "components/filesystem/public/interfaces/types.mojom.h"
+#include "services/catalog/constants.h"
+#include "services/catalog/instance.h"
+#include "services/catalog/reader.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/shell_connection.h"
+
+namespace catalog {
+namespace {
+
+bool IsPathNameValid(const std::string& name) {
+ if (name.empty() || name == "." || name == "..")
+ return false;
+
+ for (auto c : name) {
+ if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c) &&
+ c != '_' && c != '.')
+ return false;
+ }
+ return true;
+}
+
+base::FilePath GetPathForApplicationName(const std::string& application_name) {
+ std::string path = application_name;
+ const bool is_mojo =
+ base::StartsWith(path, "mojo:", base::CompareCase::INSENSITIVE_ASCII);
+ const bool is_exe =
+ !is_mojo &&
+ base::StartsWith(path, "exe:", base::CompareCase::INSENSITIVE_ASCII);
+ if (!is_mojo && !is_exe)
+ return base::FilePath();
+ if (path.find('.') != std::string::npos)
+ return base::FilePath();
+ if (is_mojo)
+ path.erase(path.begin(), path.begin() + 5);
+ else
+ path.erase(path.begin(), path.begin() + 4);
+ base::TrimString(path, "/", &path);
+ size_t end_of_name = path.find('/');
+ if (end_of_name != std::string::npos)
+ path.erase(path.begin() + end_of_name, path.end());
+
+ if (!IsPathNameValid(path))
+ return base::FilePath();
+
+ base::FilePath base_path;
+ PathService::Get(base::DIR_EXE, &base_path);
+ // TODO(beng): this won't handle user-specific components.
+ return base_path.AppendASCII(kMojoApplicationsDirName).AppendASCII(path).
+ AppendASCII("resources");
+}
+
+} // namespace
+
+Catalog::Catalog(base::SequencedWorkerPool* worker_pool,
+ std::unique_ptr<Store> store,
+ ManifestProvider* manifest_provider)
+ : Catalog(std::move(store)) {
+ system_reader_.reset(new Reader(worker_pool, manifest_provider));
+ ScanSystemPackageDir();
+}
+
+Catalog::Catalog(base::SingleThreadTaskRunner* task_runner,
+ std::unique_ptr<Store> store,
+ ManifestProvider* manifest_provider)
+ : Catalog(std::move(store)) {
+ system_reader_.reset(new Reader(task_runner, manifest_provider));
+ ScanSystemPackageDir();
+}
+
+Catalog::~Catalog() {}
+
+shell::mojom::ShellClientPtr Catalog::TakeShellClient() {
+ return std::move(shell_client_);
+}
+
+Catalog::Catalog(std::unique_ptr<Store> store)
+ : store_(std::move(store)), weak_factory_(this) {
+ shell::mojom::ShellClientRequest request = GetProxy(&shell_client_);
+ shell_connection_.reset(new shell::ShellConnection(this, std::move(request)));
+}
+
+void Catalog::ScanSystemPackageDir() {
+ base::FilePath system_package_dir;
+ PathService::Get(base::DIR_MODULE, &system_package_dir);
+ system_package_dir = system_package_dir.AppendASCII(kMojoApplicationsDirName);
+ system_reader_->Read(system_package_dir, &system_cache_,
+ base::Bind(&Catalog::SystemPackageDirScanned,
+ weak_factory_.GetWeakPtr()));
+}
+
+bool Catalog::AcceptConnection(shell::Connection* connection) {
+ connection->AddInterface<mojom::Catalog>(this);
+ connection->AddInterface<filesystem::mojom::Directory>(this);
+ connection->AddInterface<shell::mojom::ShellResolver>(this);
+ return true;
+}
+
+void Catalog::Create(shell::Connection* connection,
+ shell::mojom::ShellResolverRequest request) {
+ Instance* instance =
+ GetInstanceForUserId(connection->GetRemoteIdentity().user_id());
+ instance->BindShellResolver(std::move(request));
+}
+
+void Catalog::Create(shell::Connection* connection,
+ mojom::CatalogRequest request) {
+ Instance* instance =
+ GetInstanceForUserId(connection->GetRemoteIdentity().user_id());
+ instance->BindCatalog(std::move(request));
+}
+
+void Catalog::Create(shell::Connection* connection,
+ filesystem::mojom::DirectoryRequest request) {
+ if (!lock_table_)
+ lock_table_ = new filesystem::LockTable;
+ base::FilePath resources_path =
+ GetPathForApplicationName(connection->GetRemoteIdentity().name());
+ new filesystem::DirectoryImpl(std::move(request), resources_path,
+ scoped_refptr<filesystem::SharedTempDir>(),
+ lock_table_);
+}
+
+Instance* Catalog::GetInstanceForUserId(const std::string& user_id) {
+ auto it = instances_.find(user_id);
+ if (it != instances_.end())
+ return it->second.get();
+
+ // TODO(beng): There needs to be a way to load the store from different users.
+ Instance* instance = new Instance(std::move(store_), system_reader_.get());
+ instances_[user_id] = base::WrapUnique(instance);
+ if (loaded_)
+ instance->CacheReady(&system_cache_);
+
+ return instance;
+}
+
+void Catalog::SystemPackageDirScanned() {
+ loaded_ = true;
+ for (auto& instance : instances_)
+ instance.second->CacheReady(&system_cache_);
+}
+
+} // namespace catalog
diff --git a/chromium/services/catalog/catalog.h b/chromium/services/catalog/catalog.h
new file mode 100644
index 00000000000..25cfc03b440
--- /dev/null
+++ b/chromium/services/catalog/catalog.h
@@ -0,0 +1,105 @@
+// 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 SERVICES_CATALOG_CATALOG_H_
+#define SERVICES_CATALOG_CATALOG_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/filesystem/public/interfaces/directory.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/types.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+#include "services/shell/public/interfaces/shell_resolver.mojom.h"
+
+namespace base {
+class SequencedWorkerPool;
+class SingleThreadTaskRunner;
+}
+
+namespace filesystem {
+class LockTable;
+}
+
+namespace shell {
+class ShellConnection;
+}
+
+namespace catalog {
+
+class Instance;
+class ManifestProvider;
+class Reader;
+class Store;
+
+// Creates and owns an instance of the catalog. Exposes a ShellClientPtr that
+// can be passed to the Shell, potentially in a different process.
+class Catalog : public shell::ShellClient,
+ public shell::InterfaceFactory<mojom::Catalog>,
+ public shell::InterfaceFactory<filesystem::mojom::Directory>,
+ public shell::InterfaceFactory<shell::mojom::ShellResolver> {
+ public:
+ // |manifest_provider| may be null.
+ Catalog(base::SequencedWorkerPool* worker_pool,
+ std::unique_ptr<Store> store,
+ ManifestProvider* manifest_provider);
+ Catalog(base::SingleThreadTaskRunner* task_runner,
+ std::unique_ptr<Store> store,
+ ManifestProvider* manifest_provider);
+ ~Catalog() override;
+
+ shell::mojom::ShellClientPtr TakeShellClient();
+
+ private:
+ explicit Catalog(std::unique_ptr<Store> store);
+
+ // Starts a scane for system packages.
+ void ScanSystemPackageDir();
+
+ // shell::ShellClient:
+ bool AcceptConnection(shell::Connection* connection) override;
+
+ // shell::InterfaceFactory<shell::mojom::ShellResolver>:
+ void Create(shell::Connection* connection,
+ shell::mojom::ShellResolverRequest request) override;
+
+ // shell::InterfaceFactory<mojom::Catalog>:
+ void Create(shell::Connection* connection,
+ mojom::CatalogRequest request) override;
+
+ // shell::InterfaceFactory<filesystem::mojom::Directory>:
+ void Create(shell::Connection* connection,
+ filesystem::mojom::DirectoryRequest request) override;
+
+ Instance* GetInstanceForUserId(const std::string& user_id);
+
+ void SystemPackageDirScanned();
+
+ std::unique_ptr<Store> store_;
+
+ shell::mojom::ShellClientPtr shell_client_;
+ std::unique_ptr<shell::ShellConnection> shell_connection_;
+
+ std::map<std::string, std::unique_ptr<Instance>> instances_;
+
+ std::unique_ptr<Reader> system_reader_;
+ EntryCache system_cache_;
+ bool loaded_ = false;
+
+ scoped_refptr<filesystem::LockTable> lock_table_;
+
+ base::WeakPtrFactory<Catalog> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Catalog);
+};
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_CATALOG_H_
diff --git a/chromium/services/catalog/constants.cc b/chromium/services/catalog/constants.cc
new file mode 100644
index 00000000000..eb102cbf892
--- /dev/null
+++ b/chromium/services/catalog/constants.cc
@@ -0,0 +1,11 @@
+// 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 "services/catalog/constants.h"
+
+namespace catalog {
+
+const char kMojoApplicationsDirName[] = "Mojo Applications";
+
+} // namespace catalog
diff --git a/chromium/services/catalog/constants.h b/chromium/services/catalog/constants.h
new file mode 100644
index 00000000000..8942cc93a92
--- /dev/null
+++ b/chromium/services/catalog/constants.h
@@ -0,0 +1,14 @@
+// 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 SERVICES_CATALOG_CONSTANTS_H_
+#define SERVICES_CATALOG_CONSTANTS_H_
+
+namespace catalog {
+
+extern const char kMojoApplicationsDirName[];
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_CONSTANTS_H_
diff --git a/chromium/services/catalog/data/capabilities b/chromium/services/catalog/data/capabilities
new file mode 100644
index 00000000000..54aa56aad33
--- /dev/null
+++ b/chromium/services/catalog/data/capabilities
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "process-group": "bar",
+ "capabilities": {
+ "required": {
+ "mojo:bar": { "interfaces": [ "mojo::Bar" ] }
+ }
+ }
+}
diff --git a/chromium/services/catalog/data/instance b/chromium/services/catalog/data/instance
new file mode 100644
index 00000000000..c000efd3866
--- /dev/null
+++ b/chromium/services/catalog/data/instance
@@ -0,0 +1,7 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "process-group": "bar",
+ "capabilities": { }
+}
diff --git a/chromium/services/catalog/data/malformed b/chromium/services/catalog/data/malformed
new file mode 100644
index 00000000000..8d6705f7682
--- /dev/null
+++ b/chromium/services/catalog/data/malformed
@@ -0,0 +1,5 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "process-group": "bar",
diff --git a/chromium/services/catalog/data/serialization b/chromium/services/catalog/data/serialization
new file mode 100644
index 00000000000..460570289e2
--- /dev/null
+++ b/chromium/services/catalog/data/serialization
@@ -0,0 +1,18 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "process-group": "bar",
+ "capabilities": {
+ "provided": {
+ "foo": ["mojo::Bar", "mojo::Baz"],
+ "bar": ["mojo::Bork"]
+ },
+ "required": {
+ "mojo:bar": {
+ "classes": ["a", "b"],
+ "interfaces": ["mojo::Blork", "mojo::Blark"]
+ }
+ }
+ }
+}
diff --git a/chromium/services/catalog/data/simple b/chromium/services/catalog/data/simple
new file mode 100644
index 00000000000..e82c862ad75
--- /dev/null
+++ b/chromium/services/catalog/data/simple
@@ -0,0 +1,6 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "capabilities": { }
+}
diff --git a/chromium/services/catalog/data/wildcard_interfaces b/chromium/services/catalog/data/wildcard_interfaces
new file mode 100644
index 00000000000..bb60dba459e
--- /dev/null
+++ b/chromium/services/catalog/data/wildcard_interfaces
@@ -0,0 +1,12 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:foo",
+ "display_name": "Foo",
+ "capabilities": {
+ "required": {
+ "mojo:bar": {
+ "interfaces": [ "*" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/catalog/entry.cc b/chromium/services/catalog/entry.cc
new file mode 100644
index 00000000000..9d477b13815
--- /dev/null
+++ b/chromium/services/catalog/entry.cc
@@ -0,0 +1,298 @@
+// 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 "services/catalog/entry.h"
+
+#include "base/values.h"
+#include "services/catalog/store.h"
+#include "services/shell/public/cpp/names.h"
+
+namespace catalog {
+namespace {
+
+bool ReadStringSet(const base::ListValue& list_value,
+ std::set<std::string>* string_set) {
+ DCHECK(string_set);
+ for (auto i = list_value.begin(); i != list_value.end(); ++i) {
+ std::string value;
+ const base::Value* value_value = *i;
+ if (!value_value->GetAsString(&value)) {
+ LOG(ERROR) << "Entry::Deserialize: list member must be a string";
+ return false;
+ }
+ string_set->insert(value);
+ }
+ return true;
+}
+
+bool ReadStringSetFromValue(const base::Value& value,
+ std::set<std::string>* string_set) {
+ const base::ListValue* list_value = nullptr;
+ if (!value.GetAsList(&list_value)) {
+ LOG(ERROR) << "Entry::Deserialize: Value must be a list.";
+ return false;
+ }
+ return ReadStringSet(*list_value, string_set);
+}
+
+bool ReadStringSetFromDictionary(const base::DictionaryValue& dictionary,
+ const std::string& key,
+ std::set<std::string>* string_set) {
+ const base::ListValue* list_value = nullptr;
+ if (dictionary.HasKey(key) && !dictionary.GetList(key, &list_value)) {
+ LOG(ERROR) << "Entry::Deserialize: " << key << " must be a list.";
+ return false;
+ }
+ if (list_value)
+ return ReadStringSet(*list_value, string_set);
+ return true;
+}
+
+bool BuildCapabilities(const base::DictionaryValue& value,
+ shell::CapabilitySpec* capabilities) {
+ DCHECK(capabilities);
+ const base::DictionaryValue* provided_value = nullptr;
+ if (value.HasKey(Store::kCapabilities_ProvidedKey) &&
+ !value.GetDictionary(Store::kCapabilities_ProvidedKey,
+ &provided_value)) {
+ LOG(ERROR) << "Entry::Deserialize: " << Store::kCapabilities_ProvidedKey
+ << " must be a dictionary.";
+ return false;
+ }
+ if (provided_value) {
+ shell::CapabilityRequest provided;
+ base::DictionaryValue::Iterator it(*provided_value);
+ for(; !it.IsAtEnd(); it.Advance()) {
+ shell::Interfaces interfaces;
+ if (!ReadStringSetFromValue(it.value(), &interfaces)) {
+ LOG(ERROR) << "Entry::Deserialize: Invalid interface list in provided "
+ << " classes dictionary";
+ return false;
+ }
+ capabilities->provided[it.key()] = interfaces;
+ }
+ }
+
+ const base::DictionaryValue* required_value = nullptr;
+ if (value.HasKey(Store::kCapabilities_RequiredKey) &&
+ !value.GetDictionary(Store::kCapabilities_RequiredKey,
+ &required_value)) {
+ LOG(ERROR) << "Entry::Deserialize: " << Store::kCapabilities_RequiredKey
+ << " must be a dictionary.";
+ return false;
+ }
+ if (required_value) {
+ base::DictionaryValue::Iterator it(*required_value);
+ for (; !it.IsAtEnd(); it.Advance()) {
+ shell::CapabilityRequest spec;
+ const base::DictionaryValue* entry_value = nullptr;
+ if (!it.value().GetAsDictionary(&entry_value)) {
+ LOG(ERROR) << "Entry::Deserialize: " << Store::kCapabilities_RequiredKey
+ << " must be a dictionary.";
+ return false;
+ }
+ if (!ReadStringSetFromDictionary(
+ *entry_value, Store::kCapabilities_ClassesKey, &spec.classes)) {
+ LOG(ERROR) << "Entry::Deserialize: Invalid classes list in required "
+ << "capabilities dictionary.";
+ return false;
+ }
+ shell::Interfaces interfaces;
+ if (!ReadStringSetFromDictionary(*entry_value,
+ Store::kCapabilities_InterfacesKey,
+ &interfaces)) {
+ LOG(ERROR) << "Entry::Deserialize: Invalid interfaces list in required "
+ << "capabilities dictionary.";
+ return false;
+ }
+ if (interfaces.count("*") > 0) {
+ LOG(ERROR) << "Entry::Deserializer: Wildcard not valid in interfaces "
+ << "list.";
+ return false;
+ }
+ spec.interfaces = interfaces;
+
+ capabilities->required[it.key()] = spec;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+Entry::Entry() {}
+Entry::Entry(const std::string& name)
+ : name_(name), qualifier_(shell::GetNamePath(name)), display_name_(name) {}
+Entry::Entry(const Entry& other) = default;
+Entry::~Entry() {}
+
+std::unique_ptr<base::DictionaryValue> Entry::Serialize() const {
+ std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
+ value->SetInteger(Store::kManifestVersionKey, 1);
+ value->SetString(Store::kNameKey, name_);
+ value->SetString(Store::kDisplayNameKey, display_name_);
+ value->SetString(Store::kQualifierKey, qualifier_);
+ std::unique_ptr<base::DictionaryValue> spec(new base::DictionaryValue);
+
+ std::unique_ptr<base::DictionaryValue> provided(new base::DictionaryValue);
+ for (const auto& i : capabilities_.provided) {
+ std::unique_ptr<base::ListValue> interfaces(new base::ListValue);
+ for (const auto& interface_name : i.second)
+ interfaces->AppendString(interface_name);
+ provided->Set(i.first, std::move(interfaces));
+ }
+ spec->Set(Store::kCapabilities_ProvidedKey, std::move(provided));
+
+ std::unique_ptr<base::DictionaryValue> required(new base::DictionaryValue);
+ for (const auto& i : capabilities_.required) {
+ std::unique_ptr<base::DictionaryValue> request(new base::DictionaryValue);
+ std::unique_ptr<base::ListValue> classes(new base::ListValue);
+ for (const auto& class_name : i.second.classes)
+ classes->AppendString(class_name);
+ request->Set(Store::kCapabilities_ClassesKey, std::move(classes));
+ std::unique_ptr<base::ListValue> interfaces(new base::ListValue);
+ for (const auto& interface_name : i.second.interfaces)
+ interfaces->AppendString(interface_name);
+ request->Set(Store::kCapabilities_InterfacesKey, std::move(interfaces));
+ required->Set(i.first, std::move(request));
+ }
+ spec->Set(Store::kCapabilities_RequiredKey, std::move(required));
+
+ value->Set(Store::kCapabilitiesKey, std::move(spec));
+ return value;
+}
+
+// static
+std::unique_ptr<Entry> Entry::Deserialize(const base::DictionaryValue& value) {
+ std::unique_ptr<Entry> entry(new Entry);
+
+ // Manifest version.
+ int manifest_version = 0;
+ if (!value.GetInteger(Store::kManifestVersionKey, &manifest_version)) {
+ LOG(ERROR) << "Entry::Deserialize: " << Store::kManifestVersionKey
+ << " must be an integer.";
+ return nullptr;
+ }
+ if (manifest_version != 1) {
+ LOG(ERROR) << "Entry::Deserialize: Unsupported value of "
+ << Store::kManifestVersionKey << ":" << manifest_version;
+ return nullptr;
+ }
+
+ // Name.
+ std::string name_string;
+ if (!value.GetString(Store::kNameKey, &name_string)) {
+ LOG(ERROR) << "Entry::Deserialize: dictionary has no "
+ << Store::kNameKey << " key";
+ return nullptr;
+ }
+ if (!shell::IsValidName(name_string)) {
+ LOG(ERROR) << "Entry::Deserialize: " << name_string << " is not a valid "
+ << "Mojo name";
+ return nullptr;
+ }
+ entry->set_name(name_string);
+
+ // Process group.
+ if (value.HasKey(Store::kQualifierKey)) {
+ std::string qualifier;
+ if (!value.GetString(Store::kQualifierKey, &qualifier)) {
+ LOG(ERROR) << "Entry::Deserialize: " << Store::kQualifierKey << " must "
+ << "be a string.";
+ return nullptr;
+ }
+ entry->set_qualifier(qualifier);
+ } else {
+ entry->set_qualifier(shell::GetNamePath(name_string));
+ }
+
+ // Human-readable name.
+ std::string display_name;
+ if (!value.GetString(Store::kDisplayNameKey, &display_name)) {
+ LOG(ERROR) << "Entry::Deserialize: dictionary has no "
+ << Store::kDisplayNameKey << " key";
+ return nullptr;
+ }
+ entry->set_display_name(display_name);
+
+ // Capability spec.
+ const base::DictionaryValue* capabilities = nullptr;
+ if (!value.GetDictionary(Store::kCapabilitiesKey, &capabilities)) {
+ LOG(ERROR) << "Entry::Deserialize: dictionary has no "
+ << Store::kCapabilitiesKey << " key";
+ return nullptr;
+ }
+
+ shell::CapabilitySpec spec;
+ if (!BuildCapabilities(*capabilities, &spec)) {
+ LOG(ERROR) << "Entry::Deserialize: failed to build capability spec for "
+ << entry->name();
+ return nullptr;
+ }
+ entry->set_capabilities(spec);
+
+ if (value.HasKey(Store::kApplicationsKey)) {
+ const base::ListValue* applications = nullptr;
+ value.GetList(Store::kApplicationsKey, &applications);
+ for (size_t i = 0; i < applications->GetSize(); ++i) {
+ const base::DictionaryValue* application = nullptr;
+ applications->GetDictionary(i, &application);
+ std::unique_ptr<Entry> child = Entry::Deserialize(*application);
+ if (child) {
+ child->set_package(entry.get());
+ // Caller must assume ownership of these items.
+ entry->applications_.insert(child.release());
+ }
+ }
+ }
+
+ return entry;
+}
+
+bool Entry::ProvidesClass(const std::string& clazz) const {
+ return capabilities_.provided.find(clazz) != capabilities_.provided.end();
+}
+
+bool Entry::operator==(const Entry& other) const {
+ return other.name_ == name_ && other.qualifier_ == qualifier_ &&
+ other.display_name_ == display_name_ &&
+ other.capabilities_ == capabilities_;
+}
+
+bool Entry::operator<(const Entry& other) const {
+ return std::tie(name_, qualifier_, display_name_, capabilities_) <
+ std::tie(other.name_, other.qualifier_, other.display_name_,
+ other.capabilities_);
+}
+
+} // catalog
+
+namespace mojo {
+
+// static
+shell::mojom::ResolveResultPtr
+ TypeConverter<shell::mojom::ResolveResultPtr, catalog::Entry>::Convert(
+ const catalog::Entry& input) {
+ shell::mojom::ResolveResultPtr result(shell::mojom::ResolveResult::New());
+ result->name = input.name();
+ const catalog::Entry& package = input.package() ? *input.package() : input;
+ result->resolved_name = package.name();
+ result->qualifier = input.qualifier();
+ result->capabilities =
+ shell::mojom::CapabilitySpec::From(input.capabilities());
+ result->package_path = package.path();
+ return result;
+}
+
+// static
+catalog::mojom::EntryPtr
+ TypeConverter<catalog::mojom::EntryPtr, catalog::Entry>::Convert(
+ const catalog::Entry& input) {
+ catalog::mojom::EntryPtr result(catalog::mojom::Entry::New());
+ result->name = input.name();
+ result->display_name = input.display_name();
+ return result;
+}
+
+} // namespace mojo
diff --git a/chromium/services/catalog/entry.h b/chromium/services/catalog/entry.h
new file mode 100644
index 00000000000..b7bdfff6ff0
--- /dev/null
+++ b/chromium/services/catalog/entry.h
@@ -0,0 +1,85 @@
+// 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 SERVICES_CATALOG_ENTRY_H_
+#define SERVICES_CATALOG_ENTRY_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/shell/public/cpp/capabilities.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace catalog {
+
+// Static information about an application package known to the Catalog.
+class Entry {
+ public:
+ Entry();
+ explicit Entry(const std::string& name);
+ explicit Entry(const Entry& other);
+ ~Entry();
+
+ std::unique_ptr<base::DictionaryValue> Serialize() const;
+
+ // If the constructed Entry is a package that provides other Entrys, the
+ // caller must assume ownership of the tree of Entrys by enumerating
+ // applications().
+ static std::unique_ptr<Entry> Deserialize(const base::DictionaryValue& value);
+
+ bool ProvidesClass(const std::string& clazz) const;
+
+ bool operator==(const Entry& other) const;
+ bool operator<(const Entry& other) const;
+
+ const std::string& name() const { return name_; }
+ void set_name(const std::string& name) { name_ = name; }
+ const base::FilePath& path() const { return path_; }
+ void set_path(const base::FilePath& path) { path_ = path; }
+ const std::string& qualifier() const { return qualifier_; }
+ void set_qualifier(const std::string& qualifier) { qualifier_ = qualifier; }
+ const std::string& display_name() const { return display_name_; }
+ void set_display_name(const std::string& display_name) {
+ display_name_ = display_name;
+ }
+ const shell::CapabilitySpec& capabilities() const { return capabilities_; }
+ void set_capabilities(const shell::CapabilitySpec& capabilities) {
+ capabilities_ = capabilities;
+ }
+ const Entry* package() const { return package_; }
+ void set_package(Entry* package) { package_ = package; }
+ const std::set<Entry*>& applications() { return applications_; }
+
+ private:
+ std::string name_;
+ base::FilePath path_;
+ std::string qualifier_;
+ std::string display_name_;
+ shell::CapabilitySpec capabilities_;
+ Entry* package_ = nullptr;
+ std::set<Entry*> applications_;
+};
+
+} // namespace catalog
+
+namespace mojo {
+template <>
+struct TypeConverter<shell::mojom::ResolveResultPtr, catalog::Entry> {
+ static shell::mojom::ResolveResultPtr Convert(const catalog::Entry& input);
+};
+
+template<>
+struct TypeConverter<catalog::mojom::EntryPtr, catalog::Entry> {
+ static catalog::mojom::EntryPtr Convert(const catalog::Entry& input);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_CATALOG_ENTRY_H_
diff --git a/chromium/services/catalog/entry_unittest.cc b/chromium/services/catalog/entry_unittest.cc
new file mode 100644
index 00000000000..80dabf6e6a3
--- /dev/null
+++ b/chromium/services/catalog/entry_unittest.cc
@@ -0,0 +1,107 @@
+// 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 "services/catalog/entry.h"
+
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "services/shell/public/cpp/capabilities.h"
+#include "services/shell/public/cpp/names.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace catalog {
+
+class EntryTest : public testing::Test {
+ public:
+ EntryTest() {}
+ ~EntryTest() override {}
+
+ protected:
+ std::unique_ptr<Entry> ReadEntry(const std::string& manifest,
+ std::unique_ptr<base::Value>* out_value) {
+ std::unique_ptr<base::Value> value = ReadManifest(manifest);
+ base::DictionaryValue* dictionary = nullptr;
+ CHECK(value->GetAsDictionary(&dictionary));
+ if (out_value)
+ *out_value = std::move(value);
+ return Entry::Deserialize(*dictionary);
+ }
+
+ std::unique_ptr<base::Value> ReadManifest(const std::string& manifest) {
+ base::FilePath manifest_path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &manifest_path);
+ manifest_path = manifest_path.AppendASCII(
+ "services/catalog/data/" + manifest);
+
+ JSONFileValueDeserializer deserializer(manifest_path);
+ int error = 0;
+ std::string message;
+ // TODO(beng): probably want to do more detailed error checking. This should
+ // be done when figuring out if to unblock connection
+ // completion.
+ return deserializer.Deserialize(&error, &message);
+ }
+
+ private:
+ void SetUp() override {}
+ void TearDown() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(EntryTest);
+};
+
+TEST_F(EntryTest, Simple) {
+ std::unique_ptr<Entry> entry = ReadEntry("simple", nullptr);
+ EXPECT_EQ("mojo:foo", entry->name());
+ EXPECT_EQ(shell::GetNamePath(entry->name()), entry->qualifier());
+ EXPECT_EQ("Foo", entry->display_name());
+}
+
+TEST_F(EntryTest, NoWildcardInInterfaces) {
+ std::unique_ptr<Entry> entry = ReadEntry("wildcard_interfaces", nullptr);
+ EXPECT_EQ(nullptr, entry.get());
+}
+
+TEST_F(EntryTest, Instance) {
+ std::unique_ptr<Entry> entry = ReadEntry("instance", nullptr);
+ EXPECT_EQ("mojo:foo", entry->name());
+ EXPECT_EQ("bar", entry->qualifier());
+ EXPECT_EQ("Foo", entry->display_name());
+}
+
+TEST_F(EntryTest, Capabilities) {
+ std::unique_ptr<Entry> entry = ReadEntry("capabilities", nullptr);
+
+ EXPECT_EQ("mojo:foo", entry->name());
+ EXPECT_EQ("bar", entry->qualifier());
+ EXPECT_EQ("Foo", entry->display_name());
+ shell::CapabilitySpec spec;
+ shell::CapabilityRequest request;
+ request.interfaces.insert("mojo::Bar");
+ spec.required["mojo:bar"] = request;
+ EXPECT_EQ(spec, entry->capabilities());
+}
+
+TEST_F(EntryTest, Serialization) {
+ std::unique_ptr<base::Value> value;
+ std::unique_ptr<Entry> entry = ReadEntry("serialization", &value);
+
+ std::unique_ptr<base::DictionaryValue> serialized(entry->Serialize());
+
+ // We can't just compare values, since during deserialization some of the
+ // lists get converted to std::sets, which are sorted, so Value::Equals will
+ // fail.
+ std::unique_ptr<Entry> reconstituted = Entry::Deserialize(*serialized.get());
+ EXPECT_EQ(*entry, *reconstituted);
+}
+
+TEST_F(EntryTest, Malformed) {
+ std::unique_ptr<base::Value> value = ReadManifest("malformed");
+ EXPECT_FALSE(value.get());
+}
+
+
+} // namespace catalog
diff --git a/chromium/services/catalog/instance.cc b/chromium/services/catalog/instance.cc
new file mode 100644
index 00000000000..6673f35ab5e
--- /dev/null
+++ b/chromium/services/catalog/instance.cc
@@ -0,0 +1,179 @@
+// 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 "services/catalog/instance.h"
+
+#include "base/bind.h"
+#include "services/catalog/entry.h"
+#include "services/catalog/manifest_provider.h"
+#include "services/catalog/reader.h"
+#include "services/catalog/store.h"
+#include "services/shell/public/cpp/names.h"
+
+namespace catalog {
+namespace {
+
+void AddEntry(const Entry& entry, mojo::Array<mojom::EntryPtr>* ary) {
+ mojom::EntryPtr entry_ptr(mojom::Entry::New());
+ entry_ptr->name = entry.name();
+ entry_ptr->display_name = entry.display_name();
+ ary->push_back(std::move(entry_ptr));
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// Instance, public:
+
+Instance::Instance(std::unique_ptr<Store> store, Reader* system_reader)
+ : store_(std::move(store)),
+ system_reader_(system_reader),
+ weak_factory_(this) {}
+Instance::~Instance() {}
+
+void Instance::BindShellResolver(
+ shell::mojom::ShellResolverRequest request) {
+ if (system_cache_)
+ shell_resolver_bindings_.AddBinding(this, std::move(request));
+ else
+ pending_shell_resolver_requests_.push_back(std::move(request));
+}
+
+void Instance::BindCatalog(mojom::CatalogRequest request) {
+ if (system_cache_)
+ catalog_bindings_.AddBinding(this, std::move(request));
+ else
+ pending_catalog_requests_.push_back(std::move(request));
+}
+
+void Instance::CacheReady(EntryCache* cache) {
+ system_cache_ = cache;
+ DeserializeCatalog();
+ for (auto& request : pending_shell_resolver_requests_)
+ BindShellResolver(std::move(request));
+ for (auto& request : pending_catalog_requests_)
+ BindCatalog(std::move(request));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Instance, shell::mojom::ShellResolver:
+
+void Instance::ResolveMojoName(const mojo::String& mojo_name,
+ const ResolveMojoNameCallback& callback) {
+ DCHECK(system_cache_);
+
+ std::string type = shell::GetNameType(mojo_name);
+ if (type != shell::kNameType_Mojo && type != shell::kNameType_Exe) {
+ std::unique_ptr<Entry> entry(new Entry(mojo_name));
+ callback.Run(shell::mojom::ResolveResult::From(*entry));
+ return;
+ }
+
+ // TODO(beng): per-user catalogs.
+ auto entry = system_cache_->find(mojo_name);
+ if (entry != system_cache_->end()) {
+ callback.Run(shell::mojom::ResolveResult::From(*entry->second));
+ return;
+ }
+
+ // Manifests for mojo: names should always be in the catalog by this point.
+ //DCHECK(type == shell::kNameType_Exe);
+ system_reader_->CreateEntryForName(
+ mojo_name, system_cache_,
+ base::Bind(&Instance::OnReadManifest, weak_factory_.GetWeakPtr(),
+ mojo_name, callback));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Instance, mojom::Catalog:
+
+void Instance::GetEntries(mojo::Array<mojo::String> names,
+ const GetEntriesCallback& callback) {
+ DCHECK(system_cache_);
+
+ mojo::Array<mojom::EntryPtr> entries;
+ if (names.is_null()) {
+ // TODO(beng): user catalog.
+ for (const auto& entry : *system_cache_)
+ AddEntry(*entry.second, &entries);
+ } else {
+ std::vector<mojo::String> names_vec = names.PassStorage();
+ for (const std::string& name : names_vec) {
+ Entry* entry = nullptr;
+ // TODO(beng): user catalog.
+ if (system_cache_->find(name) != system_cache_->end())
+ entry = (*system_cache_)[name].get();
+ else
+ continue;
+ AddEntry(*entry, &entries);
+ }
+ }
+ callback.Run(std::move(entries));
+}
+
+void Instance::GetEntriesProvidingClass(
+ const mojo::String& clazz,
+ const GetEntriesProvidingClassCallback& callback) {
+ mojo::Array<mojom::EntryPtr> entries;
+ for (const auto& entry : *system_cache_)
+ if (entry.second->ProvidesClass(clazz))
+ entries.push_back(mojom::Entry::From(*entry.second));
+ callback.Run(std::move(entries));
+}
+
+void Instance::GetEntriesConsumingMIMEType(
+ const mojo::String& mime_type,
+ const GetEntriesConsumingMIMETypeCallback& callback) {
+ // TODO(beng): implement.
+}
+
+void Instance::GetEntriesSupportingScheme(
+ const mojo::String& scheme,
+ const GetEntriesSupportingSchemeCallback& callback) {
+ // TODO(beng): implement.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Instance, private:
+
+void Instance::DeserializeCatalog() {
+ DCHECK(system_cache_);
+ if (!store_)
+ return;
+ const base::ListValue* catalog = store_->GetStore();
+ CHECK(catalog);
+ // TODO(sky): make this handle aliases.
+ // TODO(beng): implement this properly!
+ for (auto it = catalog->begin(); it != catalog->end(); ++it) {
+ const base::DictionaryValue* dictionary = nullptr;
+ const base::Value* v = *it;
+ CHECK(v->GetAsDictionary(&dictionary));
+ std::unique_ptr<Entry> entry = Entry::Deserialize(*dictionary);
+ // TODO(beng): user catalog.
+ if (entry)
+ (*system_cache_)[entry->name()] = std::move(entry);
+ }
+}
+
+void Instance::SerializeCatalog() {
+ DCHECK(system_cache_);
+ std::unique_ptr<base::ListValue> catalog(new base::ListValue);
+ // TODO(beng): user catalog.
+ for (const auto& entry : *system_cache_)
+ catalog->Append(entry.second->Serialize());
+ if (store_)
+ store_->UpdateStore(std::move(catalog));
+}
+
+// static
+void Instance::OnReadManifest(base::WeakPtr<Instance> instance,
+ const std::string& mojo_name,
+ const ResolveMojoNameCallback& callback,
+ shell::mojom::ResolveResultPtr result) {
+ callback.Run(std::move(result));
+ if (instance)
+ instance->SerializeCatalog();
+}
+
+} // namespace catalog
diff --git a/chromium/services/catalog/instance.h b/chromium/services/catalog/instance.h
new file mode 100644
index 00000000000..a353c7d9f8c
--- /dev/null
+++ b/chromium/services/catalog/instance.h
@@ -0,0 +1,93 @@
+// 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 SERVICES_CATALOG_INSTANCE_H_
+#define SERVICES_CATALOG_INSTANCE_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/catalog/entry.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/store.h"
+#include "services/catalog/types.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/interfaces/shell_resolver.mojom.h"
+
+namespace catalog {
+
+class Reader;
+class Store;
+
+class Instance : public shell::mojom::ShellResolver,
+ public mojom::Catalog {
+ public:
+ // |manifest_provider| may be null.
+ Instance(std::unique_ptr<Store> store, Reader* system_reader);
+ ~Instance() override;
+
+ void BindShellResolver(shell::mojom::ShellResolverRequest request);
+ void BindCatalog(mojom::CatalogRequest request);
+
+ // Called when |cache| has been populated by a directory scan.
+ void CacheReady(EntryCache* cache);
+
+ private:
+ // shell::mojom::ShellResolver:
+ void ResolveMojoName(const mojo::String& mojo_name,
+ const ResolveMojoNameCallback& callback) override;
+
+ // mojom::Catalog:
+ void GetEntries(mojo::Array<mojo::String> names,
+ const GetEntriesCallback& callback) override;
+ void GetEntriesProvidingClass(
+ const mojo::String& clazz,
+ const GetEntriesProvidingClassCallback& callback) override;
+ void GetEntriesConsumingMIMEType(
+ const mojo::String& mime_type,
+ const GetEntriesConsumingMIMETypeCallback& callback) override;
+ void GetEntriesSupportingScheme(
+ const mojo::String& scheme,
+ const GetEntriesSupportingSchemeCallback& callback) override;
+
+ // Populate/serialize the cache from/to the supplied store.
+ void DeserializeCatalog();
+ void SerializeCatalog();
+
+ // Receives the result of manifest parsing, may be received after the
+ // catalog object that issued the request is destroyed.
+ static void OnReadManifest(base::WeakPtr<Instance> instance,
+ const std::string& mojo_name,
+ const ResolveMojoNameCallback& callback,
+ shell::mojom::ResolveResultPtr result);
+
+ // User-specific persistent storage of package manifests and other settings.
+ std::unique_ptr<Store> store_;
+
+ mojo::BindingSet<shell::mojom::ShellResolver> shell_resolver_bindings_;
+ mojo::BindingSet<mojom::Catalog> catalog_bindings_;
+
+ Reader* system_reader_;
+
+ // A map of name -> Entry data structure for system-level packages (i.e. those
+ // that are visible to all users).
+ // TODO(beng): eventually add per-user applications.
+ EntryCache* system_cache_ = nullptr;
+
+ // We only bind requests for these interfaces once the catalog has been
+ // populated. These data structures queue requests until that happens.
+ std::vector<shell::mojom::ShellResolverRequest>
+ pending_shell_resolver_requests_;
+ std::vector<mojom::CatalogRequest> pending_catalog_requests_;
+
+ base::WeakPtrFactory<Instance> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Instance);
+};
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_INSTANCE_H_
diff --git a/chromium/services/catalog/manifest.json b/chromium/services/catalog/manifest.json
new file mode 100644
index 00000000000..3f89a0f359d
--- /dev/null
+++ b/chromium/services/catalog/manifest.json
@@ -0,0 +1,16 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:catalog",
+ "display_name": "Application Resolver",
+ "capabilities": {
+ // Note, this section is provided for documentation only. Classes provided
+ // by this service must be stated in code in shell.cc as this manifest is
+ // not resolved until after several connections have been made.
+ "provided": {
+ "app": [ "filesystem::mojom::Directory" ]
+ },
+ "required": {
+ "mojo:shell": { "classes": [ "shell:all_users", "shell:explicit_class" ] }
+ }
+ }
+}
diff --git a/chromium/services/catalog/manifest_provider.h b/chromium/services/catalog/manifest_provider.h
new file mode 100644
index 00000000000..7a64e49d1b0
--- /dev/null
+++ b/chromium/services/catalog/manifest_provider.h
@@ -0,0 +1,29 @@
+// 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 SERVICES_CATALOG_MANIFEST_PROVIDER_H_
+#define SERVICES_CATALOG_MANIFEST_PROVIDER_H_
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace catalog {
+
+// An interface which can be implemented by a catalog embedder to override
+// manifest fetching behavior.
+class ManifestProvider {
+ public:
+ virtual ~ManifestProvider() {}
+
+ // Retrieves the raw contents of the manifest for application named |name|.
+ // Returns true if |name| is known and |*manifest_contents| is populated.
+ // returns false otherwise.
+ virtual bool GetApplicationManifest(const base::StringPiece& name,
+ std::string* manifest_contents) = 0;
+};
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_MANIFEST_PROVIDER_H_
diff --git a/chromium/services/catalog/public/cpp/BUILD.gn b/chromium/services/catalog/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..09e533f3727
--- /dev/null
+++ b/chromium/services/catalog/public/cpp/BUILD.gn
@@ -0,0 +1,18 @@
+# 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.
+
+source_set("cpp") {
+ sources = [
+ "resource_loader.cc",
+ "resource_loader.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/filesystem/public/interfaces",
+ "//mojo/platform_handle",
+ "//mojo/public/cpp/bindings",
+ "//services/shell/public/cpp",
+ ]
+}
diff --git a/chromium/services/catalog/public/cpp/resource_loader.cc b/chromium/services/catalog/public/cpp/resource_loader.cc
new file mode 100644
index 00000000000..16b1db8ffd5
--- /dev/null
+++ b/chromium/services/catalog/public/cpp/resource_loader.cc
@@ -0,0 +1,63 @@
+// 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 "services/catalog/public/cpp/resource_loader.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "components/filesystem/public/interfaces/directory.mojom.h"
+#include "mojo/platform_handle/platform_handle_functions.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace catalog {
+namespace {
+base::File GetFileFromHandle(mojo::ScopedHandle handle) {
+ CHECK(handle.is_valid());
+ MojoPlatformHandle platform_handle;
+ CHECK(MojoExtractPlatformHandle(handle.release().value(),
+ &platform_handle) == MOJO_RESULT_OK);
+ return base::File(platform_handle);
+}
+}
+
+ResourceLoader::ResourceLoader() {}
+ResourceLoader::~ResourceLoader() {}
+
+bool ResourceLoader::OpenFiles(filesystem::mojom::DirectoryPtr directory,
+ const std::set<std::string>& paths) {
+ mojo::Array<filesystem::mojom::FileOpenDetailsPtr> details(
+ mojo::Array<filesystem::mojom::FileOpenDetailsPtr>::New(paths.size()));
+ size_t i = 0;
+ for (const auto& path : paths) {
+ filesystem::mojom::FileOpenDetailsPtr open_details(
+ filesystem::mojom::FileOpenDetails::New());
+ open_details->path = path;
+ open_details->open_flags =
+ filesystem::mojom::kFlagOpen | filesystem::mojom::kFlagRead;
+ details[i++] = std::move(open_details);
+ }
+
+ mojo::Array<filesystem::mojom::FileOpenResultPtr> results(
+ mojo::Array<filesystem::mojom::FileOpenResultPtr>::New(paths.size()));
+ if (!directory->OpenFileHandles(std::move(details), &results))
+ return false;
+
+ for (const auto& result : results) {
+ resource_map_[result->path].reset(
+ new base::File(GetFileFromHandle(std::move(result->file_handle))));
+ }
+ return true;
+}
+
+base::File ResourceLoader::TakeFile(const std::string& path) {
+ std::unique_ptr<base::File> file_wrapper(std::move(resource_map_[path]));
+ resource_map_.erase(path);
+ return std::move(*file_wrapper);
+}
+
+} // namespace catalog
diff --git a/chromium/services/catalog/public/cpp/resource_loader.h b/chromium/services/catalog/public/cpp/resource_loader.h
new file mode 100644
index 00000000000..738be3635f2
--- /dev/null
+++ b/chromium/services/catalog/public/cpp/resource_loader.h
@@ -0,0 +1,49 @@
+// 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 SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
+#define SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "components/filesystem/public/interfaces/directory.mojom.h"
+
+namespace base {
+class File;
+}
+
+namespace catalog {
+
+// ResourceLoader asks the catalog (synchronously) to open the provided paths
+// and return the file handles. Use TakeFile() to retrieve a base::File to use
+// in client code.
+class ResourceLoader {
+ public:
+ ResourceLoader();
+ ~ResourceLoader();
+
+ // (Synchronously) opens all of the files in |paths| for reading. Use
+ // TakeFile() subsequently to obtain base::Files to use. Returns true if the
+ // sync operation completed, false if it did not.
+ bool OpenFiles(filesystem::mojom::DirectoryPtr directory,
+ const std::set<std::string>& paths);
+
+ // Releases and returns the file wrapping the handle.
+ base::File TakeFile(const std::string& path);
+
+ private:
+ using ResourceMap = std::map<std::string, std::unique_ptr<base::File>>;
+
+ ResourceMap resource_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceLoader);
+};
+
+} // namespace
+
+#endif // SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
diff --git a/chromium/services/catalog/public/interfaces/BUILD.gn b/chromium/services/catalog/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..77a6aaf1308
--- /dev/null
+++ b/chromium/services/catalog/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "catalog.mojom",
+ ]
+}
diff --git a/chromium/services/catalog/public/interfaces/OWNERS b/chromium/services/catalog/public/interfaces/OWNERS
new file mode 100644
index 00000000000..9e621796752
--- /dev/null
+++ b/chromium/services/catalog/public/interfaces/OWNERS
@@ -0,0 +1,13 @@
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=mkwst@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=palmer@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/chromium/services/catalog/public/interfaces/catalog.mojom b/chromium/services/catalog/public/interfaces/catalog.mojom
new file mode 100644
index 00000000000..beff6cbe979
--- /dev/null
+++ b/chromium/services/catalog/public/interfaces/catalog.mojom
@@ -0,0 +1,28 @@
+// 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.
+
+module catalog.mojom;
+
+struct Entry {
+ string name;
+ string display_name;
+};
+
+interface Catalog {
+ // Returns the catalog entries for the specified mojo names.
+ // If |names| is null, all available entries are returned.
+ GetEntries(array<string>? names) => (array<Entry> entries);
+
+ // Returns the entry(ies) for applications that export to the caller the
+ // specified class.
+ GetEntriesProvidingClass(string clazz) => (array<Entry> entries);
+
+ // Returns the entry(ies) for applications that can consume content of the
+ // specified MIME type.
+ GetEntriesConsumingMIMEType(string mime_type) => (array<Entry> entries);
+
+ // Returns the entry(ies) for applications that can handle links with the
+ // specified scheme.
+ GetEntriesSupportingScheme(string protocol_scheme) => (array<Entry> entries);
+};
diff --git a/chromium/services/catalog/reader.cc b/chromium/services/catalog/reader.cc
new file mode 100644
index 00000000000..ad8dd748873
--- /dev/null
+++ b/chromium/services/catalog/reader.cc
@@ -0,0 +1,216 @@
+// 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 "services/catalog/reader.h"
+
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "services/catalog/constants.h"
+#include "services/catalog/entry.h"
+#include "services/catalog/manifest_provider.h"
+#include "services/shell/public/cpp/names.h"
+
+namespace catalog {
+namespace {
+
+base::FilePath GetManifestPath(const base::FilePath& package_dir,
+ const std::string& name) {
+ // TODO(beng): think more about how this should be done for exe targets.
+ std::string type = shell::GetNameType(name);
+ std::string path = shell::GetNamePath(name);
+ if (type == shell::kNameType_Mojo) {
+ return package_dir.AppendASCII(kMojoApplicationsDirName).AppendASCII(
+ path + "/manifest.json");
+ }
+ if (type == shell::kNameType_Exe)
+ return package_dir.AppendASCII(path + "_manifest.json");
+ return base::FilePath();
+}
+
+
+base::FilePath GetPackagePath(const base::FilePath& package_dir,
+ const std::string& name) {
+ std::string type = shell::GetNameType(name);
+ if (type == shell::kNameType_Mojo) {
+ // It's still a mojo: URL, use the default mapping scheme.
+ const std::string host = shell::GetNamePath(name);
+ return package_dir.AppendASCII(host + "/" + host + ".mojo");
+ }
+ if (type == shell::kNameType_Exe) {
+#if defined OS_WIN
+ std::string extension = ".exe";
+#else
+ std::string extension;
+#endif
+ return package_dir.AppendASCII(shell::GetNamePath(name) + extension);
+ }
+ return base::FilePath();
+}
+
+std::unique_ptr<Entry> ProcessManifest(
+ std::unique_ptr<base::Value> manifest_root,
+ const base::FilePath& package_dir) {
+ // Manifest was malformed or did not exist.
+ if (!manifest_root)
+ return nullptr;
+
+ const base::DictionaryValue* dictionary = nullptr;
+ if (!manifest_root->GetAsDictionary(&dictionary))
+ return nullptr;
+
+ std::unique_ptr<Entry> entry = Entry::Deserialize(*dictionary);
+ if (!entry)
+ return nullptr;
+ entry->set_path(GetPackagePath(package_dir, entry->name()));
+ return entry;
+}
+
+std::unique_ptr<Entry> CreateEntryForManifestAt(
+ const base::FilePath& manifest_path,
+ const base::FilePath& package_dir) {
+ JSONFileValueDeserializer deserializer(manifest_path);
+ int error = 0;
+ std::string message;
+
+ // TODO(beng): probably want to do more detailed error checking. This should
+ // be done when figuring out if to unblock connection completion.
+ return ProcessManifest(deserializer.Deserialize(&error, &message),
+ package_dir);
+}
+
+void ScanDir(
+ const base::FilePath& package_dir,
+ const Reader::ReadManifestCallback& read_manifest_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> original_thread_task_runner,
+ const base::Closure& read_complete_closure) {
+ base::FileEnumerator enumerator(package_dir, false,
+ base::FileEnumerator::DIRECTORIES);
+ while (1) {
+ base::FilePath path = enumerator.Next();
+ if (path.empty())
+ break;
+ base::FilePath manifest_path = path.AppendASCII("manifest.json");
+ std::unique_ptr<Entry> entry =
+ CreateEntryForManifestAt(manifest_path, package_dir);
+ if (!entry)
+ continue;
+
+ // Skip over subdirs that contain only manifests, they're artifacts of the
+ // build (e.g. for applications that are packaged into others) and are not
+ // valid standalone packages.
+ base::FilePath package_path = GetPackagePath(package_dir, entry->name());
+ if (entry->name() != "mojo:shell" && entry->name() != "mojo:catalog" &&
+ !base::PathExists(package_path)) {
+ continue;
+ }
+
+ original_thread_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(read_manifest_callback, base::Passed(&entry)));
+ }
+
+ original_thread_task_runner->PostTask(FROM_HERE, read_complete_closure);
+}
+
+std::unique_ptr<Entry> ReadManifest(const base::FilePath& package_dir,
+ const std::string& mojo_name) {
+ std::unique_ptr<Entry> entry = CreateEntryForManifestAt(
+ GetManifestPath(package_dir, mojo_name), package_dir);
+ if (!entry) {
+ entry.reset(new Entry(mojo_name));
+ entry->set_path(GetPackagePath(
+ package_dir.AppendASCII(kMojoApplicationsDirName), mojo_name));
+ }
+ return entry;
+}
+
+void AddEntryToCache(EntryCache* cache, std::unique_ptr<Entry> entry) {
+ for (auto child : entry->applications())
+ AddEntryToCache(cache, base::WrapUnique(child));
+ (*cache)[entry->name()] = std::move(entry);
+}
+
+void DoNothing(shell::mojom::ResolveResultPtr) {}
+
+} // namespace
+
+// A sequenced task runner is used to guarantee requests are serviced in the
+// order requested. To do otherwise means we may run callbacks in an
+// unpredictable order, leading to flake.
+Reader::Reader(base::SequencedWorkerPool* worker_pool,
+ ManifestProvider* manifest_provider)
+ : Reader(manifest_provider) {
+ file_task_runner_ = worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+}
+
+Reader::Reader(base::SingleThreadTaskRunner* task_runner,
+ ManifestProvider* manifest_provider)
+ : Reader(manifest_provider) {
+ file_task_runner_ = task_runner;
+}
+
+Reader::~Reader() {}
+
+void Reader::Read(const base::FilePath& package_dir,
+ EntryCache* cache,
+ const base::Closure& read_complete_closure) {
+ file_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ScanDir, package_dir,
+ base::Bind(&Reader::OnReadManifest, weak_factory_.GetWeakPtr(),
+ cache, base::Bind(&DoNothing)),
+ base::ThreadTaskRunnerHandle::Get(),
+ read_complete_closure));
+}
+
+void Reader::CreateEntryForName(
+ const std::string& mojo_name,
+ EntryCache* cache,
+ const CreateEntryForNameCallback& entry_created_callback) {
+ std::string manifest_contents;
+ if (manifest_provider_ &&
+ manifest_provider_->GetApplicationManifest(mojo_name,
+ &manifest_contents)) {
+ std::unique_ptr<base::Value> manifest_root =
+ base::JSONReader::Read(manifest_contents);
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::Bind(&ProcessManifest, base::Passed(&manifest_root),
+ system_package_dir_),
+ base::Bind(&Reader::OnReadManifest, weak_factory_.GetWeakPtr(), cache,
+ entry_created_callback));
+ } else {
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::Bind(&ReadManifest, system_package_dir_, mojo_name),
+ base::Bind(&Reader::OnReadManifest, weak_factory_.GetWeakPtr(), cache,
+ entry_created_callback));
+ }
+}
+
+Reader::Reader(ManifestProvider* manifest_provider)
+ : manifest_provider_(manifest_provider), weak_factory_(this) {
+ PathService::Get(base::DIR_MODULE, &system_package_dir_);
+}
+
+void Reader::OnReadManifest(
+ EntryCache* cache,
+ const CreateEntryForNameCallback& entry_created_callback,
+ std::unique_ptr<Entry> entry) {
+ shell::mojom::ResolveResultPtr result =
+ shell::mojom::ResolveResult::From(*entry);
+ AddEntryToCache(cache, std::move(entry));
+ entry_created_callback.Run(std::move(result));
+}
+
+} // namespace catalog
diff --git a/chromium/services/catalog/reader.h b/chromium/services/catalog/reader.h
new file mode 100644
index 00000000000..1e6224bad69
--- /dev/null
+++ b/chromium/services/catalog/reader.h
@@ -0,0 +1,70 @@
+// 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 SERVICES_CATALOG_READER_H_
+#define SERVICES_CATALOG_READER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "services/catalog/types.h"
+#include "services/shell/public/interfaces/shell_resolver.mojom.h"
+
+namespace base {
+class SequencedWorkerPool;
+class SingleThreadTaskRunner;
+}
+
+namespace catalog {
+
+class Entry;
+class ManifestProvider;
+
+// Responsible for loading manifests & building the Entry data structures.
+class Reader {
+ public:
+ using ReadManifestCallback = base::Callback<void(std::unique_ptr<Entry>)>;
+ using CreateEntryForNameCallback =
+ base::Callback<void(shell::mojom::ResolveResultPtr)>;
+
+ Reader(base::SequencedWorkerPool* worker_pool,
+ ManifestProvider* manifest_provider);
+ Reader(base::SingleThreadTaskRunner* task_runner,
+ ManifestProvider* manifest_provider);
+ ~Reader();
+
+ // Scans the contents of |package_dir|, reading all application manifests and
+ // populating |cache|. Runs |read_complete_closure| when done.
+ void Read(const base::FilePath& package_dir,
+ EntryCache* cache,
+ const base::Closure& read_complete_closure);
+
+ // Returns an Entry for |mojo_name| via |callback|, assuming a manifest file
+ // in the canonical location
+ void CreateEntryForName(
+ const std::string& mojo_name,
+ EntryCache* cache,
+ const CreateEntryForNameCallback& entry_created_callback);
+
+ private:
+ explicit Reader(ManifestProvider* manifest_provider);
+
+ void OnReadManifest(EntryCache* cache,
+ const CreateEntryForNameCallback& entry_created_callback,
+ std::unique_ptr<Entry> entry);
+
+ base::FilePath system_package_dir_;
+ scoped_refptr<base::TaskRunner> file_task_runner_;
+ ManifestProvider* const manifest_provider_;
+ base::WeakPtrFactory<Reader> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Reader);
+};
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_READER_H_
diff --git a/chromium/services/catalog/store.cc b/chromium/services/catalog/store.cc
new file mode 100644
index 00000000000..9d1cd452be8
--- /dev/null
+++ b/chromium/services/catalog/store.cc
@@ -0,0 +1,30 @@
+// 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 "services/catalog/store.h"
+
+namespace catalog {
+
+// static
+const char Store::kManifestVersionKey[] = "manifest_version";
+// static
+const char Store::kNameKey[] = "name";
+// static
+const char Store::kQualifierKey[] = "process-group";
+// static
+const char Store::kDisplayNameKey[] = "display_name";
+// static
+const char Store::kCapabilitiesKey[] = "capabilities";
+// static
+const char Store::kCapabilities_ProvidedKey[] = "provided";
+// static
+const char Store::kCapabilities_RequiredKey[] = "required";
+// static
+const char Store::kCapabilities_ClassesKey[] = "classes";
+// static
+const char Store::kCapabilities_InterfacesKey[] = "interfaces";
+// static
+const char Store::kApplicationsKey[] = "applications";
+
+} // namespace catalog
diff --git a/chromium/services/catalog/store.h b/chromium/services/catalog/store.h
new file mode 100644
index 00000000000..5fe92c08513
--- /dev/null
+++ b/chromium/services/catalog/store.h
@@ -0,0 +1,55 @@
+// 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 SERVICES_CATALOG_STORE_H_
+#define SERVICES_CATALOG_STORE_H_
+
+#include <memory>
+
+#include "base/values.h"
+
+namespace catalog {
+
+// Implemented by an object that provides storage for the application catalog
+// (e.g. in Chrome, preferences). The Catalog is the canonical owner of the
+// contents of the store, so no one else must modify its contents.
+class Store {
+ public:
+ // Value is an integer.
+ static const char kManifestVersionKey[];
+ // Value is a string.
+ static const char kNameKey[];
+ // Value is a string.
+ static const char kQualifierKey[];
+ // Value is a string.
+ static const char kDisplayNameKey[];
+ // Value is a dictionary.
+ static const char kCapabilitiesKey[];
+ // Value is a dictionary.
+ static const char kCapabilities_ProvidedKey[];
+ // Value is a dictionary.
+ static const char kCapabilities_RequiredKey[];
+ // Value is a list.
+ static const char kCapabilities_ClassesKey[];
+ // Value is a list.
+ static const char kCapabilities_InterfacesKey[];
+ // Value is a list.
+ static const char kApplicationsKey[];
+
+ virtual ~Store() {}
+
+ // Called during initialization to construct the Catalog's catalog.
+ // Returns a serialized list of the apps. Each entry in the returned list
+ // corresponds to an app (as a dictionary). Each dictionary has a name,
+ // display name and capabilities. The return value is owned by the caller.
+ virtual const base::ListValue* GetStore() = 0;
+
+ // Write the catalog to the store. Called when the Catalog learns of a newly
+ // encountered application.
+ virtual void UpdateStore(std::unique_ptr<base::ListValue> store) = 0;
+};
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_STORE_H_
diff --git a/chromium/services/catalog/types.h b/chromium/services/catalog/types.h
new file mode 100644
index 00000000000..00d3cc58586
--- /dev/null
+++ b/chromium/services/catalog/types.h
@@ -0,0 +1,22 @@
+// 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 SERVICES_CATALOG_TYPES_H_
+#define SERVICES_CATALOG_TYPES_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+
+namespace catalog {
+
+class Entry;
+
+// A map of mojo names -> catalog |Entry|s.
+using EntryCache = std::map<std::string, std::unique_ptr<Entry>>;
+
+} // namespace catalog
+
+#endif // SERVICES_CATALOG_TYPES_H_
diff --git a/chromium/services/navigation/BUILD.gn b/chromium/services/navigation/BUILD.gn
new file mode 100644
index 00000000000..0a70e16e4b6
--- /dev/null
+++ b/chromium/services/navigation/BUILD.gn
@@ -0,0 +1,143 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+import("//testing/test.gni")
+import("//tools/grit/repack.gni")
+
+group("all") {
+ testonly = true
+ data_deps = [
+ ":navigation",
+ ":navigation_unittests",
+ ]
+}
+
+executable("navigation") {
+ testonly = true
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ ":lib",
+ ":pak",
+ "//base",
+ "//build/win:default_exe_manifest",
+ "//components/mus/public/cpp",
+ "//content",
+ "//content/public/app:both",
+ "//mojo/public/cpp/bindings",
+ "//services/navigation/content_client",
+ "//services/shell/runner:init",
+ "//services/shell/runner/common",
+ "//ui/views",
+ "//ui/views/controls/webview",
+ "//ui/views/mus",
+ ]
+
+ data_deps = [
+ ":manifest",
+ "//mash/wm",
+ ]
+
+ if (is_win) {
+ configs -= [ "//build/config/win:console" ]
+ configs += [ "//build/config/win:windowed" ]
+ deps += [ "//sandbox" ]
+ }
+}
+
+static_library("lib") {
+ sources = [
+ "navigation.cc",
+ "navigation.h",
+ "view_impl.cc",
+ "view_impl.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/mus/public/cpp",
+ "//content/public/browser",
+ "//mojo/converters/geometry",
+ "//services/navigation/public/interfaces",
+ "//services/shell/public/cpp",
+ "//skia",
+ "//ui/views",
+ "//ui/views/controls/webview",
+ "//ui/views/mus",
+ ]
+}
+
+test("navigation_unittests") {
+ sources = [
+ "navigation_unittest.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//services/navigation/public/interfaces",
+ "//services/shell/public/cpp",
+ "//services/shell/public/cpp:shell_test_support",
+ "//services/shell/public/cpp/test:run_all_shelltests",
+ "//testing/gtest",
+ ]
+
+ data_deps = [
+ ":navigation",
+ ":unittest_manifest",
+ "//components/mus/test_wm",
+ ]
+}
+
+mojo_application_manifest("manifest") {
+ type = "exe"
+ application_name = "navigation"
+ source = "manifest.json"
+}
+
+mojo_application_manifest("unittest_manifest") {
+ type = "exe"
+ application_name = "navigation_unittests"
+ source = "unittest_manifest.json"
+}
+
+repack("pak") {
+ sources = [
+ "$root_gen_dir/blink/devtools_resources.pak",
+ "$root_gen_dir/blink/public/resources/blink_image_resources_100_percent.pak",
+ "$root_gen_dir/blink/public/resources/blink_resources.pak",
+ "$root_gen_dir/content/app/resources/content_resources_100_percent.pak",
+ "$root_gen_dir/content/app/strings/content_strings_en-US.pak",
+ "$root_gen_dir/content/browser/tracing/tracing_resources.pak",
+ "$root_gen_dir/content/content_resources.pak",
+ "$root_gen_dir/content/shell/shell_resources.pak",
+ "$root_gen_dir/net/net_resources.pak",
+ "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
+ "$root_gen_dir/ui/resources/webui_resources.pak",
+ "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
+ "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
+ "$root_gen_dir/ui/views/resources/views_resources_100_percent.pak",
+ ]
+
+ deps = [
+ "//content:resources",
+ "//content/app/resources",
+ "//content/app/strings",
+ "//content/browser/devtools:resources",
+ "//content/browser/tracing:resources",
+ "//content/shell:resources",
+ "//net:net_resources",
+ "//third_party/WebKit/public:image_resources",
+ "//third_party/WebKit/public:resources",
+ "//ui/resources",
+ "//ui/strings",
+ "//ui/views/resources",
+ ]
+
+ output = "$root_out_dir/navigation.pak"
+}
diff --git a/chromium/services/navigation/DEPS b/chromium/services/navigation/DEPS
new file mode 100644
index 00000000000..96712a72022
--- /dev/null
+++ b/chromium/services/navigation/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+ "+components/mus/public/cpp",
+ "+content/public",
+ "+content/shell",
+ "+net/base",
+ "+sandbox",
+ "+services/shell",
+ "+ui"
+]
diff --git a/chromium/services/navigation/content_client/BUILD.gn b/chromium/services/navigation/content_client/BUILD.gn
new file mode 100644
index 00000000000..fbf2181b58c
--- /dev/null
+++ b/chromium/services/navigation/content_client/BUILD.gn
@@ -0,0 +1,24 @@
+# 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.
+
+static_library("content_client") {
+ testonly = true
+ sources = [
+ "browser_main_parts.cc",
+ "browser_main_parts.h",
+ "content_browser_client.cc",
+ "content_browser_client.h",
+ "main_delegate.cc",
+ "main_delegate.h",
+ ]
+
+ deps = [
+ "//base:i18n",
+ "//content",
+ "//content/shell:content_shell_lib",
+ "//net",
+ "//services/navigation:lib",
+ "//ui/views:test_support",
+ ]
+}
diff --git a/chromium/services/navigation/content_client/browser_main_parts.cc b/chromium/services/navigation/content_client/browser_main_parts.cc
new file mode 100644
index 00000000000..09a688b3c99
--- /dev/null
+++ b/chromium/services/navigation/content_client/browser_main_parts.cc
@@ -0,0 +1,43 @@
+// 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 "services/navigation/content_client/browser_main_parts.h"
+
+#include "base/message_loop/message_loop.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_net_log.h"
+#include "services/navigation/navigation.h"
+#include "ui/views/test/test_views_delegate.h"
+
+namespace navigation {
+
+BrowserMainParts::BrowserMainParts(
+ const content::MainFunctionParams& parameters) {}
+BrowserMainParts::~BrowserMainParts() {}
+
+void BrowserMainParts::ToolkitInitialized() {
+ if (!views::ViewsDelegate::GetInstance())
+ views_delegate_.reset(new views::TestViewsDelegate);
+}
+
+void BrowserMainParts::PreMainMessageLoopRun() {
+ net_log_.reset(new content::ShellNetLog("ash_shell"));
+ browser_context_.reset(
+ new content::ShellBrowserContext(false, net_log_.get()));
+ navigation_->Init(content::MojoShellConnection::Get()->GetConnector(),
+ browser_context());
+}
+
+void BrowserMainParts::PostMainMessageLoopRun() {
+ views_delegate_.reset();
+ browser_context_.reset();
+}
+
+bool BrowserMainParts::MainMessageLoopRun(int* result_code) {
+ base::MessageLoop::current()->Run();
+ return true;
+}
+
+} // namespace navigation
diff --git a/chromium/services/navigation/content_client/browser_main_parts.h b/chromium/services/navigation/content_client/browser_main_parts.h
new file mode 100644
index 00000000000..a5f69adc6da
--- /dev/null
+++ b/chromium/services/navigation/content_client/browser_main_parts.h
@@ -0,0 +1,59 @@
+// 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 SERVICES_NAVIGATION_CONTENT_CLIENT_BROWSER_MAIN_PARTS_H_
+#define SERVICES_NAVIGATION_CONTENT_CLIENT_BROWSER_MAIN_PARTS_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/public/browser/browser_main_parts.h"
+
+namespace content {
+class ShellBrowserContext;
+struct MainFunctionParams;
+}
+
+namespace net {
+class NetLog;
+}
+
+namespace views {
+class ViewsDelegate;
+}
+
+namespace navigation {
+
+class Navigation;
+
+class BrowserMainParts : public content::BrowserMainParts {
+ public:
+ BrowserMainParts(const content::MainFunctionParams& parameters);
+ ~BrowserMainParts() override;
+
+ // Overridden from content::BrowserMainParts:
+ void ToolkitInitialized() override;
+ void PreMainMessageLoopRun() override;
+ bool MainMessageLoopRun(int* result_code) override;
+ void PostMainMessageLoopRun() override;
+
+ content::ShellBrowserContext* browser_context() {
+ return browser_context_.get();
+ }
+
+ void set_navigation(Navigation* navigation) { navigation_ = navigation; }
+
+ private:
+ std::unique_ptr<net::NetLog> net_log_;
+ std::unique_ptr<content::ShellBrowserContext> browser_context_;
+ std::unique_ptr<views::ViewsDelegate> views_delegate_;
+
+ Navigation* navigation_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
+};
+
+} // namespace navigation
+
+#endif // SERVICES_NAVIGATION_CONTENT_CLIENT_BROWSER_MAIN_PARTS_H_
diff --git a/chromium/services/navigation/content_client/content_browser_client.cc b/chromium/services/navigation/content_client/content_browser_client.cc
new file mode 100644
index 00000000000..b98432c4a0b
--- /dev/null
+++ b/chromium/services/navigation/content_client/content_browser_client.cc
@@ -0,0 +1,52 @@
+// 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 "services/navigation/content_client/content_browser_client.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "services/navigation/content_client/browser_main_parts.h"
+#include "services/navigation/navigation.h"
+
+namespace navigation {
+namespace {
+
+class ConnectionListener : public content::MojoShellConnection::Listener {
+ public:
+ explicit ConnectionListener(std::unique_ptr<shell::ShellClient> wrapped)
+ : wrapped_(std::move(wrapped)) {}
+
+ private:
+ bool AcceptConnection(shell::Connection* connection) override {
+ return wrapped_->AcceptConnection(connection);
+ }
+
+ std::unique_ptr<shell::ShellClient> wrapped_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionListener);
+};
+
+} // namespace
+
+ContentBrowserClient::ContentBrowserClient() {}
+ContentBrowserClient::~ContentBrowserClient() {}
+
+content::BrowserMainParts* ContentBrowserClient::CreateBrowserMainParts(
+ const content::MainFunctionParams& parameters) {
+ browser_main_parts_ = new BrowserMainParts(parameters);
+ return browser_main_parts_;
+}
+
+void ContentBrowserClient::AddMojoShellConnectionListeners() {
+ Navigation* navigation = new Navigation;
+ browser_main_parts_->set_navigation(navigation);
+ content::MojoShellConnection::Get()->AddListener(
+ base::WrapUnique(new ConnectionListener(base::WrapUnique(navigation))));
+}
+
+} // namespace navigation
diff --git a/chromium/services/navigation/content_client/content_browser_client.h b/chromium/services/navigation/content_client/content_browser_client.h
new file mode 100644
index 00000000000..ca30601bbac
--- /dev/null
+++ b/chromium/services/navigation/content_client/content_browser_client.h
@@ -0,0 +1,36 @@
+// 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 SERVICES_NAVIGATION_CONTENT_CLIENT_CONTENT_BROWSER_CLIENT_H_
+#define SERVICES_NAVIGATION_CONTENT_CLIENT_CONTENT_BROWSER_CLIENT_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "content/public/browser/content_browser_client.h"
+
+namespace navigation {
+
+class BrowserMainParts;
+
+class ContentBrowserClient : public content::ContentBrowserClient {
+ public:
+ ContentBrowserClient();
+ ~ContentBrowserClient() override;
+
+ // Overridden from content::ContentBrowserClient:
+ content::BrowserMainParts* CreateBrowserMainParts(
+ const content::MainFunctionParams& parameters) override;
+ void AddMojoShellConnectionListeners() override;
+
+ private:
+ BrowserMainParts* browser_main_parts_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentBrowserClient);
+};
+
+} // namespace navigation
+
+#endif // SERVICES_NAVIGATION_CONTENT_CLIENT_CONTENT_BROWSER_CLIENT_H_
diff --git a/chromium/services/navigation/content_client/main_delegate.cc b/chromium/services/navigation/content_client/main_delegate.cc
new file mode 100644
index 00000000000..167c15dabc6
--- /dev/null
+++ b/chromium/services/navigation/content_client/main_delegate.cc
@@ -0,0 +1,44 @@
+// 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 "services/navigation/content_client/main_delegate.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/common/content_switches.h"
+#include "services/navigation/content_client/content_browser_client.h"
+#include "ui/base/ime/input_method_initializer.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace navigation {
+
+MainDelegate::MainDelegate() {}
+MainDelegate::~MainDelegate() {}
+
+bool MainDelegate::BasicStartupComplete(int* exit_code) {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ std::string process_type =
+ command_line.GetSwitchValueASCII(switches::kProcessType);
+
+ content::SetContentClient(&content_client_);
+
+ return false;
+}
+
+void MainDelegate::PreSandboxStartup() {
+ base::FilePath path;
+ PathService::Get(base::DIR_MODULE, &path);
+ base::FilePath pak_path = path.Append(FILE_PATH_LITERAL("navigation.pak"));
+ ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_path);
+ ui::InitializeInputMethodForTesting();
+}
+
+content::ContentBrowserClient* MainDelegate::CreateContentBrowserClient() {
+ browser_client_.reset(new ContentBrowserClient);
+ return browser_client_.get();
+}
+
+} // namespace navigation
diff --git a/chromium/services/navigation/content_client/main_delegate.h b/chromium/services/navigation/content_client/main_delegate.h
new file mode 100644
index 00000000000..455ee58f524
--- /dev/null
+++ b/chromium/services/navigation/content_client/main_delegate.h
@@ -0,0 +1,42 @@
+// 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 SERVICES_NAVIGATION_CONTENT_CLIENT_MAIN_DELEGATE_H_
+#define SERVICES_NAVIGATION_CONTENT_CLIENT_MAIN_DELEGATE_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "content/public/app/content_main_delegate.h"
+#include "content/shell/common/shell_content_client.h"
+
+namespace content {
+class ShellContentRendererClient;
+class ShellContentUtilityClient;
+}
+
+namespace navigation {
+
+class ContentBrowserClient;
+
+class MainDelegate : public content::ContentMainDelegate {
+ public:
+ MainDelegate();
+ ~MainDelegate() override;
+
+ bool BasicStartupComplete(int* exit_code) override;
+ void PreSandboxStartup() override;
+ content::ContentBrowserClient* CreateContentBrowserClient() override;
+
+ private:
+ std::unique_ptr<ContentBrowserClient> browser_client_;
+ content::ShellContentClient content_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(MainDelegate);
+};
+
+} // namespace navigation
+
+#endif // SERVICES_NAVIGATION_CONTENT_CLIENT_MAIN_DELEGATE_H_
diff --git a/chromium/services/navigation/embedder_manifest.json b/chromium/services/navigation/embedder_manifest.json
new file mode 100644
index 00000000000..ede6e1ef53b
--- /dev/null
+++ b/chromium/services/navigation/embedder_manifest.json
@@ -0,0 +1,6 @@
+{
+ "manifest_version": 1,
+ "name": "exe:navigation",
+ "display_name": "Navigation Embedder",
+ "capabilities": {}
+}
diff --git a/chromium/services/navigation/main.cc b/chromium/services/navigation/main.cc
new file mode 100644
index 00000000000..942a6e0537b
--- /dev/null
+++ b/chromium/services/navigation/main.cc
@@ -0,0 +1,53 @@
+// 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 "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/app/content_main.h"
+#include "services/navigation/content_client/main_delegate.h"
+#include "services/shell/runner/init.h"
+
+#if defined(OS_WIN)
+#include "content/public/app/sandbox_helper_win.h"
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+#if defined(OS_WIN)
+int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
+ int argc = 0;
+ char** argv = nullptr;
+#else
+int main(int argc, const char** argv) {
+#endif
+ base::CommandLine::Init(argc, argv);
+ shell::WaitForDebuggerIfNecessary();
+
+#if !defined(OFFICIAL_BUILD)
+#if defined(OS_WIN)
+ base::RouteStdioToConsole(false);
+#endif
+#endif
+
+ base::FilePath log_filename;
+ PathService::Get(base::DIR_EXE, &log_filename);
+ log_filename = log_filename.AppendASCII("navigation.mojo.log");
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_ALL;
+ settings.log_file = log_filename.value().c_str();
+ settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+ logging::InitLogging(settings);
+
+ navigation::MainDelegate delegate;
+ content::ContentMainParams params(&delegate);
+#if defined(OS_WIN)
+ sandbox::SandboxInterfaceInfo sandbox_info = { 0 };
+ content::InitializeSandboxInfo(&sandbox_info);
+ params.instance = GetModuleHandle(NULL);
+ params.sandbox_info = &sandbox_info;
+#endif
+ return content::ContentMain(params);
+}
diff --git a/chromium/services/navigation/manifest.json b/chromium/services/navigation/manifest.json
new file mode 100644
index 00000000000..c7940f550de
--- /dev/null
+++ b/chromium/services/navigation/manifest.json
@@ -0,0 +1,14 @@
+{
+ "manifest_version": 1,
+ "name": "exe:navigation",
+ "display_name": "Navigation",
+ "capabilities": {
+ "provided": {
+ "app": [ "navigation::mojom::ViewFactory" ]
+ },
+ "required": {
+ "*": { "classes": [ "app" ] },
+ "mojo:shell": { "classes": [ "shell:client_process", "shell:user_id", "shell:instance_name" ] }
+ }
+ }
+}
diff --git a/chromium/services/navigation/navigation.cc b/chromium/services/navigation/navigation.cc
new file mode 100644
index 00000000000..75176d7c492
--- /dev/null
+++ b/chromium/services/navigation/navigation.cc
@@ -0,0 +1,54 @@
+// 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 "services/navigation/navigation.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "services/navigation/view_impl.h"
+
+namespace navigation {
+
+Navigation::Navigation()
+ : ref_factory_(base::MessageLoop::QuitWhenIdleClosure()) {
+ bindings_.set_connection_error_handler(
+ base::Bind(&Navigation::ViewFactoryLost, base::Unretained(this)));
+}
+Navigation::~Navigation() {}
+
+void Navigation::Init(shell::Connector* connector,
+ content::BrowserContext* browser_context) {
+ connector_ = connector;
+ browser_context_ = browser_context;
+ for (auto& pending : pending_creates_)
+ CreateView(std::move(pending.first), std::move(pending.second));
+}
+
+bool Navigation::AcceptConnection(shell::Connection* connection) {
+ connection->AddInterface<mojom::ViewFactory>(this);
+ return true;
+}
+
+void Navigation::Create(shell::Connection* connection,
+ mojom::ViewFactoryRequest request) {
+ bindings_.AddBinding(this, std::move(request));
+ refs_.insert(ref_factory_.CreateRef());
+}
+
+void Navigation::CreateView(mojom::ViewClientPtr client,
+ mojom::ViewRequest request) {
+ if (!browser_context_) {
+ pending_creates_.push_back(
+ std::make_pair(std::move(client), std::move(request)));
+ return;
+ }
+ new ViewImpl(connector_, browser_context_, std::move(client),
+ std::move(request), ref_factory_.CreateRef());
+}
+
+void Navigation::ViewFactoryLost() {
+ refs_.erase(refs_.begin());
+}
+
+} // navigation
diff --git a/chromium/services/navigation/navigation.h b/chromium/services/navigation/navigation.h
new file mode 100644
index 00000000000..cb9fb1f86a6
--- /dev/null
+++ b/chromium/services/navigation/navigation.h
@@ -0,0 +1,57 @@
+// 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 SERVICES_NAVIGATION_NAVIGATION_H_
+#define SERVICES_NAVIGATION_NAVIGATION_H_
+
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/navigation/public/interfaces/view.mojom.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection_ref.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace navigation {
+
+class Navigation : public shell::ShellClient,
+ public shell::InterfaceFactory<mojom::ViewFactory>,
+ public mojom::ViewFactory {
+ public:
+ Navigation();
+ ~Navigation() override;
+
+ void Init(shell::Connector* connector,
+ content::BrowserContext* browser_context);
+
+ private:
+ // shell::ShellClient:
+ bool AcceptConnection(shell::Connection* connection) override;
+
+ // shell::InterfaceFactory<mojom::ViewFactory>:
+ void Create(shell::Connection* connection,
+ mojom::ViewFactoryRequest request) override;
+
+ // mojom::ViewFactory:
+ void CreateView(mojom::ViewClientPtr client,
+ mojom::ViewRequest request) override;
+
+ void ViewFactoryLost();
+
+ shell::Connector* connector_ = nullptr;
+ shell::ShellConnectionRefFactory ref_factory_;
+ std::set<std::unique_ptr<shell::ShellConnectionRef>> refs_;
+ content::BrowserContext* browser_context_ = nullptr;
+ mojo::BindingSet<mojom::ViewFactory> bindings_;
+ std::vector<std::pair<mojom::ViewClientPtr, mojom::ViewRequest>>
+ pending_creates_;
+
+ DISALLOW_COPY_AND_ASSIGN(Navigation);
+};
+
+} // navigation
+
+#endif // SERVICES_NAVIGATION_NAVIGATION_H_
diff --git a/chromium/services/navigation/navigation_unittest.cc b/chromium/services/navigation/navigation_unittest.cc
new file mode 100644
index 00000000000..a6a7b0f6b4b
--- /dev/null
+++ b/chromium/services/navigation/navigation_unittest.cc
@@ -0,0 +1,77 @@
+// 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 <memory>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "services/navigation/public/interfaces/view.mojom.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_test.h"
+
+namespace navigation {
+
+class NavigationTest : public shell::test::ShellTest,
+ public mojom::ViewClient {
+ public:
+ NavigationTest()
+ : shell::test::ShellTest("exe:navigation_unittests"),
+ binding_(this) {}
+ ~NavigationTest() override {}
+
+ protected:
+ void SetUp() override {
+ shell::test::ShellTest::SetUp();
+ window_manager_connection_ = connector()->Connect("mojo:test_wm");
+ }
+
+ mojom::ViewClientPtr GetViewClient() {
+ return binding_.CreateInterfacePtrAndBind();
+ }
+
+ void QuitOnLoadingStateChange(base::RunLoop* loop) {
+ loop_ = loop;
+ }
+
+ private:
+ // mojom::ViewClient:
+ void LoadingStateChanged(bool is_loading) override {
+ // Should see loading start, then stop.
+ if (++load_count_ == 2 && loop_)
+ loop_->Quit();
+ }
+ void NavigationStateChanged(const GURL& url,
+ const mojo::String& title,
+ bool can_go_back,
+ bool can_go_forward) override {}
+ void LoadProgressChanged(double progress) override {}
+ void ViewCreated(mojom::ViewPtr,
+ mojom::ViewClientRequest,
+ bool,
+ mojo::RectPtr,
+ bool) override {}
+ void Close() override {}
+
+ int load_count_ = 0;
+ mojo::Binding<mojom::ViewClient> binding_;
+ base::RunLoop* loop_ = nullptr;
+ std::unique_ptr<shell::Connection> window_manager_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationTest);
+};
+
+TEST_F(NavigationTest, Navigate) {
+ mojom::ViewFactoryPtr view_factory;
+ connector()->ConnectToInterface("exe:navigation", &view_factory);
+
+ mojom::ViewPtr view;
+ view_factory->CreateView(GetViewClient(), GetProxy(&view));
+ view->NavigateTo(GURL("about:blank"));
+
+ base::RunLoop loop;
+ QuitOnLoadingStateChange(&loop);
+ loop.Run();
+}
+
+} // namespace navigation
diff --git a/chromium/services/navigation/public/interfaces/BUILD.gn b/chromium/services/navigation/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..ec88b94b405
--- /dev/null
+++ b/chromium/services/navigation/public/interfaces/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "view.mojom",
+ ]
+
+ deps = [
+ "//components/mus/public/interfaces",
+ "//ui/mojo/geometry:interfaces",
+ "//url/mojo:url_mojom_gurl",
+ ]
+}
diff --git a/chromium/services/navigation/public/interfaces/view.mojom b/chromium/services/navigation/public/interfaces/view.mojom
new file mode 100644
index 00000000000..0ceead80299
--- /dev/null
+++ b/chromium/services/navigation/public/interfaces/view.mojom
@@ -0,0 +1,42 @@
+// 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.
+
+module navigation.mojom;
+
+import "components/mus/public/interfaces/window_tree.mojom";
+import "ui/mojo/geometry/geometry.mojom";
+import "url/mojo/url.mojom";
+
+interface ViewFactory {
+ CreateView(ViewClient client, View& view);
+};
+
+interface ViewClient {
+ LoadingStateChanged(bool is_loading);
+ NavigationStateChanged(url.mojom.Url url,
+ string title,
+ bool can_go_back,
+ bool can_go_forward);
+ LoadProgressChanged(double progress);
+ ViewCreated(View view,
+ ViewClient& client,
+ bool is_popup,
+ mojo.Rect initial_rect,
+ bool user_gesture);
+ Close();
+};
+
+interface View {
+ // Navigates the view to |url|.
+ NavigateTo(url.mojom.Url url);
+
+ GoBack();
+ GoForward();
+ Reload(bool skip_cache);
+ Stop();
+
+ // Obtains a Mus WindowTreeClient for the View, so it can be embedded in a
+ // UI.
+ GetWindowTreeClient(mus.mojom.WindowTreeClient& client);
+};
diff --git a/chromium/services/navigation/unittest_manifest.json b/chromium/services/navigation/unittest_manifest.json
new file mode 100644
index 00000000000..1040004a1c8
--- /dev/null
+++ b/chromium/services/navigation/unittest_manifest.json
@@ -0,0 +1,13 @@
+{
+ "manifest_version": 1,
+ "name": "exe:navigation_unittests",
+ "display_name": "Navigation Unittests",
+ "capabilities": {
+ "required": {
+ "exe:navigation": {
+ "interfaces": [ "navigation::mojom::ViewFactory" ]
+ },
+ "*": { "classes": [ "app" ] }
+ }
+ }
+}
diff --git a/chromium/services/navigation/view_impl.cc b/chromium/services/navigation/view_impl.cc
new file mode 100644
index 00000000000..227b3580994
--- /dev/null
+++ b/chromium/services/navigation/view_impl.cc
@@ -0,0 +1,139 @@
+// 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 "services/navigation/view_impl.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/mus/public/cpp/window_tree_connection.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/mus/native_widget_mus.h"
+#include "ui/views/widget/widget.h"
+#include "url/gurl.h"
+
+namespace navigation {
+
+ViewImpl::ViewImpl(shell::Connector* connector,
+ content::BrowserContext* browser_context,
+ mojom::ViewClientPtr client,
+ mojom::ViewRequest request,
+ std::unique_ptr<shell::ShellConnectionRef> ref)
+ : connector_(connector),
+ binding_(this, std::move(request)),
+ client_(std::move(client)),
+ ref_(std::move(ref)),
+ web_view_(new views::WebView(browser_context)) {
+ web_view_->GetWebContents()->SetDelegate(this);
+}
+ViewImpl::~ViewImpl() {}
+
+void ViewImpl::NavigateTo(const GURL& url) {
+ web_view_->GetWebContents()->GetController().LoadURL(
+ url, content::Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+}
+
+void ViewImpl::GoBack() {
+ web_view_->GetWebContents()->GetController().GoBack();
+}
+
+void ViewImpl::GoForward() {
+ web_view_->GetWebContents()->GetController().GoForward();
+}
+
+void ViewImpl::Reload(bool skip_cache) {
+ if (skip_cache)
+ web_view_->GetWebContents()->GetController().Reload(true);
+ else
+ web_view_->GetWebContents()->GetController().ReloadBypassingCache(true);
+}
+
+void ViewImpl::Stop() {
+ web_view_->GetWebContents()->Stop();
+}
+
+void ViewImpl::GetWindowTreeClient(
+ mus::mojom::WindowTreeClientRequest request) {
+ mus::WindowTreeConnection::Create(
+ this, std::move(request),
+ mus::WindowTreeConnection::CreateType::DONT_WAIT_FOR_EMBED);
+}
+
+void ViewImpl::AddNewContents(content::WebContents* source,
+ content::WebContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_rect,
+ bool user_gesture,
+ bool* was_blocked) {
+ mojom::ViewClientPtr client;
+ mojom::ViewPtr view;
+ mojom::ViewRequest view_request = GetProxy(&view);
+ client_->ViewCreated(std::move(view), GetProxy(&client),
+ disposition == NEW_POPUP, mojo::Rect::From(initial_rect),
+ user_gesture);
+ ViewImpl* impl =
+ new ViewImpl(connector_, new_contents->GetBrowserContext(),
+ std::move(client), std::move(view_request), ref_->Clone());
+ // TODO(beng): This is a bit crappy. should be able to create the ViewImpl
+ // with |new_contents| instead.
+ impl->web_view_->SetWebContents(new_contents);
+ impl->web_view_->GetWebContents()->SetDelegate(impl);
+
+ // TODO(beng): this reply is currently synchronous, figure out a fix.
+ if (was_blocked)
+ *was_blocked = false;
+}
+
+void ViewImpl::CloseContents(content::WebContents* source) {
+ client_->Close();
+}
+
+void ViewImpl::LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) {
+ client_->LoadingStateChanged(source->IsLoading());
+}
+
+void ViewImpl::NavigationStateChanged(content::WebContents* source,
+ content::InvalidateTypes changed_flags) {
+ client_->NavigationStateChanged(source->GetVisibleURL(),
+ base::UTF16ToUTF8(source->GetTitle()),
+ source->GetController().CanGoBack(),
+ source->GetController().CanGoForward());
+}
+
+void ViewImpl::LoadProgressChanged(content::WebContents* source,
+ double progress) {
+ client_->LoadProgressChanged(progress);
+}
+
+void ViewImpl::OnEmbed(mus::Window* root) {
+ DCHECK(!widget_.get());
+ widget_.reset(new views::Widget);
+ views::Widget::InitParams params(
+ views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.delegate = this;
+ params.native_widget = new views::NativeWidgetMus(
+ widget_.get(), connector_, root, mus::mojom::SurfaceType::DEFAULT);
+ widget_->Init(params);
+ widget_->Show();
+}
+
+void ViewImpl::OnConnectionLost(mus::WindowTreeConnection* connection) {}
+void ViewImpl::OnEventObserved(const ui::Event& event, mus::Window* target) {}
+
+views::View* ViewImpl::GetContentsView() {
+ return web_view_;
+}
+
+views::Widget* ViewImpl::GetWidget() {
+ return web_view_->GetWidget();
+}
+
+const views::Widget* ViewImpl::GetWidget() const {
+ return web_view_->GetWidget();
+}
+
+} // navigation
diff --git a/chromium/services/navigation/view_impl.h b/chromium/services/navigation/view_impl.h
new file mode 100644
index 00000000000..426185f7c9c
--- /dev/null
+++ b/chromium/services/navigation/view_impl.h
@@ -0,0 +1,89 @@
+// 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 SERVICES_NAVIGATION_VIEW_IMPL_H_
+#define SERVICES_NAVIGATION_VIEW_IMPL_H_
+
+#include "base/macros.h"
+#include "components/mus/public/cpp/window_tree_delegate.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/navigation/public/interfaces/view.mojom.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection_ref.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+class WebView;
+class Widget;
+}
+
+namespace navigation {
+
+class ViewImpl : public mojom::View,
+ public content::WebContentsDelegate,
+ public mus::WindowTreeDelegate,
+ public views::WidgetDelegate {
+ public:
+ ViewImpl(shell::Connector* connector,
+ content::BrowserContext* browser_context,
+ mojom::ViewClientPtr client,
+ mojom::ViewRequest request,
+ std::unique_ptr<shell::ShellConnectionRef> ref);
+ ~ViewImpl() override;
+
+ private:
+ // mojom::View:
+ void NavigateTo(const GURL& url) override;
+ void GoBack() override;
+ void GoForward() override;
+ void Reload(bool skip_cache) override;
+ void Stop() override;
+ void GetWindowTreeClient(
+ mus::mojom::WindowTreeClientRequest request) override;
+
+ // content::WebContentsDelegate:
+ void AddNewContents(content::WebContents* source,
+ content::WebContents* new_contents,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_rect,
+ bool user_gesture,
+ bool* was_blocked) override;
+ void CloseContents(content::WebContents* source) override;
+ void LoadingStateChanged(content::WebContents* source,
+ bool to_different_document) override;
+ void NavigationStateChanged(content::WebContents* source,
+ content::InvalidateTypes changed_flags) override;
+ void LoadProgressChanged(content::WebContents* source,
+ double progress) override;
+
+ // mus::WindowTreeDelegate:
+ void OnEmbed(mus::Window* root) override;
+ void OnConnectionLost(mus::WindowTreeConnection* connection) override;
+ void OnEventObserved(const ui::Event& event, mus::Window* target) override;
+
+ // views::WidgetDelegate:
+ views::View* GetContentsView() override;
+ views::Widget* GetWidget() override;
+ const views::Widget* GetWidget() const override;
+
+ shell::Connector* connector_;
+ mojo::StrongBinding<mojom::View> binding_;
+ mojom::ViewClientPtr client_;
+ std::unique_ptr<shell::ShellConnectionRef> ref_;
+
+ views::WebView* web_view_;
+
+ std::unique_ptr<content::WebContents> web_contents_;
+
+ std::unique_ptr<views::Widget> widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViewImpl);
+};
+
+} // navigation
+
+#endif // SERVICES_NAVIGATION_VIEW_IMPL_H_
diff --git a/chromium/services/shell/BUILD.gn b/chromium/services/shell/BUILD.gn
new file mode 100644
index 00000000000..a854f36aaec
--- /dev/null
+++ b/chromium/services/shell/BUILD.gn
@@ -0,0 +1,58 @@
+# 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.
+
+import("//mojo/public/mojo_application_manifest.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
+
+group("all") {
+ testonly = true
+ deps = [
+ ":shell",
+ "//services/shell/background",
+ "//services/shell/runner",
+ "//services/shell/standalone",
+ "//services/shell/tests",
+ ]
+}
+
+source_set("shell") {
+ output_name = "mojo_shell"
+ sources = [
+ "connect_params.cc",
+ "connect_params.h",
+ "connect_util.cc",
+ "connect_util.h",
+ "native_runner.h",
+ "native_runner_delegate.h",
+ "shell.cc",
+ "shell.h",
+ "switches.cc",
+ "switches.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//mojo/common",
+ "//mojo/public/cpp/bindings",
+ "//services/catalog/public/interfaces",
+ "//services/shell/public/cpp:sources",
+ "//services/shell/public/interfaces",
+ ]
+
+ public_deps = [
+ # ApplicationManager exposes and uses PackageManager types in its header.
+ "//services/catalog:lib",
+ ]
+
+ data_deps = [
+ ":manifest",
+ ]
+}
+
+mojo_application_manifest("manifest") {
+ application_name = "shell"
+ source = "manifest.json"
+}
diff --git a/chromium/services/shell/OWNERS b/chromium/services/shell/OWNERS
new file mode 100644
index 00000000000..5bd620a16dc
--- /dev/null
+++ b/chromium/services/shell/OWNERS
@@ -0,0 +1,5 @@
+amistry@chromium.org
+ben@chromium.org
+jam@chromium.org
+rockot@chromium.org
+sky@chromium.org
diff --git a/chromium/services/shell/background/BUILD.gn b/chromium/services/shell/background/BUILD.gn
new file mode 100644
index 00000000000..067f6eb58db
--- /dev/null
+++ b/chromium/services/shell/background/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+group("background") {
+ testonly = true
+ deps = [
+ ":lib",
+ ":main",
+ ]
+}
+
+source_set("lib") {
+ sources = [
+ "background_shell.cc",
+ "background_shell.h",
+ ]
+ deps = [
+ "//base",
+ "//services/catalog:lib",
+ "//services/shell",
+ "//services/shell/public/cpp:sources",
+ "//services/shell/runner:init",
+ "//services/shell/standalone:lib",
+ ]
+}
+
+source_set("main") {
+ sources = [
+ "background_shell_main.cc",
+ "background_shell_main.h",
+ ]
+ deps = [
+ "//base",
+ "//services/shell",
+ "//services/shell/public/cpp:sources",
+ "//services/shell/runner:init",
+ "//services/shell/runner/common",
+ "//services/shell/runner/host:lib",
+ "//services/shell/standalone:lib",
+ ]
+}
diff --git a/chromium/services/shell/background/DEPS b/chromium/services/shell/background/DEPS
new file mode 100644
index 00000000000..3fd6080bf1e
--- /dev/null
+++ b/chromium/services/shell/background/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+services/catalog",
+]
diff --git a/chromium/services/shell/background/background_shell.cc b/chromium/services/shell/background/background_shell.cc
new file mode 100644
index 00000000000..4c42c09dda5
--- /dev/null
+++ b/chromium/services/shell/background/background_shell.cc
@@ -0,0 +1,174 @@
+// 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 "services/shell/background/background_shell.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_pump_default.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/simple_thread.h"
+#include "services/catalog/store.h"
+#include "services/shell/connect_params.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/shell.h"
+#include "services/shell/standalone/context.h"
+
+namespace shell {
+
+namespace {
+
+std::unique_ptr<base::MessagePump> CreateDefaultMessagePump() {
+ return base::WrapUnique(new base::MessagePumpDefault);
+}
+
+class MojoMessageLoop : public base::MessageLoop {
+ public:
+ MojoMessageLoop()
+ : base::MessageLoop(base::MessageLoop::TYPE_CUSTOM,
+ base::Bind(&CreateDefaultMessagePump)) {}
+ ~MojoMessageLoop() override {}
+
+ void BindToCurrentThread() { base::MessageLoop::BindToCurrentThread(); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MojoMessageLoop);
+};
+
+} // namespace
+
+// Manages the thread to startup mojo.
+class BackgroundShell::MojoThread : public base::SimpleThread {
+ public:
+ explicit MojoThread(std::unique_ptr<BackgroundShell::InitParams> init_params)
+ : SimpleThread("mojo-background-shell"),
+ init_params_(std::move(init_params)) {}
+ ~MojoThread() override {}
+
+ void CreateShellClientRequest(base::WaitableEvent* signal,
+ const std::string& name,
+ mojom::ShellClientRequest* request) {
+ // Only valid to call this on the background thread.
+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
+ *request = context_->shell()->InitInstanceForEmbedder(name);
+ signal->Signal();
+ }
+
+ void Connect(std::unique_ptr<ConnectParams> params) {
+ context_->shell()->Connect(std::move(params));
+ }
+
+ base::MessageLoop* message_loop() { return message_loop_; }
+
+ // Stops the background thread.
+ void Stop() {
+ DCHECK_NE(message_loop_, base::MessageLoop::current());
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ Join();
+ }
+
+ void RunShellCallback(const BackgroundShell::ShellThreadCallback& callback) {
+ DCHECK_EQ(message_loop_, base::MessageLoop::current());
+ callback.Run(context_->shell());
+ }
+
+ // base::SimpleThread:
+ void Start() override {
+ DCHECK(!message_loop_);
+ message_loop_ = new MojoMessageLoop;
+ base::SimpleThread::Start();
+ }
+ void Run() override {
+ // The construction/destruction order is very finicky and has to be done
+ // in the order here.
+ std::unique_ptr<base::MessageLoop> message_loop(message_loop_);
+
+ std::unique_ptr<Context::InitParams> context_init_params(
+ new Context::InitParams);
+ if (init_params_) {
+ context_init_params->catalog_store =
+ std::move(init_params_->catalog_store);
+ context_init_params->native_runner_delegate =
+ init_params_->native_runner_delegate;
+ context_init_params->init_edk = init_params_->init_edk;
+ }
+ if (context_init_params->init_edk)
+ Context::EnsureEmbedderIsInitialized();
+
+ message_loop_->BindToCurrentThread();
+
+ std::unique_ptr<Context> context(new Context);
+ context_ = context.get();
+ context_->Init(std::move(context_init_params));
+
+ message_loop_->Run();
+
+ // Has to happen after run, but while messageloop still valid.
+ context_->Shutdown();
+
+ // Context has to be destroyed after the MessageLoop has been destroyed.
+ message_loop.reset();
+ context_ = nullptr;
+ }
+
+ private:
+ // We own this. It's created on the main thread, but destroyed on the
+ // background thread.
+ MojoMessageLoop* message_loop_ = nullptr;
+ // Created in Run() on the background thread.
+ Context* context_ = nullptr;
+
+ std::unique_ptr<BackgroundShell::InitParams> init_params_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoThread);
+};
+
+BackgroundShell::InitParams::InitParams() {}
+BackgroundShell::InitParams::~InitParams() {}
+
+BackgroundShell::BackgroundShell() {}
+
+BackgroundShell::~BackgroundShell() {
+ thread_->Stop();
+}
+
+void BackgroundShell::Init(std::unique_ptr<InitParams> init_params) {
+ DCHECK(!thread_);
+ thread_.reset(new MojoThread(std::move(init_params)));
+ thread_->Start();
+}
+
+mojom::ShellClientRequest BackgroundShell::CreateShellClientRequest(
+ const std::string& name) {
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(CreateShellIdentity());
+ params->set_target(Identity(name, mojom::kRootUserID));
+ mojom::ShellClientRequest request;
+ base::WaitableEvent signal(true, false);
+ thread_->message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MojoThread::CreateShellClientRequest,
+ base::Unretained(thread_.get()), &signal, name,
+ &request));
+ signal.Wait();
+ thread_->message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MojoThread::Connect,
+ base::Unretained(thread_.get()),
+ base::Passed(&params)));
+ return request;
+}
+
+void BackgroundShell::ExecuteOnShellThread(
+ const ShellThreadCallback& callback) {
+ thread_->message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&MojoThread::RunShellCallback,
+ base::Unretained(thread_.get()), callback));
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/background/background_shell.h b/chromium/services/shell/background/background_shell.h
new file mode 100644
index 00000000000..8b48dd53794
--- /dev/null
+++ b/chromium/services/shell/background/background_shell.h
@@ -0,0 +1,67 @@
+// 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 SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_H_
+#define SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/catalog/store.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace catalog {
+class Store;
+}
+
+namespace shell {
+
+class NativeRunnerDelegate;
+class Shell;
+
+// BackgroundShell starts up the mojo shell on a background thread, and
+// destroys the thread in the destructor. Once created use CreateApplication()
+// to obtain an InterfaceRequest for the Application. The InterfaceRequest can
+// then be bound to an ApplicationImpl.
+class BackgroundShell {
+ public:
+ struct InitParams {
+ InitParams();
+ ~InitParams();
+
+ NativeRunnerDelegate* native_runner_delegate = nullptr;
+ std::unique_ptr<catalog::Store> catalog_store;
+ // If true the edk is initialized.
+ bool init_edk = true;
+ };
+
+ BackgroundShell();
+ ~BackgroundShell();
+
+ // Starts the background shell. |command_line_switches| are additional
+ // switches applied to any processes spawned by this call.
+ void Init(std::unique_ptr<InitParams> init_params);
+
+ // Obtains an InterfaceRequest for the specified name.
+ mojom::ShellClientRequest CreateShellClientRequest(
+ const std::string& name);
+
+ // Use to do processing on the thread running the shell. The callback is
+ // supplied a pointer to the Shell. The callback does *not* own the Shell.
+ using ShellThreadCallback = base::Callback<void(Shell*)>;
+ void ExecuteOnShellThread(const ShellThreadCallback& callback);
+
+ private:
+ class MojoThread;
+
+ std::unique_ptr<MojoThread> thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackgroundShell);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_H_
diff --git a/chromium/services/shell/background/background_shell_main.cc b/chromium/services/shell/background/background_shell_main.cc
new file mode 100644
index 00000000000..e8d7b21c32f
--- /dev/null
+++ b/chromium/services/shell/background/background_shell_main.cc
@@ -0,0 +1,41 @@
+// 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 "services/shell/background/background_shell_main.h"
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/process/launch.h"
+#include "services/shell/runner/common/switches.h"
+#include "services/shell/runner/host/child_process.h"
+#include "services/shell/runner/init.h"
+
+namespace shell {
+namespace {
+
+int RunChildProcess() {
+ base::AtExitManager at_exit;
+ InitializeLogging();
+ WaitForDebuggerIfNecessary();
+#if !defined(OFFICIAL_BUILD) && defined(OS_WIN)
+ base::RouteStdioToConsole(false);
+#endif
+ return ChildProcessMain();
+}
+
+} // namespace
+} // namespace shell
+
+int main(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kChildProcess)) {
+ return shell::RunChildProcess();
+ }
+ // Reset CommandLine as most likely main() is going to use CommandLine too
+ // and expect to be able to initialize it.
+ base::CommandLine::Reset();
+ return MasterProcessMain(argc, argv);
+}
diff --git a/chromium/services/shell/background/background_shell_main.h b/chromium/services/shell/background/background_shell_main.h
new file mode 100644
index 00000000000..1475c357dea
--- /dev/null
+++ b/chromium/services/shell/background/background_shell_main.h
@@ -0,0 +1,12 @@
+// 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 SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_MAIN_H_
+#define SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_MAIN_H_
+
+// The "main" gn target supplies a file with a main() that calls to the child
+// process as necessary. For the main process this function is called.
+int MasterProcessMain(int argc, char** argv);
+
+#endif // SERVICES_SHELL_BACKGROUND_BACKGROUND_SHELL_MAIN_H_
diff --git a/chromium/services/shell/connect_params.cc b/chromium/services/shell/connect_params.cc
new file mode 100644
index 00000000000..d59ba1fcd44
--- /dev/null
+++ b/chromium/services/shell/connect_params.cc
@@ -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.
+
+#include "services/shell/connect_params.h"
+
+namespace shell {
+
+ConnectParams::ConnectParams() {}
+ConnectParams::~ConnectParams() {}
+
+} // namespace shell
diff --git a/chromium/services/shell/connect_params.h b/chromium/services/shell/connect_params.h
new file mode 100644
index 00000000000..7bd2ad5f413
--- /dev/null
+++ b/chromium/services/shell/connect_params.h
@@ -0,0 +1,77 @@
+// 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 SERVICES_SHELL_CONNECT_PARAMS_H_
+#define SERVICES_SHELL_CONNECT_PARAMS_H_
+
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+
+// This class represents a request for the application manager to connect to an
+// application.
+class ConnectParams {
+ public:
+ ConnectParams();
+ ~ConnectParams();
+
+ void set_source(const Identity& source) { source_ = source; }
+ const Identity& source() const { return source_; }
+ void set_target(const Identity& target) { target_ = target; }
+ const Identity& target() const { return target_; }
+
+ void set_remote_interfaces(mojom::InterfaceProviderRequest value) {
+ remote_interfaces_ = std::move(value);
+ }
+ mojom::InterfaceProviderRequest TakeRemoteInterfaces() {
+ return std::move(remote_interfaces_);
+ }
+
+ void set_local_interfaces(mojom::InterfaceProviderPtr value) {
+ local_interfaces_ = std::move(value);
+ }
+ mojom::InterfaceProviderPtr TakeLocalInterfaces() {
+ return std::move(local_interfaces_);
+ }
+
+ void set_client_process_connection(
+ mojom::ClientProcessConnectionPtr client_process_connection) {
+ client_process_connection_ = std::move(client_process_connection);
+ }
+ mojom::ClientProcessConnectionPtr TakeClientProcessConnection() {
+ return std::move(client_process_connection_);
+ }
+
+ void set_connect_callback(const mojom::Connector::ConnectCallback& value) {
+ connect_callback_ = value;
+ }
+ const mojom::Connector::ConnectCallback& connect_callback() const {
+ return connect_callback_;
+ }
+
+ private:
+ // It may be null (i.e., is_null() returns true) which indicates that there is
+ // no source (e.g., for the first application or in tests).
+ Identity source_;
+ // The identity of the application being connected to.
+ Identity target_;
+
+ mojom::InterfaceProviderRequest remote_interfaces_;
+ mojom::InterfaceProviderPtr local_interfaces_;
+ mojom::ClientProcessConnectionPtr client_process_connection_;
+ mojom::Connector::ConnectCallback connect_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectParams);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_CONNECT_PARAMS_H_
diff --git a/chromium/services/shell/connect_util.cc b/chromium/services/shell/connect_util.cc
new file mode 100644
index 00000000000..45b468ec102
--- /dev/null
+++ b/chromium/services/shell/connect_util.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 "services/shell/connect_util.h"
+
+#include <memory>
+#include <utility>
+
+#include "services/shell/connect_params.h"
+#include "services/shell/shell.h"
+
+namespace shell {
+
+mojo::ScopedMessagePipeHandle ConnectToInterfaceByName(
+ Shell* shell,
+ const Identity& source,
+ const Identity& target,
+ const std::string& interface_name) {
+ mojom::InterfaceProviderPtr remote_interfaces;
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(source);
+ params->set_target(target);
+ params->set_remote_interfaces(mojo::GetProxy(&remote_interfaces));
+ shell->Connect(std::move(params));
+ mojo::MessagePipe pipe;
+ remote_interfaces->GetInterface(interface_name, std::move(pipe.handle1));
+ return std::move(pipe.handle0);
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/connect_util.h b/chromium/services/shell/connect_util.h
new file mode 100644
index 00000000000..d5602251ac9
--- /dev/null
+++ b/chromium/services/shell/connect_util.h
@@ -0,0 +1,47 @@
+// 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 SERVICES_SHELL_CONNECT_UTIL_H_
+#define SERVICES_SHELL_CONNECT_UTIL_H_
+
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+
+namespace shell {
+
+class Shell;
+
+mojo::ScopedMessagePipeHandle ConnectToInterfaceByName(
+ Shell* shell,
+ const Identity& source,
+ const Identity& target,
+ const std::string& interface_name);
+
+// Must only be used by shell internals and test code as it does not forward
+// capability filters. Runs |name| with a permissive capability filter.
+template <typename Interface>
+inline void ConnectToInterface(Shell* shell,
+ const Identity& source,
+ const Identity& target,
+ mojo::InterfacePtr<Interface>* ptr) {
+ mojo::ScopedMessagePipeHandle service_handle =
+ ConnectToInterfaceByName(shell, source, target, Interface::Name_);
+ ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(service_handle), 0u));
+}
+
+template <typename Interface>
+inline void ConnectToInterface(Shell* shell,
+ const Identity& source,
+ const std::string& name,
+ mojo::InterfacePtr<Interface>* ptr) {
+ mojo::ScopedMessagePipeHandle service_handle = ConnectToInterfaceByName(
+ shell, source, Identity(name, mojom::kInheritUserID), Interface::Name_);
+ ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(service_handle), 0u));
+}
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_CONNECT_UTIL_H_
diff --git a/chromium/services/shell/manifest.json b/chromium/services/shell/manifest.json
new file mode 100644
index 00000000000..bf91a389981
--- /dev/null
+++ b/chromium/services/shell/manifest.json
@@ -0,0 +1,29 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:shell",
+ "display_name": "Service Manager",
+ "capabilities": {
+ "provided": {
+ // Clients requesting this class are able to connect to other clients as
+ // specific users other than their own.
+ "shell:user_id": [ ],
+ // Clients requesting this class are allowed to register clients for
+ // processes they launch themselves.
+ "shell:client_process": [ ],
+ // Clients requesting this class are allowed to connect to other clients
+ // in specific process instance groups.
+ "shell:instance_name": [ ],
+ // Clients requesting this class are run as a unique user id which is
+ // visible to clients run as any user.
+ "shell:all_users": [ ],
+ "shell:block_wildcard": [ ],
+ // Clients requesting this class block inbound requests to bind interfaces
+ // from other sources who specify wildcard rules in their manifest
+ // capability interface sets.
+ "shell:explicit_class": [ ]
+ },
+ "required": {
+ "mojo:shell": { "classes": [ "shell:all_users" ] }
+ }
+ }
+}
diff --git a/chromium/services/shell/mojo_shell_unittests.isolate b/chromium/services/shell/mojo_shell_unittests.isolate
new file mode 100644
index 00000000000..4259f2ba925
--- /dev/null
+++ b/chromium/services/shell/mojo_shell_unittests.isolate
@@ -0,0 +1,23 @@
+# 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.
+{
+ 'includes': [
+ '../../base/base.isolate',
+ ],
+ 'conditions': [
+ ['OS=="win" or OS=="mac" or OS=="linux"', {
+ 'variables': {
+ 'command': [
+ '../../testing/test_env.py',
+ '<(PRODUCT_DIR)/mojo_shell_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ ],
+ 'files': [
+ '../../testing/test_env.py',
+ ],
+ },
+ }],
+ ],
+}
diff --git a/chromium/services/shell/native_runner.h b/chromium/services/shell/native_runner.h
new file mode 100644
index 00000000000..c81d2adf93c
--- /dev/null
+++ b/chromium/services/shell/native_runner.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 SERVICES_SHELL_NATIVE_RUNNER_H_
+#define SERVICES_SHELL_NATIVE_RUNNER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/process/process_handle.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace shell {
+class Identity;
+
+// Shell requires implementations of NativeRunner and NativeRunnerFactory to run
+// native applications.
+class NativeRunner {
+ public:
+ virtual ~NativeRunner() {}
+
+ // Loads the app in the file at |app_path| and runs it on some other
+ // thread/process. Returns a ShellClient handle the shell can use to connect
+ // to the the app.
+ virtual mojom::ShellClientPtr Start(
+ const base::FilePath& app_path,
+ const Identity& target,
+ bool start_sandboxed,
+ const base::Callback<void(base::ProcessId)>& pid_available_callback,
+ const base::Closure& app_completed_callback) = 0;
+};
+
+class NativeRunnerFactory {
+ public:
+ virtual ~NativeRunnerFactory() {}
+ virtual std::unique_ptr<NativeRunner> Create(
+ const base::FilePath& app_path) = 0;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_NATIVE_RUNNER_H_
diff --git a/chromium/services/shell/native_runner_delegate.h b/chromium/services/shell/native_runner_delegate.h
new file mode 100644
index 00000000000..8c22d5a52b6
--- /dev/null
+++ b/chromium/services/shell/native_runner_delegate.h
@@ -0,0 +1,29 @@
+// 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 SERVICES_SHELL_NATIVE_RUNNER_DELEGATE_H_
+#define SERVICES_SHELL_NATIVE_RUNNER_DELEGATE_H_
+
+namespace base {
+class CommandLine;
+}
+
+namespace shell {
+class Identity;
+
+class NativeRunnerDelegate {
+ public:
+ // Called to adjust the commandline for launching the specified app.
+ // WARNING: this is called on a background thread.
+ virtual void AdjustCommandLineArgumentsForTarget(
+ const Identity& target,
+ base::CommandLine* command_line) = 0;
+
+ protected:
+ virtual ~NativeRunnerDelegate() {}
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_NATIVE_RUNNER_DELEGATE_H_
diff --git a/chromium/services/shell/public/cpp/BUILD.gn b/chromium/services/shell/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..cbfac3a258f
--- /dev/null
+++ b/chromium/services/shell/public/cpp/BUILD.gn
@@ -0,0 +1,89 @@
+# 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.
+
+# GYP version: mojo/mojo_base.gyp:mojo_application_base
+source_set("cpp") {
+ public_deps = [
+ ":sources",
+ ]
+}
+
+# TODO(rockot): Rename this to "cpp".
+source_set("sources") {
+ sources = [
+ "application_runner.h",
+ "capabilities.h",
+ "connect.h",
+ "connection.h",
+ "connector.h",
+ "identity.h",
+ "interface_binder.h",
+ "interface_factory.h",
+ "interface_factory_impl.h",
+ "interface_registry.h",
+ "lib/application_runner.cc",
+ "lib/capabilities.cc",
+ "lib/connection_impl.cc",
+ "lib/connection_impl.h",
+ "lib/connector_impl.cc",
+ "lib/connector_impl.h",
+ "lib/identity.cc",
+ "lib/interface_factory_binder.h",
+ "lib/interface_registry.cc",
+ "lib/names.cc",
+ "lib/shell_client.cc",
+ "lib/shell_connection.cc",
+ "lib/shell_connection_ref.cc",
+ "names.h",
+ "shell_client.h",
+ "shell_connection.h",
+ "shell_connection_ref.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/system",
+ "//services/shell/public/interfaces",
+ "//url",
+ ]
+}
+
+source_set("application_support") {
+ sources = [
+ "lib/init_commandline.cc",
+ "lib/initialize_base_and_icu.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//base:i18n",
+ "//mojo/public/c/system",
+ ]
+}
+
+source_set("shell_test_support") {
+ testonly = true
+ sources = [
+ "lib/shell_test.cc",
+ "shell_test.h",
+ ]
+
+ public_deps = [
+ ":cpp",
+ "//testing/gtest",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//mojo/logging",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/system",
+ "//services/shell/background:lib",
+ "//services/shell/public/interfaces:interfaces_cpp_sources",
+ ]
+
+ data_deps = []
+}
diff --git a/chromium/services/shell/public/cpp/application_runner.h b/chromium/services/shell/public/cpp/application_runner.h
new file mode 100644
index 00000000000..36d79e36fa4
--- /dev/null
+++ b/chromium/services/shell/public/cpp/application_runner.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
+#define SERVICES_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
+
+#include <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace shell {
+
+class ShellClient;
+class ShellConnection;
+
+// A utility for running a chromium based mojo Application. The typical use
+// case is to use when writing your MojoMain:
+//
+// MojoResult MojoMain(MojoHandle shell_handle) {
+// shell::ApplicationRunner runner(new MyDelegate());
+// return runner.Run(shell_handle);
+// }
+//
+// ApplicationRunner takes care of chromium environment initialization and
+// shutdown, and starting a MessageLoop from which your application can run and
+// ultimately Quit().
+class ApplicationRunner {
+ public:
+ // Takes ownership of |client|.
+ explicit ApplicationRunner(ShellClient* client);
+ ~ApplicationRunner();
+
+ static void InitBaseCommandLine();
+
+ void set_message_loop_type(base::MessageLoop::Type type);
+
+ // Once the various parameters have been set above, use Run to initialize an
+ // ShellConnection 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);
+
+ // Allows the caller to shut down the connection with the shell. After the
+ // shell notices the pipe has closed, it will no longer track an instance of
+ // this application, though this application may continue to run and service
+ // requests from others.
+ void DestroyShellConnection();
+
+ // Allows the caller to explicitly quit the application. Must be called from
+ // the thread which created the ApplicationRunner.
+ void Quit();
+
+ private:
+ std::unique_ptr<ShellConnection> connection_;
+ std::unique_ptr<ShellClient> client_;
+
+ // MessageLoop type. TYPE_CUSTOM is default (MessagePumpMojo will be used as
+ // the underlying message pump).
+ base::MessageLoop::Type message_loop_type_;
+ // Whether Run() has been called.
+ bool has_run_;
+
+ DISALLOW_COPY_AND_ASSIGN(ApplicationRunner);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_H_
diff --git a/chromium/services/shell/public/cpp/capabilities.h b/chromium/services/shell/public/cpp/capabilities.h
new file mode 100644
index 00000000000..53eaf7d2b12
--- /dev/null
+++ b/chromium/services/shell/public/cpp/capabilities.h
@@ -0,0 +1,77 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_CAPABILITIES_H_
+#define SERVICES_SHELL_PUBLIC_CPP_CAPABILITIES_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "services/shell/public/interfaces/shell_resolver.mojom.h"
+
+namespace shell {
+
+using Class = std::string;
+using Classes = std::set<std::string>;
+using Interface = std::string;
+using Interfaces = std::set<std::string>;
+using Name = std::string;
+
+// See comments in services/shell/public/interfaces/capabilities.mojom for a
+// description of CapabilityRequest and CapabilitySpec.
+
+struct CapabilityRequest {
+ CapabilityRequest();
+ CapabilityRequest(const CapabilityRequest& other);
+ ~CapabilityRequest();
+ bool operator==(const CapabilityRequest& other) const;
+ bool operator<(const CapabilityRequest& other) const;
+ Classes classes;
+ Interfaces interfaces;
+};
+
+struct CapabilitySpec {
+ CapabilitySpec();
+ CapabilitySpec(const CapabilitySpec& other);
+ ~CapabilitySpec();
+ bool operator==(const CapabilitySpec& other) const;
+ bool operator<(const CapabilitySpec& other) const;
+ std::map<Class, Interfaces> provided;
+ std::map<Name, CapabilityRequest> required;
+};
+
+} // namespace shell
+
+namespace mojo {
+
+template <>
+struct TypeConverter<shell::mojom::CapabilitySpecPtr, shell::CapabilitySpec> {
+ static shell::mojom::CapabilitySpecPtr Convert(
+ const shell::CapabilitySpec& input);
+};
+
+template <>
+struct TypeConverter<shell::CapabilitySpec, shell::mojom::CapabilitySpecPtr> {
+ static shell::CapabilitySpec Convert(
+ const shell::mojom::CapabilitySpecPtr& input);
+};
+
+template <>
+struct TypeConverter<shell::mojom::CapabilityRequestPtr,
+ shell::CapabilityRequest> {
+ static shell::mojom::CapabilityRequestPtr Convert(
+ const shell::CapabilityRequest& input);
+};
+
+template <>
+struct TypeConverter<shell::CapabilityRequest,
+ shell::mojom::CapabilityRequestPtr> {
+ static shell::CapabilityRequest Convert(
+ const shell::mojom::CapabilityRequestPtr& input);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_CAPABILITIES_H_
diff --git a/chromium/services/shell/public/cpp/connect.h b/chromium/services/shell/public/cpp/connect.h
new file mode 100644
index 00000000000..ecce18b9ef6
--- /dev/null
+++ b/chromium/services/shell/public/cpp/connect.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_CONNECT_H_
+#define SERVICES_SHELL_PUBLIC_CPP_CONNECT_H_
+
+#include <utility>
+
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+
+// Binds |ptr| to a remote implementation of Interface from |interfaces|.
+template <typename Interface>
+inline void GetInterface(mojom::InterfaceProvider* interfaces,
+ mojo::InterfacePtr<Interface>* ptr) {
+ mojo::MessagePipe pipe;
+ ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
+ interfaces->GetInterface(Interface::Name_, std::move(pipe.handle1));
+}
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_CONNECT_H_
diff --git a/chromium/services/shell/public/cpp/connection.h b/chromium/services/shell/public/cpp/connection.h
new file mode 100644
index 00000000000..989af5486f6
--- /dev/null
+++ b/chromium/services/shell/public/cpp/connection.h
@@ -0,0 +1,147 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_CONNECTION_H_
+#define SERVICES_SHELL_PUBLIC_CPP_CONNECTION_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "services/shell/public/cpp/connect.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/cpp/interface_registry.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+
+class InterfaceBinder;
+
+// Represents a connection to another application. An instance of this class is
+// returned from Shell's ConnectToApplication(), and passed to ShellClient's
+// AcceptConnection() each time an incoming connection is received.
+//
+// Call AddService<T>(factory) to expose an interface to the remote application,
+// and GetInterface(&interface_ptr) to consume an interface exposed by the
+// remote application.
+//
+// Internally, this class wraps an InterfaceRegistry that accepts interfaces
+// that may be exposed to a remote application. See documentation in
+// interface_registry.h for more information.
+//
+// A Connection returned via Shell::ConnectToApplication() is owned by the
+// caller.
+// An Connection received via AcceptConnection is owned by the ShellConnection.
+// To close a connection, call CloseConnection which will destroy this object.
+class Connection {
+ public:
+ virtual ~Connection() {}
+
+ enum class State {
+ // The shell has not yet processed the connection.
+ PENDING,
+
+ // The shell processed the connection and it was established. GetResult()
+ // returns mojom::ConnectionResult::SUCCESS.
+ CONNECTED,
+
+ // The shell processed the connection and establishment was prevented by
+ // an error, call GetResult().
+ DISCONNECTED
+ };
+
+ class TestApi {
+ public:
+ explicit TestApi(Connection* connection) : connection_(connection) {}
+ base::WeakPtr<Connection> GetWeakPtr() {
+ return connection_->GetWeakPtr();
+ }
+
+ private:
+ Connection* connection_;
+ };
+
+ // Allow the remote application to request instances of Interface.
+ // |factory| will create implementations of Interface on demand.
+ // Returns true if the interface was exposed, false if capability filtering
+ // from the shell prevented the interface from being exposed.
+ template <typename Interface>
+ bool AddInterface(InterfaceFactory<Interface>* factory) {
+ return GetLocalRegistry()->AddInterface<Interface>(factory);
+ }
+
+ // Binds |ptr| to an implemention of Interface in the remote application.
+ // |ptr| can immediately be used to start sending requests to the remote
+ // interface.
+ template <typename Interface>
+ void GetInterface(mojo::InterfacePtr<Interface>* ptr) {
+ shell::GetInterface(GetRemoteInterfaces(), ptr);
+ }
+
+ // Returns true if the remote application has the specified capability class
+ // specified in its manifest. Only valid for inbound connections. Will return
+ // false for outbound connections.
+ virtual bool HasCapabilityClass(const std::string& class_name) const = 0;
+
+ // Returns the name that was used by the source application to establish a
+ // connection to the destination application.
+ //
+ // When Connection is representing and outgoing connection, this will be the
+ // same as the value returned by GetRemoveApplicationName().
+ virtual const std::string& GetConnectionName() = 0;
+
+ // Returns the remote identity. While the connection is in the pending state,
+ // the user_id() field will be the value passed via Connect(). After the
+ // connection is completed, it will change to the value assigned by the shell.
+ // Call AddConnectionCompletedClosure() to schedule a closure to be run when
+ // the resolved user id is available.
+ virtual const Identity& GetRemoteIdentity() const = 0;
+
+ // Register a handler to receive an error notification on the pipe to the
+ // remote application's InterfaceProvider.
+ virtual void SetConnectionLostClosure(const mojo::Closure& handler) = 0;
+
+ // Returns the result of the connection. This function should only be called
+ // when the connection state is not pending. Call
+ // AddConnectionCompletedClosure() to schedule a closure to be run when the
+ // connection is processed by the shell.
+ virtual mojom::ConnectResult GetResult() const = 0;
+
+ // Returns true if the connection has not yet been processed by the shell.
+ virtual bool IsPending() const = 0;
+
+ // Returns the instance id of the remote application if it is known at the
+ // time this function is called. When IsPending() returns true, this function
+ // will return mojom::kInvalidInstanceID. Use
+ // AddConnectionCompletedClosure() to schedule a closure to be run when the
+ // connection is processed by the shell and remote id is available.
+ virtual uint32_t GetRemoteInstanceID() const = 0;
+
+ // Register a closure to be run when the connection has been completed by the
+ // shell and remote metadata is available. Useful only for connections created
+ // via Connector::Connect(). Once the connection is complete, metadata is
+ // available immediately.
+ virtual void AddConnectionCompletedClosure(const mojo::Closure& callback) = 0;
+
+ // Returns true if the Shell allows |interface_name| to be exposed to the
+ // remote application.
+ virtual bool AllowsInterface(const std::string& interface_name) const = 0;
+
+ // Returns the raw proxy to the remote application's InterfaceProvider
+ // interface. Most applications will just use GetInterface() instead.
+ // Caller does not take ownership.
+ virtual mojom::InterfaceProvider* GetRemoteInterfaces() = 0;
+
+ protected:
+ virtual InterfaceRegistry* GetLocalRegistry() = 0;
+
+ virtual base::WeakPtr<Connection> GetWeakPtr() = 0;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_CONNECTION_H_
diff --git a/chromium/services/shell/public/cpp/connector.h b/chromium/services/shell/public/cpp/connector.h
new file mode 100644
index 00000000000..6e40590b9a3
--- /dev/null
+++ b/chromium/services/shell/public/cpp/connector.h
@@ -0,0 +1,104 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_CONNECTOR_H_
+#define SERVICES_SHELL_PUBLIC_CPP_CONNECTOR_H_
+
+#include <memory>
+
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/shell.mojom.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace shell {
+
+// An interface that encapsulates the Mojo Shell's broker interface by which
+// connections between applications are established. Once Connect() is called,
+// this class is bound to the thread the call was made on and it cannot be
+// passed to another thread without calling Clone().
+// An instance of this class is created internally by ShellConnection for use
+// on the thread ShellConnection is instantiated on, and this interface is
+// wrapped by the Shell interface.
+// To use this interface on other threads, call Shell::CloneConnector() and
+// pass the result to another thread. To pass to subsequent threads, call
+// Clone() on instances of this object.
+// While instances of this object are owned by the caller, the underlying
+// connection with the shell is bound to the lifetime of the instance that
+// created it, i.e. when the application is terminated the Connector pipe is
+// closed.
+class Connector {
+ public:
+ virtual ~Connector() {}
+
+ class ConnectParams {
+ public:
+ explicit ConnectParams(const Identity& target);
+ explicit ConnectParams(const std::string& name);
+ ~ConnectParams();
+
+ const Identity& target() { return target_; }
+ void set_target(const Identity& target) { target_ = target; }
+ void set_client_process_connection(
+ mojom::ShellClientPtr shell_client,
+ mojom::PIDReceiverRequest pid_receiver_request) {
+ shell_client_ = std::move(shell_client);
+ pid_receiver_request_ = std::move(pid_receiver_request);
+ }
+ void TakeClientProcessConnection(
+ mojom::ShellClientPtr* shell_client,
+ mojom::PIDReceiverRequest* pid_receiver_request) {
+ *shell_client = std::move(shell_client_);
+ *pid_receiver_request = std::move(pid_receiver_request_);
+ }
+
+ private:
+ Identity target_;
+ mojom::ShellClientPtr shell_client_;
+ mojom::PIDReceiverRequest pid_receiver_request_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectParams);
+ };
+
+ // Requests a new connection to an application. Returns a pointer to the
+ // connection if the connection is permitted by this application's delegate,
+ // or nullptr otherwise. Caller takes ownership.
+ // Once this method is called, this object is bound to the thread on which the
+ // call took place. To pass to another thread, call Clone() and pass the
+ // result.
+ virtual std::unique_ptr<Connection> Connect(const std::string& name) = 0;
+ virtual std::unique_ptr<Connection> Connect(ConnectParams* params) = 0;
+
+ // Connect to application identified by |request->name| and connect to the
+ // service implementation of the interface identified by |Interface|.
+ template <typename Interface>
+ void ConnectToInterface(ConnectParams* params,
+ mojo::InterfacePtr<Interface>* ptr) {
+ std::unique_ptr<Connection> connection = Connect(params);
+ if (connection)
+ connection->GetInterface(ptr);
+ }
+ template <typename Interface>
+ void ConnectToInterface(const Identity& target,
+ mojo::InterfacePtr<Interface>* ptr) {
+ ConnectParams params(target);
+ return ConnectToInterface(&params, ptr);
+ }
+ template <typename Interface>
+ void ConnectToInterface(const std::string& name,
+ mojo::InterfacePtr<Interface>* ptr) {
+ ConnectParams params(name);
+ return ConnectToInterface(&params, ptr);
+ }
+
+ // Creates a new instance of this class which may be passed to another thread.
+ // The returned object may be passed multiple times until Connect() is called,
+ // at which point this method must be called again to pass again.
+ virtual std::unique_ptr<Connector> Clone() = 0;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_CONNECTOR_H_
diff --git a/chromium/services/shell/public/cpp/identity.h b/chromium/services/shell/public/cpp/identity.h
new file mode 100644
index 00000000000..3c2cb0b1cb5
--- /dev/null
+++ b/chromium/services/shell/public/cpp/identity.h
@@ -0,0 +1,60 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_IDENTITY_H_
+#define SERVICES_SHELL_PUBLIC_CPP_IDENTITY_H_
+
+#include <string>
+
+#include "services/shell/public/interfaces/connector.mojom.h"
+
+namespace shell {
+
+// Represents the identity of an application.
+// |name| is the structured name of the application.
+// |instance| is a string that allows to tie a specific instance to another. A
+// typical use case of instance is to control process grouping for a given name.
+class Identity {
+ public:
+ Identity();
+ Identity(const std::string& name,
+ const std::string& user_id);
+ Identity(const std::string& name,
+ const std::string& user_id,
+ const std::string& instance);
+ Identity(const Identity& other);
+ ~Identity();
+
+ bool operator<(const Identity& other) const;
+ bool is_null() const { return name_.empty(); }
+ bool operator==(const Identity& other) const;
+
+ const std::string& name() const { return name_; }
+ const std::string& user_id() const { return user_id_; }
+ void set_user_id(const std::string& user_id) { user_id_ = user_id; }
+ const std::string& instance() const { return instance_; }
+
+ private:
+ std::string name_;
+ std::string user_id_;
+ std::string instance_;
+};
+
+} // namespace shell
+
+namespace mojo {
+
+template <>
+struct TypeConverter<shell::mojom::IdentityPtr, shell::Identity> {
+ static shell::mojom::IdentityPtr Convert(const shell::Identity& input);
+};
+
+template <>
+struct TypeConverter<shell::Identity, shell::mojom::IdentityPtr> {
+ static shell::Identity Convert(const shell::mojom::IdentityPtr& input);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_IDENTITY_H_
diff --git a/chromium/services/shell/public/cpp/interface_binder.h b/chromium/services/shell/public/cpp/interface_binder.h
new file mode 100644
index 00000000000..9dec4addde6
--- /dev/null
+++ b/chromium/services/shell/public/cpp/interface_binder.h
@@ -0,0 +1,30 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_INTERFACE_BINDER_H_
+#define SERVICES_SHELL_PUBLIC_CPP_INTERFACE_BINDER_H_
+
+#include <string>
+
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace shell {
+
+class Connection;
+
+class InterfaceBinder {
+ public:
+ virtual ~InterfaceBinder() {}
+
+ // Asks the InterfaceBinder to bind an implementation of the specified
+ // interface to the request passed via |handle|. If the InterfaceBinder binds
+ // an implementation it must take ownership of the request handle.
+ virtual void BindInterface(Connection* connection,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle) = 0;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_INTERFACE_BINDER_H_
diff --git a/chromium/services/shell/public/cpp/interface_factory.h b/chromium/services/shell/public/cpp/interface_factory.h
new file mode 100644
index 00000000000..165645d61b6
--- /dev/null
+++ b/chromium/services/shell/public/cpp/interface_factory.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
+#define SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace shell {
+
+class Connection;
+
+// Implement this class to provide implementations of a given interface and
+// bind them to incoming requests. The implementation of this class is
+// responsible for managing the lifetime of the implementations of the
+// interface.
+template <typename Interface>
+class InterfaceFactory {
+ public:
+ virtual ~InterfaceFactory() {}
+ virtual void Create(Connection* connection,
+ mojo::InterfaceRequest<Interface> request) = 0;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_H_
diff --git a/chromium/services/shell/public/cpp/interface_factory_impl.h b/chromium/services/shell/public/cpp/interface_factory_impl.h
new file mode 100644
index 00000000000..7510a0843b9
--- /dev/null
+++ b/chromium/services/shell/public/cpp/interface_factory_impl.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
+#define SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
+
+#include "services/shell/public/cpp/interface_factory.h"
+
+namespace shell {
+
+// Use this class to allocate and bind instances of Impl to interface requests.
+// The lifetime of the constructed Impl is bound to the pipe.
+template <typename Impl,
+ typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImpl : public InterfaceFactory<Interface> {
+ public:
+ virtual ~InterfaceFactoryImpl() {}
+
+ virtual void Create(Connection* connection,
+ mojo::InterfaceRequest<Interface> request) override {
+ BindToRequest(new Impl(), &request);
+ }
+};
+
+// Use this class to allocate and bind instances of Impl constructed with a
+// context parameter to interface requests. The lifetime of the constructed
+// Impl is bound to the pipe.
+template <typename Impl,
+ typename Context,
+ typename Interface = typename Impl::ImplementedInterface>
+class InterfaceFactoryImplWithContext : public InterfaceFactory<Interface> {
+ public:
+ explicit InterfaceFactoryImplWithContext(Context* context)
+ : context_(context) {}
+ virtual ~InterfaceFactoryImplWithContext() {}
+
+ virtual void Create(Connection* connection,
+ mojo::InterfaceRequest<Interface> request) override {
+ BindToRequest(new Impl(context_), &request);
+ }
+
+ private:
+ Context* context_;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_
diff --git a/chromium/services/shell/public/cpp/interface_registry.h b/chromium/services/shell/public/cpp/interface_registry.h
new file mode 100644
index 00000000000..89f8df76357
--- /dev/null
+++ b/chromium/services/shell/public/cpp/interface_registry.h
@@ -0,0 +1,112 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_INTERFACE_REGISTRY_H_
+#define SERVICES_SHELL_PUBLIC_CPP_INTERFACE_REGISTRY_H_
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/shell/public/cpp/lib/interface_factory_binder.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+class InterfaceBinder;
+
+// An implementation of mojom::InterfaceProvider that allows the user to
+// register services to be exposed to another application.
+//
+// To use, define a class that implements your specific interface. Then
+// implement an InterfaceFactory<Foo> that binds instances of FooImpl to
+// InterfaceRequest<Foo>s and register that on the registry like this:
+//
+// registry.AddInterface(&factory);
+//
+// Or, if you have multiple factories implemented by the same type, explicitly
+// specify the interface to register the factory for:
+//
+// registry.AddInterface<Foo>(&my_foo_and_bar_factory_);
+// registry.AddInterface<Bar>(&my_foo_and_bar_factory_);
+//
+// The InterfaceFactory must outlive the InterfaceRegistry.
+//
+// Additionally you may specify a default InterfaceBinder to handle requests for
+// interfaces unhandled by any registered InterfaceFactory. Just as with
+// InterfaceFactory, the default InterfaceBinder supplied must outlive
+// InterfaceRegistry.
+//
+class InterfaceRegistry : public mojom::InterfaceProvider {
+ public:
+ class TestApi {
+ public:
+ explicit TestApi(InterfaceRegistry* registry) : registry_(registry) {}
+ ~TestApi() {}
+
+ void SetInterfaceBinderForName(InterfaceBinder* binder,
+ const std::string& interface_name) {
+ registry_->SetInterfaceBinderForName(
+ base::WrapUnique(binder), interface_name);
+ }
+
+ void RemoveInterfaceBinderForName(const std::string& interface_name) {
+ registry_->RemoveInterfaceBinderForName(interface_name);
+ }
+
+ private:
+ InterfaceRegistry* registry_;
+ DISALLOW_COPY_AND_ASSIGN(TestApi);
+ };
+
+ // Construct with a Connection (which may be null), and create an
+ // InterfaceProvider pipe, the client end of which may be obtained by calling
+ // TakeClientHandle(). If |connection| is non-null, the Mojo Shell's
+ // rules filtering which interfaces are allowed to be exposed to clients are
+ // imposed on this registry. If null, they are not.
+ explicit InterfaceRegistry(Connection* connection);
+ // Construct with an InterfaceProviderRequest and a Connection (which may be
+ // null, see note above about filtering).
+ InterfaceRegistry(mojom::InterfaceProviderRequest request,
+ Connection* connection);
+ ~InterfaceRegistry() override;
+
+ // Takes the client end of the InterfaceProvider pipe created in the
+ // constructor.
+ mojom::InterfaceProviderPtr TakeClientHandle();
+
+ template <typename Interface>
+ bool AddInterface(InterfaceFactory<Interface>* factory) {
+ return SetInterfaceBinderForName(
+ base::WrapUnique(
+ new internal::InterfaceFactoryBinder<Interface>(factory)),
+ Interface::Name_);
+ }
+
+ private:
+ using NameToInterfaceBinderMap =
+ std::map<std::string, std::unique_ptr<InterfaceBinder>>;
+
+ // mojom::InterfaceProvider:
+ void GetInterface(const mojo::String& interface_name,
+ mojo::ScopedMessagePipeHandle handle) override;
+
+ // Returns true if the binder was set, false if it was not set (e.g. by
+ // some filtering policy preventing this interface from being exposed).
+ bool SetInterfaceBinderForName(std::unique_ptr<InterfaceBinder> binder,
+ const std::string& name);
+
+ void RemoveInterfaceBinderForName(const std::string& interface_name);
+
+ mojom::InterfaceProviderPtr client_handle_;
+ mojo::Binding<mojom::InterfaceProvider> binding_;
+ Connection* connection_;
+
+ NameToInterfaceBinderMap name_to_binder_;
+
+ DISALLOW_COPY_AND_ASSIGN(InterfaceRegistry);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_INTERFACE_REGISTRY_H_
diff --git a/chromium/services/shell/public/cpp/lib/application_runner.cc b/chromium/services/shell/public/cpp/lib/application_runner.cc
new file mode 100644
index 00000000000..2b5a0f2e627
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/application_runner.cc
@@ -0,0 +1,91 @@
+// 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 "services/shell/public/cpp/application_runner.h"
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/launch.h"
+#include "base/run_loop.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection.h"
+
+namespace shell {
+
+int g_application_runner_argc;
+const char* const* g_application_runner_argv;
+
+ApplicationRunner::ApplicationRunner(ShellClient* client)
+ : client_(std::unique_ptr<ShellClient>(client)),
+ message_loop_type_(base::MessageLoop::TYPE_DEFAULT),
+ has_run_(false) {}
+
+ApplicationRunner::~ApplicationRunner() {}
+
+void ApplicationRunner::InitBaseCommandLine() {
+ base::CommandLine::Init(g_application_runner_argc, g_application_runner_argv);
+}
+
+void ApplicationRunner::set_message_loop_type(base::MessageLoop::Type type) {
+ DCHECK_NE(base::MessageLoop::TYPE_CUSTOM, type);
+ DCHECK(!has_run_);
+
+ message_loop_type_ = type;
+}
+
+MojoResult ApplicationRunner::Run(MojoHandle shell_client_request_handle,
+ bool init_base) {
+ DCHECK(!has_run_);
+ has_run_ = true;
+
+ std::unique_ptr<base::AtExitManager> at_exit;
+ if (init_base) {
+ InitBaseCommandLine();
+ at_exit.reset(new base::AtExitManager);
+ }
+
+ {
+ std::unique_ptr<base::MessageLoop> loop;
+ loop.reset(new base::MessageLoop(message_loop_type_));
+
+ connection_.reset(new ShellConnection(
+ client_.get(),
+ mojo::MakeRequest<mojom::ShellClient>(mojo::MakeScopedHandle(
+ mojo::MessagePipeHandle(shell_client_request_handle)))));
+ base::RunLoop run_loop;
+ connection_->SetConnectionLostClosure(run_loop.QuitClosure());
+ run_loop.Run();
+ // It's very common for the client to cache the app and terminate on errors.
+ // If we don't delete the client before the app we run the risk of the
+ // client having a stale reference to the app and trying to use it.
+ // Note that we destruct the message loop first because that might trigger
+ // connection error handlers and they might access objects created by the
+ // client.
+ loop.reset();
+ client_.reset();
+ connection_.reset();
+ }
+ return MOJO_RESULT_OK;
+}
+
+MojoResult ApplicationRunner::Run(MojoHandle shell_client_request_handle) {
+ bool init_base = true;
+ if (base::CommandLine::InitializedForCurrentProcess()) {
+ init_base =
+ !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process");
+ }
+ return Run(shell_client_request_handle, init_base);
+}
+
+void ApplicationRunner::DestroyShellConnection() {
+ connection_.reset();
+}
+
+void ApplicationRunner::Quit() {
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/capabilities.cc b/chromium/services/shell/public/cpp/lib/capabilities.cc
new file mode 100644
index 00000000000..51dcd0dbfee
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/capabilities.cc
@@ -0,0 +1,85 @@
+// 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 "services/shell/public/cpp/capabilities.h"
+
+namespace shell {
+
+CapabilityRequest::CapabilityRequest() {}
+CapabilityRequest::CapabilityRequest(const CapabilityRequest& other) = default;
+CapabilityRequest::~CapabilityRequest() {}
+
+bool CapabilityRequest::operator==(const CapabilityRequest& other) const {
+ return other.classes == classes && other.interfaces == interfaces;
+}
+
+bool CapabilityRequest::operator<(const CapabilityRequest& other) const {
+ return std::tie(classes, interfaces) <
+ std::tie(other.classes, other.interfaces);
+}
+
+CapabilitySpec::CapabilitySpec() {}
+CapabilitySpec::CapabilitySpec(const CapabilitySpec& other) = default;
+CapabilitySpec::~CapabilitySpec() {}
+
+bool CapabilitySpec::operator==(const CapabilitySpec& other) const {
+ return other.provided == provided && other.required == required;
+}
+
+bool CapabilitySpec::operator<(const CapabilitySpec& other) const {
+ return std::tie(provided, required) <
+ std::tie(other.provided, other.required);
+}
+
+} // namespace shell
+
+namespace mojo {
+
+// static
+shell::mojom::CapabilitySpecPtr
+TypeConverter<shell::mojom::CapabilitySpecPtr, shell::CapabilitySpec>::Convert(
+ const shell::CapabilitySpec& input) {
+ shell::mojom::CapabilitySpecPtr spec(shell::mojom::CapabilitySpec::New());
+ spec->provided =
+ mojo::Map<mojo::String, mojo::Array<mojo::String>>::From(input.provided);
+ spec->required =
+ mojo::Map<mojo::String, shell::mojom::CapabilityRequestPtr>::From(
+ input.required);
+ return spec;
+}
+
+// static
+shell::CapabilitySpec
+TypeConverter<shell::CapabilitySpec, shell::mojom::CapabilitySpecPtr>::Convert(
+ const shell::mojom::CapabilitySpecPtr& input) {
+ shell::CapabilitySpec spec;
+ spec.provided =
+ input->provided.To<std::map<shell::Class, shell::Interfaces>>();
+ spec.required =
+ input->required.To<std::map<shell::Name, shell::CapabilityRequest>>();
+ return spec;
+}
+
+// static
+shell::mojom::CapabilityRequestPtr TypeConverter<
+ shell::mojom::CapabilityRequestPtr,
+ shell::CapabilityRequest>::Convert(const shell::CapabilityRequest& input) {
+ shell::mojom::CapabilityRequestPtr request(
+ shell::mojom::CapabilityRequest::New());
+ request->classes = mojo::Array<mojo::String>::From(input.classes);
+ request->interfaces = mojo::Array<mojo::String>::From(input.interfaces);
+ return request;
+}
+
+// static
+shell::CapabilityRequest
+TypeConverter<shell::CapabilityRequest, shell::mojom::CapabilityRequestPtr>::
+ Convert(const shell::mojom::CapabilityRequestPtr& input) {
+ shell::CapabilityRequest request;
+ request.classes = input->classes.To<std::set<std::string>>();
+ request.interfaces = input->interfaces.To<std::set<std::string>>();
+ return request;
+}
+
+} // namespace mojo
diff --git a/chromium/services/shell/public/cpp/lib/connection_impl.cc b/chromium/services/shell/public/cpp/lib/connection_impl.cc
new file mode 100644
index 00000000000..60fd9888f47
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/connection_impl.cc
@@ -0,0 +1,129 @@
+// 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 "services/shell/public/cpp/lib/connection_impl.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/interface_binder.h"
+
+namespace shell {
+namespace internal {
+
+////////////////////////////////////////////////////////////////////////////////
+// ConnectionImpl, public:
+
+ConnectionImpl::ConnectionImpl(
+ const std::string& connection_name,
+ const Identity& remote,
+ uint32_t remote_id,
+ shell::mojom::InterfaceProviderPtr remote_interfaces,
+ shell::mojom::InterfaceProviderRequest local_interfaces,
+ const CapabilityRequest& capability_request,
+ State initial_state)
+ : connection_name_(connection_name),
+ remote_(remote),
+ remote_id_(remote_id),
+ state_(initial_state),
+ local_registry_(std::move(local_interfaces), this),
+ remote_interfaces_(std::move(remote_interfaces)),
+ capability_request_(capability_request),
+ allow_all_interfaces_(capability_request.interfaces.size() == 1 &&
+ capability_request.interfaces.count("*") == 1),
+ weak_factory_(this) {}
+
+ConnectionImpl::ConnectionImpl()
+ : local_registry_(shell::mojom::InterfaceProviderRequest(), this),
+ allow_all_interfaces_(true),
+ weak_factory_(this) {}
+
+ConnectionImpl::~ConnectionImpl() {}
+
+shell::mojom::Connector::ConnectCallback ConnectionImpl::GetConnectCallback() {
+ return base::Bind(&ConnectionImpl::OnConnectionCompleted,
+ weak_factory_.GetWeakPtr());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConnectionImpl, Connection implementation:
+
+bool ConnectionImpl::HasCapabilityClass(const std::string& class_name) const {
+ return capability_request_.classes.count(class_name) > 0;
+}
+
+const std::string& ConnectionImpl::GetConnectionName() {
+ return connection_name_;
+}
+
+const Identity& ConnectionImpl::GetRemoteIdentity() const {
+ return remote_;
+}
+
+void ConnectionImpl::SetConnectionLostClosure(const mojo::Closure& handler) {
+ remote_interfaces_.set_connection_error_handler(handler);
+}
+
+shell::mojom::ConnectResult ConnectionImpl::GetResult() const {
+ return result_;
+}
+
+bool ConnectionImpl::IsPending() const {
+ return state_ == State::PENDING;
+}
+
+uint32_t ConnectionImpl::GetRemoteInstanceID() const {
+ return remote_id_;
+}
+
+void ConnectionImpl::AddConnectionCompletedClosure(
+ const mojo::Closure& callback) {
+ if (IsPending())
+ connection_completed_callbacks_.push_back(callback);
+ else
+ callback.Run();
+}
+
+bool ConnectionImpl::AllowsInterface(const std::string& interface_name) const {
+ return allow_all_interfaces_ ||
+ capability_request_.interfaces.count(interface_name);
+}
+
+shell::mojom::InterfaceProvider* ConnectionImpl::GetRemoteInterfaces() {
+ return remote_interfaces_.get();
+}
+
+InterfaceRegistry* ConnectionImpl::GetLocalRegistry() {
+ return &local_registry_;
+}
+
+base::WeakPtr<Connection> ConnectionImpl::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ConnectionImpl, private:
+
+void ConnectionImpl::OnConnectionCompleted(shell::mojom::ConnectResult result,
+ const std::string& target_user_id,
+ uint32_t target_application_id) {
+ DCHECK(State::PENDING == state_);
+
+ result_ = result;
+ state_ = result_ == shell::mojom::ConnectResult::SUCCEEDED ?
+ State::CONNECTED : State::DISCONNECTED;
+ remote_id_ = target_application_id;
+ remote_.set_user_id(target_user_id);
+ std::vector<mojo::Closure> callbacks;
+ callbacks.swap(connection_completed_callbacks_);
+ for (auto callback : callbacks)
+ callback.Run();
+}
+
+} // namespace internal
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/connection_impl.h b/chromium/services/shell/public/cpp/lib/connection_impl.h
new file mode 100644
index 00000000000..246cdb2aba1
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/connection_impl.h
@@ -0,0 +1,84 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
+#define SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
+
+#include <stdint.h>
+
+#include <set>
+#include <string>
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/shell/public/cpp/capabilities.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+namespace internal {
+
+// A ConnectionImpl represents each half of a connection between two
+// applications, allowing customization of which interfaces are published to the
+// other.
+class ConnectionImpl : public Connection {
+ public:
+ ConnectionImpl();
+ // |allowed_interfaces| are the set of interfaces that the shell has allowed
+ // an application to expose to another application. If this set contains only
+ // the string value "*" all interfaces may be exposed.
+ ConnectionImpl(const std::string& connection_name,
+ const Identity& remote,
+ uint32_t remote_id,
+ shell::mojom::InterfaceProviderPtr remote_interfaces,
+ shell::mojom::InterfaceProviderRequest local_interfaces,
+ const CapabilityRequest& capability_request,
+ State initial_state);
+ ~ConnectionImpl() override;
+
+ shell::mojom::Connector::ConnectCallback GetConnectCallback();
+
+ private:
+ // Connection:
+ bool HasCapabilityClass(const std::string& class_name) const override;
+ const std::string& GetConnectionName() override;
+ const Identity& GetRemoteIdentity() const override;
+ void SetConnectionLostClosure(const mojo::Closure& handler) override;
+ shell::mojom::ConnectResult GetResult() const override;
+ bool IsPending() const override;
+ uint32_t GetRemoteInstanceID() const override;
+ void AddConnectionCompletedClosure(const mojo::Closure& callback) override;
+ bool AllowsInterface(const std::string& interface_name) const override;
+ shell::mojom::InterfaceProvider* GetRemoteInterfaces() override;
+ InterfaceRegistry* GetLocalRegistry() override;
+ base::WeakPtr<Connection> GetWeakPtr() override;
+
+ void OnConnectionCompleted(shell::mojom::ConnectResult result,
+ const std::string& target_user_id,
+ uint32_t target_application_id);
+
+ const std::string connection_name_;
+ Identity remote_;
+ uint32_t remote_id_ = shell::mojom::kInvalidInstanceID;
+
+ State state_;
+ shell::mojom::ConnectResult result_ = shell::mojom::ConnectResult::SUCCEEDED;
+ std::vector<mojo::Closure> connection_completed_callbacks_;
+
+ InterfaceRegistry local_registry_;
+ shell::mojom::InterfaceProviderPtr remote_interfaces_;
+
+ const CapabilityRequest capability_request_;
+ const bool allow_all_interfaces_;
+
+ base::WeakPtrFactory<ConnectionImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionImpl);
+};
+
+} // namespace internal
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
diff --git a/chromium/services/shell/public/cpp/lib/connector_impl.cc b/chromium/services/shell/public/cpp/lib/connector_impl.cc
new file mode 100644
index 00000000000..1bd9e68924c
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/connector_impl.cc
@@ -0,0 +1,94 @@
+// 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 "services/shell/public/cpp/lib/connector_impl.h"
+
+#include "base/memory/ptr_util.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/cpp/lib/connection_impl.h"
+
+namespace shell {
+
+Connector::ConnectParams::ConnectParams(const Identity& target)
+ : target_(target) {}
+
+Connector::ConnectParams::ConnectParams(const std::string& name)
+ : target_(name, mojom::kInheritUserID) {}
+
+Connector::ConnectParams::~ConnectParams() {}
+
+ConnectorImpl::ConnectorImpl(mojom::ConnectorPtrInfo unbound_state)
+ : unbound_state_(std::move(unbound_state)) {}
+
+ConnectorImpl::ConnectorImpl(mojom::ConnectorPtr connector)
+ : connector_(std::move(connector)) {
+ thread_checker_.reset(new base::ThreadChecker);
+}
+
+ConnectorImpl::~ConnectorImpl() {}
+
+std::unique_ptr<Connection> ConnectorImpl::Connect(const std::string& name) {
+ ConnectParams params(name);
+ return Connect(&params);
+}
+
+std::unique_ptr<Connection> ConnectorImpl::Connect(ConnectParams* params) {
+ // Bind this object to the current thread the first time it is used to
+ // connect.
+ if (!connector_.is_bound()) {
+ if (!unbound_state_.is_valid()) {
+ // It's possible to get here when the link to the shell has been severed
+ // (and so the connector pipe has been closed) but the app has chosen not
+ // to quit.
+ return nullptr;
+ }
+ connector_.Bind(std::move(unbound_state_));
+ thread_checker_.reset(new base::ThreadChecker);
+ }
+ DCHECK(thread_checker_->CalledOnValidThread());
+
+ DCHECK(params);
+ // We allow all interfaces on outgoing connections since we are presumably in
+ // a position to know who we're talking to.
+ CapabilityRequest request;
+ request.interfaces.insert("*");
+ mojom::InterfaceProviderPtr local_interfaces;
+ mojom::InterfaceProviderRequest local_request = GetProxy(&local_interfaces);
+ mojom::InterfaceProviderPtr remote_interfaces;
+ mojom::InterfaceProviderRequest remote_request = GetProxy(&remote_interfaces);
+ std::unique_ptr<internal::ConnectionImpl> registry(
+ new internal::ConnectionImpl(
+ params->target().name(), params->target(), mojom::kInvalidInstanceID,
+ std::move(remote_interfaces), std::move(local_request), request,
+ Connection::State::PENDING));
+
+ mojom::ShellClientPtr shell_client;
+ mojom::PIDReceiverRequest pid_receiver_request;
+ params->TakeClientProcessConnection(&shell_client, &pid_receiver_request);
+ mojom::ClientProcessConnectionPtr client_process_connection;
+ if (shell_client.is_bound() && pid_receiver_request.is_pending()) {
+ client_process_connection = mojom::ClientProcessConnection::New();
+ client_process_connection->shell_client =
+ shell_client.PassInterface().PassHandle();
+ client_process_connection->pid_receiver_request =
+ pid_receiver_request.PassMessagePipe();
+ } else if (shell_client.is_bound() || pid_receiver_request.is_pending()) {
+ NOTREACHED() << "If one of shell_client or pid_receiver_request is valid, "
+ << "both must be valid.";
+ return std::move(registry);
+ }
+ connector_->Connect(mojom::Identity::From(params->target()),
+ std::move(remote_request), std::move(local_interfaces),
+ std::move(client_process_connection),
+ registry->GetConnectCallback());
+ return std::move(registry);
+}
+
+std::unique_ptr<Connector> ConnectorImpl::Clone() {
+ mojom::ConnectorPtr connector;
+ connector_->Clone(GetProxy(&connector));
+ return base::WrapUnique(new ConnectorImpl(connector.PassInterface()));
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/connector_impl.h b/chromium/services/shell/public/cpp/lib/connector_impl.h
new file mode 100644
index 00000000000..128469a7a0f
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/connector_impl.h
@@ -0,0 +1,39 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
+#define SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/threading/thread_checker.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+
+namespace shell {
+
+class ConnectorImpl : public Connector {
+ public:
+ explicit ConnectorImpl(mojom::ConnectorPtrInfo unbound_state);
+ explicit ConnectorImpl(mojom::ConnectorPtr connector);
+ ~ConnectorImpl() override;
+
+ private:
+ // Connector:
+ std::unique_ptr<Connection> Connect(const std::string& name) override;
+ std::unique_ptr<Connection> Connect(ConnectParams* params) override;
+ std::unique_ptr<Connector> Clone() override;
+
+ mojom::ConnectorPtrInfo unbound_state_;
+ mojom::ConnectorPtr connector_;
+
+ std::unique_ptr<base::ThreadChecker> thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectorImpl);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
diff --git a/chromium/services/shell/public/cpp/lib/identity.cc b/chromium/services/shell/public/cpp/lib/identity.cc
new file mode 100644
index 00000000000..dc49424fbf0
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/identity.cc
@@ -0,0 +1,65 @@
+// 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 "services/shell/public/cpp/identity.h"
+
+#include "base/guid.h"
+#include "services/shell/public/cpp/names.h"
+
+namespace shell {
+
+Identity::Identity() {}
+
+Identity::Identity(const std::string& name, const std::string& user_id)
+ : Identity(name, user_id, "") {}
+
+Identity::Identity(const std::string& name, const std::string& user_id,
+ const std::string& instance)
+ : name_(name),
+ user_id_(user_id),
+ instance_(instance.empty() ? GetNamePath(name_) : instance) {
+ CHECK(!user_id.empty());
+ CHECK(base::IsValidGUID(user_id));
+}
+
+Identity::Identity(const Identity& other) = default;
+
+Identity::~Identity() {}
+
+bool Identity::operator<(const Identity& other) const {
+ if (name_ != other.name_)
+ return name_ < other.name_;
+ if (instance_ != other.instance_)
+ return instance_ < other.instance_;
+ return user_id_ < other.user_id_;
+}
+
+bool Identity::operator==(const Identity& other) const {
+ return other.name_ == name_ && other.instance_ == instance_ &&
+ other.user_id_ == user_id_;
+}
+
+} // namespace shell
+
+namespace mojo {
+
+// static
+shell::mojom::IdentityPtr
+TypeConverter<shell::mojom::IdentityPtr, shell::Identity>::Convert(
+ const shell::Identity& input) {
+ shell::mojom::IdentityPtr identity(shell::mojom::Identity::New());
+ identity->name = input.name();
+ identity->user_id = input.user_id();
+ identity->instance = input.instance();
+ return identity;
+}
+
+// static
+shell::Identity
+TypeConverter<shell::Identity, shell::mojom::IdentityPtr>::Convert(
+ const shell::mojom::IdentityPtr& input) {
+ return shell::Identity(input->name, input->user_id, input->instance);
+}
+
+} // namespace mojo
diff --git a/chromium/services/shell/public/cpp/lib/init_commandline.cc b/chromium/services/shell/public/cpp/lib/init_commandline.cc
new file mode 100644
index 00000000000..73c201116f0
--- /dev/null
+++ b/chromium/services/shell/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 shell {
+
+extern int g_application_runner_argc;
+extern const char* const* g_application_runner_argv;
+
+} // namespace shell
+
+#if !defined(OS_WIN)
+extern "C" {
+__attribute__((visibility("default"))) void InitCommandLineArgs(
+ int argc, const char* const* argv) {
+ shell::g_application_runner_argc = argc;
+ shell::g_application_runner_argv = argv;
+}
+}
+#endif
diff --git a/chromium/services/shell/public/cpp/lib/initialize_base_and_icu.cc b/chromium/services/shell/public/cpp/lib/initialize_base_and_icu.cc
new file mode 100644
index 00000000000..b910f0feea0
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/initialize_base_and_icu.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.
+
+// This file declares a raw symbol and should be included only once in a
+// certain binary target. This needs to be run before we raise the sandbox,
+// which means that it can't use mojo. Our runners will dig around in the
+// symbol table and run this before the mojo system is initialized.
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/i18n/icu_util.h"
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "mojo/public/c/system/types.h"
+
+#if !defined(OS_ANDROID)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
+
+extern "C" {
+#if defined(WIN32)
+__declspec(dllexport) void __cdecl
+#else
+void __attribute__((visibility("default")))
+#endif
+InitializeBase(const uint8_t* icu_data) {
+ base::RandUint64();
+ base::SysInfo::AmountOfPhysicalMemory();
+ base::SysInfo::NumberOfProcessors();
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ base::SysInfo::MaxSharedMemorySize();
+#endif
+
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+ // Initialize core ICU. We must perform the full initialization before we
+ // initialize icu::TimeZone subsystem because otherwise ICU gets in a state
+ // where the timezone data is disconnected from the locale data which can
+ // cause crashes.
+ CHECK(base::i18n::InitializeICUFromRawMemory(icu_data));
+#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+
+#if !defined(OS_ANDROID)
+ // ICU DateFormat class (used in base/time_format.cc) needs to get the
+ // Olson timezone ID by accessing the zoneinfo files on disk. After
+ // TimeZone::createDefault is called once here, the timezone ID is
+ // cached and there's no more need to access the file system.
+ std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+}
+}
diff --git a/chromium/services/shell/public/cpp/lib/interface_factory_binder.h b/chromium/services/shell/public/cpp/lib/interface_factory_binder.h
new file mode 100644
index 00000000000..bd97a762825
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/interface_factory_binder.h
@@ -0,0 +1,39 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_BINDER_H_
+#define SERVICES_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_BINDER_H_
+
+#include <utility>
+
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/cpp/interface_binder.h"
+#include "services/shell/public/cpp/interface_factory.h"
+
+namespace shell {
+namespace internal {
+
+template <typename Interface>
+class InterfaceFactoryBinder : public InterfaceBinder {
+ public:
+ explicit InterfaceFactoryBinder(InterfaceFactory<Interface>* factory)
+ : factory_(factory) {}
+ ~InterfaceFactoryBinder() override {}
+
+ void BindInterface(Connection* connection,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle client_handle) override {
+ factory_->Create(connection,
+ mojo::MakeRequest<Interface>(std::move(client_handle)));
+ }
+
+ private:
+ InterfaceFactory<Interface>* factory_;
+ DISALLOW_COPY_AND_ASSIGN(InterfaceFactoryBinder);
+};
+
+} // namespace internal
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_LIB_INTERFACE_FACTORY_BINDER_H_
diff --git a/chromium/services/shell/public/cpp/lib/interface_registry.cc b/chromium/services/shell/public/cpp/lib/interface_registry.cc
new file mode 100644
index 00000000000..fefe3e52e7e
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/interface_registry.cc
@@ -0,0 +1,62 @@
+// 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 "services/shell/public/cpp/interface_registry.h"
+
+#include "services/shell/public/cpp/connection.h"
+
+namespace shell {
+
+InterfaceRegistry::InterfaceRegistry(Connection* connection)
+ : InterfaceRegistry(nullptr, connection) {}
+
+InterfaceRegistry::InterfaceRegistry(mojom::InterfaceProviderRequest request,
+ Connection* connection)
+ : binding_(this), connection_(connection) {
+ if (!request.is_pending())
+ request = GetProxy(&client_handle_);
+ binding_.Bind(std::move(request));
+}
+
+InterfaceRegistry::~InterfaceRegistry() {}
+
+mojom::InterfaceProviderPtr InterfaceRegistry::TakeClientHandle() {
+ return std::move(client_handle_);
+}
+
+// mojom::InterfaceProvider:
+void InterfaceRegistry::GetInterface(const mojo::String& interface_name,
+ mojo::ScopedMessagePipeHandle handle) {
+ auto iter = name_to_binder_.find(interface_name);
+ if (iter != name_to_binder_.end()) {
+ iter->second->BindInterface(connection_, interface_name, std::move(handle));
+ } else if (connection_ && connection_->AllowsInterface(interface_name)) {
+ LOG(ERROR) << "Connection CapabilityFilter prevented binding to "
+ << "interface: " << interface_name << " connection_name:"
+ << connection_->GetConnectionName() << " remote_name:"
+ << connection_->GetRemoteIdentity().name();
+ }
+}
+
+bool InterfaceRegistry::SetInterfaceBinderForName(
+ std::unique_ptr<InterfaceBinder> binder,
+ const std::string& interface_name) {
+ if (!connection_ ||
+ (connection_ && connection_->AllowsInterface(interface_name))) {
+ RemoveInterfaceBinderForName(interface_name);
+ name_to_binder_[interface_name] = std::move(binder);
+ return true;
+ }
+ return false;
+}
+
+void InterfaceRegistry::RemoveInterfaceBinderForName(
+ const std::string& interface_name) {
+ NameToInterfaceBinderMap::iterator it = name_to_binder_.find(interface_name);
+ if (it == name_to_binder_.end())
+ return;
+ name_to_binder_.erase(it);
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/names.cc b/chromium/services/shell/public/cpp/lib/names.cc
new file mode 100644
index 00000000000..49122223e82
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/names.cc
@@ -0,0 +1,46 @@
+// 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 "services/shell/public/cpp/names.h"
+
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace shell {
+
+const char kNameType_Mojo[] = "mojo";
+const char kNameType_Exe[] = "exe";
+
+bool IsValidName(const std::string& name) {
+ std::vector<std::string> parts =
+ base::SplitString(name, ":", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+ if (parts.size() != 2)
+ return false;
+
+ if (parts.front().empty())
+ return false;
+
+ const std::string& path = parts.back();
+ return !path.empty() &&
+ !base::StartsWith(path, "//", base::CompareCase::INSENSITIVE_ASCII);
+}
+
+std::string GetNameType(const std::string& name) {
+ std::vector<std::string> parts =
+ base::SplitString(name, ":", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+ DCHECK(2 == parts.size());
+ return parts.front();
+}
+
+std::string GetNamePath(const std::string& name) {
+ std::vector<std::string> parts =
+ base::SplitString(name, ":", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+ DCHECK(2 == parts.size());
+ return parts.back();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/shell_client.cc b/chromium/services/shell/public/cpp/lib/shell_client.cc
new file mode 100644
index 00000000000..562d6ee46c4
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/shell_client.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 "services/shell/public/cpp/shell_client.h"
+
+namespace shell {
+
+ShellClient::ShellClient() {}
+ShellClient::~ShellClient() {}
+
+void ShellClient::Initialize(Connector* connector, const Identity& identity,
+ uint32_t id) {
+}
+
+bool ShellClient::AcceptConnection(Connection* connection) {
+ return false;
+}
+
+bool ShellClient::ShellConnectionLost() { return true; }
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/shell_connection.cc b/chromium/services/shell/public/cpp/lib/shell_connection.cc
new file mode 100644
index 00000000000..8b1ad3fbb6d
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/shell_connection.cc
@@ -0,0 +1,105 @@
+// 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 "services/shell/public/cpp/shell_connection.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/cpp/capabilities.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/cpp/lib/connection_impl.h"
+#include "services/shell/public/cpp/lib/connector_impl.h"
+#include "services/shell/public/cpp/shell_client.h"
+
+namespace shell {
+
+////////////////////////////////////////////////////////////////////////////////
+// ShellConnection, public:
+
+ShellConnection::ShellConnection(shell::ShellClient* client,
+ mojom::ShellClientRequest request)
+ : client_(client), binding_(this) {
+ mojom::ConnectorPtr connector;
+ pending_connector_request_ = GetProxy(&connector);
+ connector_.reset(new ConnectorImpl(std::move(connector)));
+
+ DCHECK(request.is_pending());
+ binding_.Bind(std::move(request));
+}
+
+ShellConnection::~ShellConnection() {}
+
+void ShellConnection::set_initialize_handler(const base::Closure& callback) {
+ initialize_handler_ = callback;
+}
+
+void ShellConnection::SetAppTestConnectorForTesting(
+ mojom::ConnectorPtr connector) {
+ pending_connector_request_ = nullptr;
+ connector_.reset(new ConnectorImpl(std::move(connector)));
+}
+
+void ShellConnection::SetConnectionLostClosure(const base::Closure& closure) {
+ connection_lost_closure_ = closure;
+ if (should_run_connection_lost_closure_ &&
+ !connection_lost_closure_.is_null())
+ connection_lost_closure_.Run();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShellConnection, mojom::ShellClient implementation:
+
+void ShellConnection::Initialize(mojom::IdentityPtr identity,
+ uint32_t id,
+ const InitializeCallback& callback) {
+ identity_ = identity.To<Identity>();
+ if (!initialize_handler_.is_null())
+ initialize_handler_.Run();
+
+ callback.Run(std::move(pending_connector_request_));
+
+ DCHECK(binding_.is_bound());
+ binding_.set_connection_error_handler([this] { OnConnectionError(); });
+
+ client_->Initialize(connector_.get(), identity_, id);
+}
+
+void ShellConnection::AcceptConnection(
+ mojom::IdentityPtr source,
+ uint32_t source_id,
+ mojom::InterfaceProviderRequest local_interfaces,
+ mojom::InterfaceProviderPtr remote_interfaces,
+ mojom::CapabilityRequestPtr allowed_capabilities,
+ const mojo::String& name) {
+ std::unique_ptr<Connection> registry(new internal::ConnectionImpl(
+ name, source.To<Identity>(), source_id, std::move(remote_interfaces),
+ std::move(local_interfaces), allowed_capabilities.To<CapabilityRequest>(),
+ Connection::State::CONNECTED));
+ if (!client_->AcceptConnection(registry.get()))
+ return;
+
+ // TODO(beng): it appears we never prune this list. We should, when the
+ // connection's remote service provider pipe breaks.
+ incoming_connections_.push_back(std::move(registry));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShellConnection, private:
+
+void ShellConnection::OnConnectionError() {
+ // Note that the ShellClient doesn't technically have to quit now, it may live
+ // on to service existing connections. All existing Connectors however are
+ // invalid.
+ should_run_connection_lost_closure_ = client_->ShellConnectionLost();
+ if (should_run_connection_lost_closure_ &&
+ !connection_lost_closure_.is_null())
+ connection_lost_closure_.Run();
+ // We don't reset the connector as clients may have taken a raw pointer to it.
+ // Connect() will return nullptr if they try to connect to anything.
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/shell_connection_ref.cc b/chromium/services/shell/public/cpp/lib/shell_connection_ref.cc
new file mode 100644
index 00000000000..8b06bb79a4e
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/shell_connection_ref.cc
@@ -0,0 +1,87 @@
+// 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 "services/shell/public/cpp/shell_connection_ref.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace shell {
+
+class ShellConnectionRefImpl : public ShellConnectionRef {
+ public:
+ ShellConnectionRefImpl(
+ base::WeakPtr<ShellConnectionRefFactory> factory,
+ scoped_refptr<base::SingleThreadTaskRunner> shell_client_task_runner)
+ : factory_(factory),
+ shell_client_task_runner_(shell_client_task_runner) {
+ // This object is not thread-safe but may be used exclusively on a different
+ // thread from the one which constructed it.
+ thread_checker_.DetachFromThread();
+ }
+
+ ~ShellConnectionRefImpl() override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (shell_client_task_runner_->BelongsToCurrentThread() && factory_) {
+ factory_->Release();
+ } else {
+ shell_client_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ShellConnectionRefFactory::Release, factory_));
+ }
+ }
+
+ private:
+ // ShellConnectionRef:
+ std::unique_ptr<ShellConnectionRef> Clone() override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (shell_client_task_runner_->BelongsToCurrentThread() && factory_) {
+ factory_->AddRef();
+ } else {
+ shell_client_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ShellConnectionRefFactory::AddRef, factory_));
+ }
+
+ return base::WrapUnique(
+ new ShellConnectionRefImpl(factory_, shell_client_task_runner_));
+ }
+
+ base::WeakPtr<ShellConnectionRefFactory> factory_;
+ scoped_refptr<base::SingleThreadTaskRunner> shell_client_task_runner_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellConnectionRefImpl);
+};
+
+ShellConnectionRefFactory::ShellConnectionRefFactory(
+ const base::Closure& quit_closure)
+ : quit_closure_(quit_closure), weak_factory_(this) {
+ DCHECK(!quit_closure_.is_null());
+}
+
+ShellConnectionRefFactory::~ShellConnectionRefFactory() {}
+
+std::unique_ptr<ShellConnectionRef> ShellConnectionRefFactory::CreateRef() {
+ AddRef();
+ return base::WrapUnique(
+ new ShellConnectionRefImpl(weak_factory_.GetWeakPtr(),
+ base::ThreadTaskRunnerHandle::Get()));
+}
+
+void ShellConnectionRefFactory::AddRef() {
+ ++ref_count_;
+}
+
+void ShellConnectionRefFactory::Release() {
+ if (!--ref_count_)
+ quit_closure_.Run();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/lib/shell_test.cc b/chromium/services/shell/public/cpp/lib/shell_test.cc
new file mode 100644
index 00000000000..31f290fb2da
--- /dev/null
+++ b/chromium/services/shell/public/cpp/lib/shell_test.cc
@@ -0,0 +1,81 @@
+// 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 "services/shell/public/cpp/shell_test.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "services/shell/background/background_shell.h"
+#include "services/shell/public/cpp/shell_client.h"
+
+namespace shell {
+namespace test {
+
+ShellTestClient::ShellTestClient(ShellTest* test) : test_(test) {}
+ShellTestClient::~ShellTestClient() {}
+
+void ShellTestClient::Initialize(Connector* connector, const Identity& identity,
+ uint32_t id) {
+ test_->InitializeCalled(connector, identity.name(), identity.user_id(), id);
+}
+
+ShellTest::ShellTest() {}
+ShellTest::ShellTest(const std::string& test_name) : test_name_(test_name) {}
+ShellTest::~ShellTest() {}
+
+void ShellTest::InitTestName(const std::string& test_name) {
+ DCHECK(test_name_.empty());
+ test_name_ = test_name;
+}
+
+std::unique_ptr<ShellClient> ShellTest::CreateShellClient() {
+ return base::WrapUnique(new ShellTestClient(this));
+}
+
+std::unique_ptr<base::MessageLoop> ShellTest::CreateMessageLoop() {
+ return base::WrapUnique(new base::MessageLoop);
+}
+
+void ShellTest::InitializeCalled(Connector* connector,
+ const std::string& name,
+ const std::string& user_id,
+ uint32_t id) {
+ DCHECK_EQ(connector_, connector);
+ initialize_name_ = name;
+ initialize_instance_id_ = id;
+ initialize_userid_ = user_id;
+ initialize_called_.Run();
+}
+
+void ShellTest::SetUp() {
+ shell_client_ = CreateShellClient();
+ message_loop_ = CreateMessageLoop();
+ background_shell_.reset(new shell::BackgroundShell);
+ background_shell_->Init(nullptr);
+
+ // Create the shell connection. We don't proceed until we get our
+ // ShellClient's Initialize() method is called.
+ base::RunLoop run_loop;
+ base::MessageLoop::ScopedNestableTaskAllower allow(
+ base::MessageLoop::current());
+ initialize_called_ = run_loop.QuitClosure();
+
+ shell_connection_.reset(new ShellConnection(
+ shell_client_.get(),
+ background_shell_->CreateShellClientRequest(test_name_)));
+ connector_ = shell_connection_->connector();
+
+ run_loop.Run();
+}
+
+void ShellTest::TearDown() {
+ shell_connection_.reset();
+ background_shell_.reset();
+ message_loop_.reset();
+ shell_client_.reset();
+}
+
+} // namespace test
+} // namespace shell
diff --git a/chromium/services/shell/public/cpp/names.h b/chromium/services/shell/public/cpp/names.h
new file mode 100644
index 00000000000..fe534e93eb9
--- /dev/null
+++ b/chromium/services/shell/public/cpp/names.h
@@ -0,0 +1,56 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_NAMES_H_
+#define SERVICES_SHELL_PUBLIC_CPP_NAMES_H_
+
+#include <string>
+
+namespace shell {
+
+extern const char kNameType_Mojo[];
+extern const char kNameType_Exe[];
+
+// Mojo services and applications are identified by structured "names", of the
+// form:
+//
+// type:path.
+//
+// The type field tells the shell how to load the application. Two types are
+// currently recognized:
+//
+// mojo
+// Represents an application packaged as a .mojo, launched from the
+// NativeRunner launch path. .mojo files are assumed to live alongside the
+// shell executable at a path matching <path>/<path>.mojo. .mojo applications
+// have a MojoMain() entrypoint that receives a handle to a ShellClientRequest
+// that must be bound to enable further communication with the shell.
+//
+// exe
+// Represents a native executable on the host platform, expected to live
+// alongside the shell executable. Executables launched via this mechanism are
+// passed a handle to the shell on the command line and are expected to bind
+// a ShellClientRequest enabling further communication with the shell. The
+// path component contains the executable name, minus any platform-specific
+// extension.
+//
+// Other types may be supplied but are not recognized by any of the
+// NativeRunners, and as such custom loaders must be specified for such names.
+//
+// Any name type may serve as an alias for any other name type. Aliasing is
+// resolved implicitly by the Shell.
+
+// Returns true if the name is a valid form, i.e. type:path. path cannot start
+// with a "//" sequence. These are _not_ urls.
+bool IsValidName(const std::string& name);
+
+// Get the type component of the specified name.
+std::string GetNameType(const std::string& name);
+
+// Get the path component of the specified name.
+std::string GetNamePath(const std::string& name);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_NAMES_H_
diff --git a/chromium/services/shell/public/cpp/shell_client.h b/chromium/services/shell/public/cpp/shell_client.h
new file mode 100644
index 00000000000..d9513b76e10
--- /dev/null
+++ b/chromium/services/shell/public/cpp/shell_client.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_SHELL_CLIENT_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SHELL_CLIENT_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/macros.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/identity.h"
+
+namespace shell {
+
+class Connector;
+
+// An interface representing an instance "known to the Mojo Shell". The
+// implementation receives lifecycle messages for the instance and gets the
+// opportunity to handle inbound connections brokered by the Shell. Every client
+// of ShellConnection must implement this interface, and instances of this
+// interface must outlive the ShellConnection.
+class ShellClient {
+ public:
+ ShellClient();
+ virtual ~ShellClient();
+
+ // Called once a bidirectional connection with the shell has been established.
+ // |identity| is the identity of the instance.
+ // |id| is a unique identifier the shell uses to identify this specific
+ // instance of the application.
+ // Called exactly once before any other method.
+ virtual void Initialize(Connector* connector,
+ const Identity& identity,
+ uint32_t id);
+
+ // Called when a connection to this client is brokered by the shell. Override
+ // to expose services to the remote application. Return true if the connection
+ // should succeed. Return false if the connection should be rejected and the
+ // underlying pipe closed. The default implementation returns false.
+ virtual bool AcceptConnection(Connection* connection);
+
+ // Called when ShellConnection's ShellClient binding (i.e. the pipe the
+ // Mojo Shell has to talk to us over) is closed. A shell client may use this
+ // as a signal to terminate. Return true from this method to tell the
+ // ShellConnection to run its connection lost closure if it has one, false to
+ // prevent it from being run. The default implementation returns true.
+ // When used in conjunction with ApplicationRunner, returning true here quits
+ // the message loop created by ApplicationRunner, which results in the app
+ // quitting.
+ virtual bool ShellConnectionLost();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShellClient);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_SHELL_CLIENT_H_
diff --git a/chromium/services/shell/public/cpp/shell_connection.h b/chromium/services/shell/public/cpp/shell_connection.h
new file mode 100644
index 00000000000..f2f0cfc5129
--- /dev/null
+++ b/chromium/services/shell/public/cpp/shell_connection.h
@@ -0,0 +1,107 @@
+// 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.
+
+#ifndef SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/callback.h"
+#include "mojo/public/cpp/system/core.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace shell {
+
+class Connector;
+
+// Encapsulates a connection to the Mojo Shell in two parts:
+// - a bound InterfacePtr to mojom::Shell, the primary mechanism
+// by which the instantiating application interacts with other services
+// brokered by the Mojo Shell.
+// - a bound InterfaceRequest of mojom::ShellClient, an interface
+// used by the Mojo Shell to inform this application of lifecycle events and
+// inbound connections brokered by it.
+//
+// This class should be used in two scenarios:
+// - During early startup to bind the mojom::ShellClientRequest obtained from
+// the Mojo Shell, typically in response to either MojoMain() or main().
+// - In an implementation of mojom::ShellClientFactory to bind the
+// mojom::ShellClientRequest passed via StartApplication. In this scenario
+// there can be many instances of this class per process.
+//
+// Instances of this class are constructed with an implementation of the Shell
+// Client Lib's ShellClient interface. See documentation in shell_client.h
+// for details.
+//
+class ShellConnection : public mojom::ShellClient {
+ public:
+ // Creates a new ShellConnection bound to |request|. This connection may be
+ // used immediately to make outgoing connections via connector(). Does not
+ // take ownership of |client|, which must remain valid for the lifetime of
+ // ShellConnection.
+ ShellConnection(shell::ShellClient* client,
+ mojom::ShellClientRequest request);
+
+ ~ShellConnection() override;
+
+ Connector* connector() { return connector_.get(); }
+ const Identity& identity() { return identity_; }
+
+ // TODO(rockot): Remove this. http://crbug.com/594852.
+ void set_initialize_handler(const base::Closure& callback);
+
+ // TODO(rockot): Remove this once we get rid of app tests.
+ void SetAppTestConnectorForTesting(mojom::ConnectorPtr connector);
+
+ // Specify a function to be called when the connection to the shell is lost.
+ // Note that if connection has already been lost, then |closure| is called
+ // immediately.
+ void SetConnectionLostClosure(const base::Closure& closure);
+
+ private:
+ // mojom::ShellClient:
+ void Initialize(mojom::IdentityPtr identity,
+ uint32_t id,
+ const InitializeCallback& callback) override;
+ void AcceptConnection(mojom::IdentityPtr source,
+ uint32_t source_id,
+ mojom::InterfaceProviderRequest remote_interfaces,
+ mojom::InterfaceProviderPtr local_interfaces,
+ mojom::CapabilityRequestPtr allowed_capabilities,
+ const mojo::String& name) override;
+
+ void OnConnectionError();
+
+ // A callback called when Initialize() is run.
+ base::Closure initialize_handler_;
+
+ // We track the lifetime of incoming connection registries as it more
+ // convenient for the client.
+ ScopedVector<Connection> incoming_connections_;
+
+ // A pending Connector request which will eventually be passed to the shell.
+ mojom::ConnectorRequest pending_connector_request_;
+
+ shell::ShellClient* client_;
+ mojo::Binding<mojom::ShellClient> binding_;
+ std::unique_ptr<Connector> connector_;
+ shell::Identity identity_;
+ bool should_run_connection_lost_closure_ = false;
+
+ base::Closure connection_lost_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellConnection);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
diff --git a/chromium/services/shell/public/cpp/shell_connection_ref.h b/chromium/services/shell/public/cpp/shell_connection_ref.h
new file mode 100644
index 00000000000..b22e12ea3d6
--- /dev/null
+++ b/chromium/services/shell/public/cpp/shell_connection_ref.h
@@ -0,0 +1,59 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace shell {
+
+class ShellConnectionRefImpl;
+
+// An interface implementation can keep this object as a member variable to
+// hold a reference to the ShellConnection, keeping it alive as long as the
+// bound implementation exists.
+//
+// This class is safe to use on any thread and instances may be passed to other
+// threads. However, each instance should only be used on one thread at a time,
+// otherwise there'll be races between the AddRef resulting from cloning and
+// destruction.
+class ShellConnectionRef {
+ public:
+ virtual ~ShellConnectionRef() {}
+
+ virtual std::unique_ptr<ShellConnectionRef> Clone() = 0;
+};
+
+class ShellConnectionRefFactory {
+ public:
+ // |quit_closure| is called whenever the last ref is destroyed.
+ explicit ShellConnectionRefFactory(const base::Closure& quit_closure);
+ ~ShellConnectionRefFactory();
+
+ std::unique_ptr<ShellConnectionRef> CreateRef();
+
+ bool HasNoRefs() const { return !ref_count_; }
+
+ private:
+ friend ShellConnectionRefImpl;
+
+ // Called from ShellConnectionRefImpl.
+ void AddRef();
+ void Release();
+
+ const base::Closure quit_closure_;
+ int ref_count_ = 0;
+ base::WeakPtrFactory<ShellConnectionRefFactory> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellConnectionRefFactory);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
diff --git a/chromium/services/shell/public/cpp/shell_test.h b/chromium/services/shell/public/cpp/shell_test.h
new file mode 100644
index 00000000000..b299297a4c9
--- /dev/null
+++ b/chromium/services/shell/public/cpp/shell_test.h
@@ -0,0 +1,112 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace shell {
+
+class BackgroundShell;
+
+namespace test {
+
+class ShellTest;
+
+// A default implementation of ShellClient for use in ShellTests. Tests wishing
+// to customize this should subclass this class instead of ShellClient,
+// otherwise they will have to call ShellTest::InitializeCalled() to forward
+// metadata from Initialize() to the test.
+class ShellTestClient : public ShellClient {
+ public:
+ explicit ShellTestClient(ShellTest* test);
+ ~ShellTestClient() override;
+
+ protected:
+ void Initialize(Connector* connector,
+ const Identity& identity,
+ uint32_t id) override;
+
+ private:
+ ShellTest* test_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellTestClient);
+};
+
+class ShellTest : public testing::Test {
+ public:
+ ShellTest();
+ // Initialize passing the name to use as the identity for the test itself.
+ // Once set via this constructor, it cannot be changed later by calling
+ // InitTestName(). The test executable must provide a manifest in the
+ // appropriate location that specifies this name also.
+ explicit ShellTest(const std::string& test_name);
+ ~ShellTest() override;
+
+ protected:
+ // See constructor. Can only be called once.
+ void InitTestName(const std::string& test_name);
+
+ Connector* connector() { return connector_; }
+
+ // Instance information received from the Shell during Initialize().
+ const std::string& test_name() const { return initialize_name_; }
+ const std::string& test_userid() const { return initialize_userid_; }
+ uint32_t test_instance_id() const { return initialize_instance_id_; }
+
+ // By default, creates a simple ShellClient that captures the metadata sent
+ // via Initialize(). Override to customize, but custom implementations must
+ // call InitializeCalled() to forward the metadata so test_name() etc all
+ // work.
+ virtual std::unique_ptr<ShellClient> CreateShellClient();
+
+ virtual std::unique_ptr<base::MessageLoop> CreateMessageLoop();
+
+ // Call to set Initialize() metadata when GetShellClient() is overridden.
+ void InitializeCalled(Connector* connector,
+ const std::string& name,
+ const std::string& userid,
+ uint32_t id);
+
+ // testing::Test:
+ void SetUp() override;
+ void TearDown() override;
+
+ private:
+ friend ShellTestClient;
+
+ std::unique_ptr<ShellClient> shell_client_;
+
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<BackgroundShell> background_shell_;
+ std::unique_ptr<ShellConnection> shell_connection_;
+
+ // See constructor.
+ std::string test_name_;
+
+ Connector* connector_ = nullptr;
+ std::string initialize_name_;
+ std::string initialize_userid_ = shell::mojom::kInheritUserID;
+ uint32_t initialize_instance_id_ = shell::mojom::kInvalidInstanceID;
+
+ base::Closure initialize_called_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellTest);
+};
+
+} // namespace test
+} // namespace shell
+
+#endif // SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
diff --git a/chromium/services/shell/public/interfaces/BUILD.gn b/chromium/services/shell/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..5a2ef6ce1cd
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/BUILD.gn
@@ -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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+# GYP version: mojo/mojo_base.gyp:mojo_application_bindings
+mojom("interfaces") {
+ sources = [
+ "capabilities.mojom",
+ "connector.mojom",
+ "interface_provider.mojom",
+ "shell.mojom",
+ "shell_client.mojom",
+ "shell_client_factory.mojom",
+ "shell_resolver.mojom",
+ ]
+
+ public_deps = [
+ "//mojo/common:common_custom_types",
+ ]
+}
diff --git a/chromium/services/shell/public/interfaces/OWNERS b/chromium/services/shell/public/interfaces/OWNERS
new file mode 100644
index 00000000000..9e621796752
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/OWNERS
@@ -0,0 +1,13 @@
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=mkwst@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=palmer@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/chromium/services/shell/public/interfaces/capabilities.mojom b/chromium/services/shell/public/interfaces/capabilities.mojom
new file mode 100644
index 00000000000..dff92305f4b
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/capabilities.mojom
@@ -0,0 +1,47 @@
+// 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.
+
+module shell.mojom;
+
+// Mojo Capabilities -----------------------------------------------------------
+//
+// Mojo applications expose interfaces and capability classes to one another.
+//
+// An interface is just a Mojo interface, defined in a mojom file like this one.
+// In a CapabilitySpec, an interface is represented by its fully qualified name,
+// which is serialized based on the interface name and module:
+// module::path::InterfaceName.
+//
+// A class is an alias to something, either a set of interface names granted
+// with that class, or some behavior specific to the application that provides
+// it.
+
+// Describes the set of classes and interfaces required by an application.
+// Note that there may be overlap between the interfaces implied by the
+// resolution of classes and those specified in |interfaces|. The set of
+// interfaces granted to the requestor is the union of these sets.
+struct CapabilityRequest {
+ // An array of class names required.
+ array<string> classes;
+ // An array of interface names required.
+ array<string> interfaces;
+};
+
+// Describes the capabilities offered and requested by an application.
+// This struct is populated from the application manifest.
+struct CapabilitySpec {
+ // The classes offered by this application, and for each class an array of
+ // interfaces. If no interfaces are granted with a class, the array will be
+ // empty.
+ // A map of class name -> array of interfaces. The array can be empty,
+ // non-empty, or ["*"], which means allow access to all interfaces.
+ map<string, array<string>> provided;
+
+ // The applications this application needs to speak to, and the classes and
+ // interfaces it requests.
+ // A map of application name -> spec. "*" is also supported as the key, which
+ // supplies a CapabilityRequest for all applications in addition to specific
+ // ones specified.
+ map<string, CapabilityRequest> required;
+};
diff --git a/chromium/services/shell/public/interfaces/connector.mojom b/chromium/services/shell/public/interfaces/connector.mojom
new file mode 100644
index 00000000000..f419ebee4aa
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/connector.mojom
@@ -0,0 +1,144 @@
+// 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.
+
+module shell.mojom;
+
+import "services/shell/public/interfaces/interface_provider.mojom";
+
+const string kRootUserID = "505C0EE9-3013-43C0-82B0-A84F50CF8D84";
+const string kInheritUserID = "D26290E4-4485-4EAE-81A2-66D1EEB40A9D";
+
+const uint32 kInvalidInstanceID = 0;
+
+enum ConnectResult {
+ // The connection was established successfully.
+ SUCCEEDED,
+
+ // The name or user id supplied was malformed, or the application specified
+ // by |name| could not be loaded.
+ INVALID_ARGUMENT,
+
+ // The connection was blocked by policy. Either connections to |name| are
+ // forbidden from this app by the CapabilityFilter, or the application
+ // attempted to connect using a user id other than its own,
+ // kInheritUserID or kRootUserID.
+ ACCESS_DENIED
+};
+
+// A collection of metadata that disambiguates instances in the shell.
+struct Identity {
+ // A mojo: or exe: name identifying an application.
+ string name;
+
+ // The user id of the target application instance to connect to. If no such
+ // instance exists, the shell may start one. This user id will be passed to
+ // the new instance via Initialize().
+ // When connecting to other applications, applications must generally pass
+ // kInheritUserID for this value, and the shell will either connect to an
+ // existing instance matching the caller's user id, create a new instance
+ // matching the caller's user id, or connect to an existing instance running
+ // as kRootUserID. By default, applications do not have the ability to set
+ // arbitrary values to this field, and doing so will result in a connection
+ // error on the remote service provider. An application with the ability to
+ // launch applications with arbitrary user ids (e.g. a login app) may set this
+ // value to something meaningful to it. The user id string is a valid guid of
+ // the form "%08X-%04X-%04X-%04X-%012llX", and (aside from the root user whose
+ // guid is defined above) intended to be not-guessable.
+ // When an application is initialized or receives a connection from another
+ // application, this value is always the resolved user id, never
+ // kInheritUserID.
+ string user_id;
+
+ // An application may spawn multiple instances with the same name,user_id
+ // pair, provided they are started with unique values of this field.
+ // TODO(beng): enforce the emptiness of this parameter unless the client bears
+ // the appropriate capability.
+ string instance;
+};
+
+// Implemented by an object in the shell associated with a specific instance.
+// Tells it the PID for a process launched by the client. See
+// ClientProcessConnection.
+interface PIDReceiver {
+ SetPID(uint32 pid);
+};
+
+// Typically, the shell will start a process for a service the first time it
+// receives a connection request for it. This struct allows a client to start
+// the process itself and provide the shell the pipes it needs to communicate
+// with it. When an instance of this struct is supplied to Connect(), the client
+// owns the lifetime of the child process, not the shell. The shell binds the
+// |shell_client| pipe, and when it closes destroys the associated instance but
+// the process stays alive.
+struct ClientProcessConnection {
+ // Provides the shell the ability to bind a ShellClient from the client
+ // process to the instance it creates.
+ handle<message_pipe> shell_client;
+
+ // Allows the client process launcher to tell the shell the PID of the process
+ // it created (the pid isn't supplied directly here as the process may not
+ // have been launched by the time Connect() is called.)
+ handle<message_pipe> pid_receiver_request;
+};
+
+// Encapsulates establishing connections with other Mojo applications.
+interface Connector {
+ // Requests a connection with another application. The application originating
+ // the request is referred to as the "source" and the one receiving the
+ // "target".
+ //
+ // The connection is embodied by a pair of message pipes binding the
+ // InterfaceProvider interface, which allows both the source and target
+ // applications to export interfaces to one another. The interfaces bound via
+ // these InterfaceProviders are brokered by the shell according to the
+ // security policy defined by each application in its manifest .
+ //
+ // If the target application is not running, the shell will run it, calling
+ // its Initialize() method before completing the connection.
+ //
+ // Parameters:
+ //
+ // target
+ // Identifies the target application instance to connect to.
+ //
+ // remote_interfaces
+ // Allows the source application access to interface implementations
+ // exposed by the target application. The interfaces accessible via this
+ // InterfaceParameter are filtered by the security policy described by the
+ // source and target application manifests.
+ //
+ // local_interfaces
+ // Allows the remote application access to interface implementations
+ // exposed by the source application. The interfaces accessible via this
+ // InterfaceProvider are filtered by the security policy described by the
+ // source and target application manifests.
+ //
+ // client_process_connection
+ // When non-null, supplies control pipes the shell can use to bind a
+ // process created by the client, instead of creating one itself.
+ // TODO(beng): access to this parameter should be restricted by a
+ // capability.
+ //
+ // Response parameters:
+ //
+ // result
+ // Indicates the result of the Connect() operation.
+ //
+ // user_id
+ // The user id the shell ran the target application as. Typically a client
+ // passes kInheritUserID as the user id to Connect() which is resolved by
+ // the shell into a valid user id returned through this callback.
+ //
+ // application_id
+ // A unique identifier for the instance that was connected to.
+ //
+ Connect(Identity target,
+ InterfaceProvider&? remote_interfaces,
+ InterfaceProvider? local_interfaces,
+ ClientProcessConnection? client_process_connection) =>
+ (ConnectResult result, string user_id, uint32 application_id);
+
+ // Clones this Connector so it can be passed to another thread.
+ Clone(Connector& request);
+};
diff --git a/chromium/services/shell/public/interfaces/interface_provider.mojom b/chromium/services/shell/public/interfaces/interface_provider.mojom
new file mode 100644
index 00000000000..c64f52f637a
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/interface_provider.mojom
@@ -0,0 +1,17 @@
+// 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.
+
+module shell.mojom;
+
+// An interface through which a client may request interfaces from a host.
+// Instances of this interface are created within the context of an
+// already-identified client and host pair, so there is no need to explicitly
+// identify the client or host in the methods below.
+interface InterfaceProvider {
+ // Asks the host to provide an implementation of the interface identified by
+ // |interface_name| through the message |pipe| endpoint supplied by the caller.
+ // If the host is not willing or able to provide the requested interface, it
+ // must close the |pipe|.
+ GetInterface(string interface_name, handle<message_pipe> pipe);
+};
diff --git a/chromium/services/shell/public/interfaces/shell.mojom b/chromium/services/shell/public/interfaces/shell.mojom
new file mode 100644
index 00000000000..2ff9201882d
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/shell.mojom
@@ -0,0 +1,41 @@
+// 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 shell.mojom;
+
+import "services/shell/public/interfaces/connector.mojom";
+
+struct InstanceInfo {
+ uint32 id;
+ Identity identity;
+ uint32 pid;
+};
+
+// Implemented by a client that wishes to be informed when the list of running
+// instances changes.
+interface InstanceListener {
+ // Called once when the listener is added via Shell::AddInstanceListener() to
+ // provide the initial list of instances that the listener observes changes
+ // against.
+ SetExistingInstances(array<InstanceInfo> instances);
+
+ // Called when the shell has started tracking an instance. This happens when
+ // the shell first handles a request to launch the instance, before any
+ // process is created for it.
+ InstanceCreated(InstanceInfo instance);
+
+ // Called when the shell has stopped tracking an instance. (i.e. when it has
+ // ended/quit).
+ InstanceDestroyed(uint32 id);
+
+ // Called when a pid is available for the instance. This could be because a
+ // process was created by the runner for it, or because an existing content
+ // handler process was assigned.
+ InstancePIDAvailable(uint32 id, uint32 pid);
+};
+
+interface Shell {
+ // The listener is removed when the |listener| pipe is closed.
+ AddInstanceListener(InstanceListener listener);
+};
diff --git a/chromium/services/shell/public/interfaces/shell_client.mojom b/chromium/services/shell/public/interfaces/shell_client.mojom
new file mode 100644
index 00000000000..04618cac063
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/shell_client.mojom
@@ -0,0 +1,78 @@
+// 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.
+
+module shell.mojom;
+
+import "services/shell/public/interfaces/capabilities.mojom";
+import "services/shell/public/interfaces/connector.mojom";
+import "services/shell/public/interfaces/interface_provider.mojom";
+
+// Implemented by something "known to" the Mojo Shell (e.g. an application or
+// service), for which an instance is tracked. It allows the implementor to
+// receive lifecycle events and service inbound connection attempts.
+interface ShellClient {
+ // Called by the shell once an instance for this application has been created.
+ // This method will be called exactly once before any other method is called.
+ //
+ // Parameters:
+ //
+ // identity
+ // The identity of this instance in the shell. Includes:
+ // * The resolved name used in the connection request that resulted in this
+ // instance being initialized.
+ // * The user associated with this instance in the shell. This will never
+ // be kInheritUserID.
+ // * The instance group this instance belongs to.
+ //
+ // id
+ // A unique identifier used by the shell to identify this instance.
+ //
+ //
+ // Response parameters:
+ //
+ // connector_request
+ // An optional Connector request for the shell to bind, allowing the
+ // initialized client to connect to others.
+ //
+ Initialize(Identity identity, uint32 id) => (Connector&? connector_request);
+
+ // Called when another application attempts to open a connection to this
+ // application. An application implements this method to complete the exchange
+ // of interface implementations with the remote application. See also
+ // documentation in shell.mojom for Connect(). The application originating
+ // the request is referred to as the "source" and the one receiving the
+ // "target".
+ //
+ // Parameters:
+ //
+ // source
+ // The identity of the instance originating the connection.
+ //
+ // source_id
+ // A unique identifier used by the shell to identify the source instance.
+ //
+ // local_interfaces
+ // A request for an InterfaceProvider by which the source application may
+ // seek to bind interface implementations exported by the target.
+ //
+ // remote_interfaces
+ // An InterfaceProvider by which the target application may bind interface
+ // implementations exported by the source.
+ //
+ // allowed_interfaces
+ // A whitelist of interface names that should be exported to the source,
+ // according to the security policy described by the source and target's
+ // manifests. Attempts to bind interfaces not in this whitelist must not be
+ // fulfilled.
+ //
+ // resolved_name
+ // The resolved name used to complete this connection.
+ //
+ AcceptConnection(Identity source,
+ uint32 source_id,
+ InterfaceProvider&? local_interfaces,
+ InterfaceProvider? remote_interfaces,
+ CapabilityRequest allowed_capabilities,
+ string resolved_name);
+};
diff --git a/chromium/services/shell/public/interfaces/shell_client_factory.mojom b/chromium/services/shell/public/interfaces/shell_client_factory.mojom
new file mode 100644
index 00000000000..a159389db52
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/shell_client_factory.mojom
@@ -0,0 +1,13 @@
+// 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.
+
+module shell.mojom;
+
+import "services/shell/public/interfaces/shell_client.mojom";
+
+// Implemented by a package containing multiple applications identified by
+// unique names.
+interface ShellClientFactory {
+ CreateShellClient(ShellClient& shell_client, string name);
+};
diff --git a/chromium/services/shell/public/interfaces/shell_resolver.mojom b/chromium/services/shell/public/interfaces/shell_resolver.mojom
new file mode 100644
index 00000000000..3483aa68b4d
--- /dev/null
+++ b/chromium/services/shell/public/interfaces/shell_resolver.mojom
@@ -0,0 +1,38 @@
+// 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.
+
+module shell.mojom;
+
+import "mojo/common/common_custom_types.mojom";
+import "services/shell/public/interfaces/capabilities.mojom";
+
+// The result of a Resolve operation via ShellResolver.
+struct ResolveResult {
+ // The mojo: name that was requested to be resolved.
+ string name;
+
+ // The mojo: name of the physical package supplying the requested name. This
+ // could be the same name that was passed, or the name of a package that
+ // contains it.
+ string resolved_name;
+
+ // An additional piece of metadata that identifies what instance |name| should
+ // be run in. It's possible that |name| may provide several services that
+ // should be run as different instances.
+ string qualifier;
+
+ // The set of capabilities provided and required by |name|.
+ CapabilitySpec capabilities;
+
+ // A path to the package file specified by |name|.
+ mojo.common.mojom.FilePath package_path;
+};
+
+// Implemented exclusively for the Mojo Shell's use in resolving mojo: names
+// and reading static manifest information.
+interface ShellResolver {
+ // Resolves |mojo_name| and returns a ResolveResult containing metadata from
+ // the catalog that the Shell uses to run an instance of it.
+ ResolveMojoName(string mojo_name) => (ResolveResult result);
+};
diff --git a/chromium/services/shell/public/java/BUILD.gn b/chromium/services/shell/public/java/BUILD.gn
new file mode 100644
index 00000000000..925916fb172
--- /dev/null
+++ b/chromium/services/shell/public/java/BUILD.gn
@@ -0,0 +1,21 @@
+# 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.
+
+import("//build/config/android/rules.gni")
+
+android_library("application") {
+ java_files = [
+ "src/org/chromium/mojo/application/ApplicationConnection.java",
+ "src/org/chromium/mojo/application/ApplicationDelegate.java",
+ "src/org/chromium/mojo/application/ApplicationImpl.java",
+ "src/org/chromium/mojo/application/ApplicationRunner.java",
+ "src/org/chromium/mojo/application/ServiceFactoryBinder.java",
+ "src/org/chromium/mojo/application/ShellHelper.java",
+ ]
+ deps = [
+ "//mojo/public/java:bindings",
+ "//mojo/public/java:system",
+ "//services/shell/public/interfaces:interfaces_java",
+ ]
+}
diff --git a/chromium/services/shell/runner/BUILD.gn b/chromium/services/shell/runner/BUILD.gn
new file mode 100644
index 00000000000..65520053a58
--- /dev/null
+++ b/chromium/services/shell/runner/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+group("runner") {
+ testonly = true
+ deps = [
+ "//services/shell/runner/child",
+ "//services/shell/runner/host",
+ ]
+}
+
+source_set("init") {
+ sources = [
+ "init.cc",
+ "init.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base:base_static",
+ "//base:i18n",
+ "//services/shell/runner/common",
+ ]
+}
diff --git a/chromium/services/shell/runner/child/BUILD.gn b/chromium/services/shell/runner/child/BUILD.gn
new file mode 100644
index 00000000000..197a0a46e42
--- /dev/null
+++ b/chromium/services/shell/runner/child/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+
+group("child") {
+ testonly = true
+ deps = [
+ ":test_native_main",
+ ]
+}
+
+source_set("test_native_main") {
+ sources = [
+ "test_native_main.cc",
+ "test_native_main.h",
+ ]
+
+ public_deps = [
+ "//services/shell/runner:init",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/edk/system",
+ "//services/shell/public/cpp",
+ "//services/shell/runner/common",
+ ]
+}
diff --git a/chromium/services/shell/runner/child/manifest.json b/chromium/services/shell/runner/child/manifest.json
new file mode 100644
index 00000000000..a6a557a0d3a
--- /dev/null
+++ b/chromium/services/shell/runner/child/manifest.json
@@ -0,0 +1,10 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:mojo_runner_child_apptest",
+ "display_name": "Runner Child Apptest",
+ "capabilities": {
+ "required": {
+ "*": { "classes": [ "app" ] }
+ }
+ }
+}
diff --git a/chromium/services/shell/runner/child/test_native_main.cc b/chromium/services/shell/runner/child/test_native_main.cc
new file mode 100644
index 00000000000..ea5bd0c96bb
--- /dev/null
+++ b/chromium/services/shell/runner/child/test_native_main.cc
@@ -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.
+
+#include "services/shell/runner/child/test_native_main.h"
+
+#include <utility>
+
+#include "base/debug/stack_trace.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/launch.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/runner/common/client_util.h"
+#include "services/shell/runner/init.h"
+
+namespace shell {
+namespace {
+
+class ProcessDelegate : public mojo::edk::ProcessDelegate {
+ public:
+ ProcessDelegate() {}
+ ~ProcessDelegate() override {}
+
+ private:
+ void OnShutdownComplete() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
+};
+
+} // namespace
+
+int TestNativeMain(shell::ShellClient* shell_client) {
+ shell::WaitForDebuggerIfNecessary();
+
+#if !defined(OFFICIAL_BUILD)
+ base::debug::EnableInProcessStackDumping();
+#if defined(OS_WIN)
+ base::RouteStdioToConsole(false);
+#endif
+#endif
+
+ {
+ mojo::edk::Init();
+
+ ProcessDelegate process_delegate;
+ base::Thread io_thread("io_thread");
+ base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
+ CHECK(io_thread.StartWithOptions(io_thread_options));
+
+ mojo::edk::InitIPCSupport(&process_delegate, io_thread.task_runner());
+ mojo::edk::SetParentPipeHandleFromCommandLine();
+
+ base::MessageLoop loop;
+ shell::ShellConnection impl(shell_client,
+ shell::GetShellClientRequestFromCommandLine());
+ loop.Run();
+
+ mojo::edk::ShutdownIPCSupport();
+ }
+
+ return 0;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/child/test_native_main.h b/chromium/services/shell/runner/child/test_native_main.h
new file mode 100644
index 00000000000..a8956166697
--- /dev/null
+++ b/chromium/services/shell/runner/child/test_native_main.h
@@ -0,0 +1,16 @@
+// 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 SERVICES_SHELL_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
+#define SERVICES_SHELL_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
+
+namespace shell {
+
+class ShellClient;
+
+int TestNativeMain(ShellClient* shell_client);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
diff --git a/chromium/services/shell/runner/common/BUILD.gn b/chromium/services/shell/runner/common/BUILD.gn
new file mode 100644
index 00000000000..4bb5387fbdc
--- /dev/null
+++ b/chromium/services/shell/runner/common/BUILD.gn
@@ -0,0 +1,23 @@
+# 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.
+
+source_set("common") {
+ sources = [
+ "client_util.cc",
+ "client_util.h",
+ "switches.cc",
+ "switches.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/edk/system",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/system",
+ ]
+
+ public_deps = [
+ "//services/shell/public/interfaces",
+ ]
+}
diff --git a/chromium/services/shell/runner/common/client_util.cc b/chromium/services/shell/runner/common/client_util.cc
new file mode 100644
index 00000000000..9a79c0e88db
--- /dev/null
+++ b/chromium/services/shell/runner/common/client_util.cc
@@ -0,0 +1,36 @@
+// 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 "services/shell/runner/common/client_util.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "services/shell/runner/common/switches.h"
+
+namespace shell {
+
+mojom::ShellClientPtr PassShellClientRequestOnCommandLine(
+ base::CommandLine* command_line) {
+ std::string token = mojo::edk::GenerateRandomToken();
+ command_line->AppendSwitchASCII(switches::kPrimordialPipeToken, token);
+
+ mojom::ShellClientPtr client;
+ client.Bind(
+ mojom::ShellClientPtrInfo(mojo::edk::CreateParentMessagePipe(token), 0));
+ return client;
+}
+
+mojom::ShellClientRequest GetShellClientRequestFromCommandLine() {
+ std::string token =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kPrimordialPipeToken);
+ mojom::ShellClientRequest request;
+ if (!token.empty())
+ request.Bind(mojo::edk::CreateChildMessagePipe(token));
+ return request;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/common/client_util.h b/chromium/services/shell/runner/common/client_util.h
new file mode 100644
index 00000000000..d1ff4ff3be8
--- /dev/null
+++ b/chromium/services/shell/runner/common/client_util.h
@@ -0,0 +1,30 @@
+// 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 SERVICES_SHELL_RUNNER_COMMON_CLIENT_UTIL_H_
+#define SERVICES_SHELL_RUNNER_COMMON_CLIENT_UTIL_H_
+
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace shell {
+
+// Creates a new ShellClient pipe and returns one end of it. The other end is
+// passed via a token in |command_line|. A child of the calling process may
+// extract a ShellClientRequest from this by calling
+// GetShellClientRequestFromCommandLine().
+mojom::ShellClientPtr PassShellClientRequestOnCommandLine(
+ base::CommandLine* command_line);
+
+// Extracts a ShellClientRequest from the command line of the current process.
+// The parent of this process should have passed a request using
+// PassShellClientRequestOnCommandLine().
+mojom::ShellClientRequest GetShellClientRequestFromCommandLine();
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_COMMON_CLIENT_UTIL_H_
diff --git a/chromium/services/shell/runner/common/switches.cc b/chromium/services/shell/runner/common/switches.cc
new file mode 100644
index 00000000000..545123781a3
--- /dev/null
+++ b/chromium/services/shell/runner/common/switches.cc
@@ -0,0 +1,21 @@
+// 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 "services/shell/runner/common/switches.h"
+
+namespace switches {
+
+// Used internally by the main process to indicate that a new process should be
+// a child process. Takes the absolute path to the mojo application to load as
+// an argument. Not for user use.
+const char kChildProcess[] = "child-process";
+
+// Enables the sandbox on this process.
+const char kEnableSandbox[] = "enable-sandbox";
+
+// Provides a child process with a token string they can use to establish a
+// primordial message pipe to the parent.
+const char kPrimordialPipeToken[] = "primordial-pipe-token";
+
+} // namespace switches
diff --git a/chromium/services/shell/runner/common/switches.h b/chromium/services/shell/runner/common/switches.h
new file mode 100644
index 00000000000..4406b07acce
--- /dev/null
+++ b/chromium/services/shell/runner/common/switches.h
@@ -0,0 +1,18 @@
+// 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 SERVICES_SHELL_RUNNER_COMMON_SWITCHES_H_
+#define SERVICES_SHELL_RUNNER_COMMON_SWITCHES_H_
+
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kChildProcess[];
+extern const char kEnableSandbox[];
+extern const char kPrimordialPipeToken[];
+
+} // namespace switches
+
+#endif // SERVICES_SHELL_RUNNER_COMMON_SWITCHES_H_
diff --git a/chromium/services/shell/runner/host/BUILD.gn b/chromium/services/shell/runner/host/BUILD.gn
new file mode 100644
index 00000000000..b7658de33cc
--- /dev/null
+++ b/chromium/services/shell/runner/host/BUILD.gn
@@ -0,0 +1,126 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
+
+group("host") {
+ testonly = true
+
+ deps = [
+ ":lib",
+ ":mojo_runner_host_unittests",
+ ]
+}
+
+source_set("native_application_support") {
+ sources = [
+ "native_application_support.cc",
+ "native_application_support.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/platform_handle:platform_handle_impl",
+ "//services/shell",
+ ]
+
+ # This target has to include the public thunk headers, which generally
+ # shouldn't be included without picking an implementation. We are providing
+ # the implementation but the thunk header target cannot declare that we are
+ # permitted to include it since it's in the public SDK and we are not.
+ # Suppress include checking so we can still check the rest of the targets in
+ # this file.
+ check_includes = false
+}
+
+source_set("child_process_base") {
+ sources = [
+ "child_process_base.cc",
+ "child_process_base.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/edk/system",
+ "//mojo/platform_handle:platform_handle_impl",
+ "//services/shell",
+ "//services/shell/public/interfaces",
+ "//services/shell/runner:init",
+ "//services/shell/runner/common",
+ ]
+}
+
+source_set("lib") {
+ sources = [
+ "child_process.cc",
+ "child_process.h",
+ "child_process_host.cc",
+ "child_process_host.h",
+ "in_process_native_runner.cc",
+ "in_process_native_runner.h",
+ "out_of_process_native_runner.cc",
+ "out_of_process_native_runner.h",
+ ]
+
+ deps = [
+ ":child_process_base",
+ ":native_application_support",
+ "//base:base_static",
+ "//base:i18n",
+ "//mojo/platform_handle:platform_handle_impl",
+ "//services/shell/public/cpp:sources",
+ "//services/shell/runner:init",
+ "//services/shell/runner/common",
+ ]
+
+ public_deps = [
+ "//base",
+ "//mojo/edk/system",
+ "//mojo/public/cpp/system",
+ "//services/shell",
+ "//services/shell/public/interfaces",
+ ]
+
+ if (is_linux && !is_android) {
+ sources += [
+ "linux_sandbox.cc",
+ "linux_sandbox.h",
+ ]
+
+ deps += [
+ "//sandbox/linux:sandbox",
+ "//sandbox/linux:sandbox_services",
+ "//sandbox/linux:seccomp_bpf",
+ "//sandbox/linux:seccomp_bpf_helpers",
+ ]
+ }
+
+ if (is_mac) {
+ sources += [
+ "mach_broker.cc",
+ "mach_broker.h",
+ ]
+ }
+}
+
+test("mojo_runner_host_unittests") {
+ sources = [
+ "child_process_host_unittest.cc",
+ "host_unittests.cc",
+ "in_process_native_runner_unittest.cc",
+ ]
+
+ deps = [
+ ":lib",
+ "//base",
+ "//base/test:test_support",
+ "//mojo/edk/system",
+ "//services/shell",
+ "//services/shell/runner:init",
+ "//services/shell/runner/common",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/services/shell/runner/host/DEPS b/chromium/services/shell/runner/host/DEPS
new file mode 100644
index 00000000000..ec69c8f59a8
--- /dev/null
+++ b/chromium/services/shell/runner/host/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+sandbox",
+]
diff --git a/chromium/services/shell/runner/host/OWNERS b/chromium/services/shell/runner/host/OWNERS
new file mode 100644
index 00000000000..2b40a92356e
--- /dev/null
+++ b/chromium/services/shell/runner/host/OWNERS
@@ -0,0 +1 @@
+per-file linux_sandbox*=rickyz@chromium.org
diff --git a/chromium/services/shell/runner/host/child_process.cc b/chromium/services/shell/runner/host/child_process.cc
new file mode 100644
index 00000000000..836adc8fa19
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process.cc
@@ -0,0 +1,126 @@
+// 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 "services/shell/runner/host/child_process.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/core.h"
+#include "services/shell/runner/common/switches.h"
+#include "services/shell/runner/host/child_process_base.h"
+#include "services/shell/runner/host/native_application_support.h"
+#include "services/shell/runner/init.h"
+
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "services/shell/runner/host/linux_sandbox.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "services/shell/runner/host/mach_broker.h"
+#endif
+
+namespace shell {
+
+namespace {
+
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+std::unique_ptr<LinuxSandbox> InitializeSandbox() {
+ using sandbox::syscall_broker::BrokerFilePermission;
+ // Warm parts of base in the copy of base in the mojo runner.
+ base::RandUint64();
+ base::SysInfo::AmountOfPhysicalMemory();
+ base::SysInfo::MaxSharedMemorySize();
+ base::SysInfo::NumberOfProcessors();
+
+ // TODO(erg,jln): Allowing access to all of /dev/shm/ makes it easy to
+ // spy on other shared memory using processes. This is a temporary hack
+ // so that we have some sandbox until we have proper shared memory
+ // support integrated into mojo.
+ std::vector<BrokerFilePermission> permissions;
+ permissions.push_back(
+ BrokerFilePermission::ReadWriteCreateUnlinkRecursive("/dev/shm/"));
+ std::unique_ptr<LinuxSandbox> sandbox(new LinuxSandbox(permissions));
+ sandbox->Warmup();
+ sandbox->EngageNamespaceSandbox();
+ sandbox->EngageSeccompSandbox();
+ sandbox->Seal();
+ return sandbox;
+}
+#endif
+
+void RunNativeLibrary(base::NativeLibrary app_library,
+ mojom::ShellClientRequest shell_client_request) {
+ if (!RunNativeApplication(app_library, std::move(shell_client_request))) {
+ LOG(ERROR) << "Failure to RunNativeApplication()";
+ }
+}
+
+} // namespace
+
+int ChildProcessMain() {
+ DVLOG(2) << "ChildProcessMain()";
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+ std::unique_ptr<LinuxSandbox> sandbox;
+#endif
+ base::NativeLibrary app_library = 0;
+ // Load the application library before we engage the sandbox.
+ base::FilePath app_library_path =
+ command_line.GetSwitchValuePath(switches::kChildProcess);
+ if (!app_library_path.empty())
+ app_library = LoadNativeApplication(app_library_path);
+ base::i18n::InitializeICU();
+ if (app_library)
+ CallLibraryEarlyInitialization(app_library);
+
+#if defined(OS_MACOSX)
+ // Send our task port to the parent.
+ MachBroker::SendTaskPortToParent();
+#endif
+
+#if !defined(OFFICIAL_BUILD)
+ // Initialize stack dumping just before initializing sandbox to make
+ // sure symbol names in all loaded libraries will be cached.
+ base::debug::EnableInProcessStackDumping();
+#endif
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+ if (command_line.HasSwitch(switches::kEnableSandbox))
+ sandbox = InitializeSandbox();
+#endif
+
+ ChildProcessMain(base::Bind(&RunNativeLibrary, app_library));
+
+ return 0;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/child_process.h b/chromium/services/shell/runner/host/child_process.h
new file mode 100644
index 00000000000..1f70c007d59
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process.h
@@ -0,0 +1,15 @@
+// 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.
+
+#ifndef SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_H_
+#define SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_H_
+
+namespace shell {
+
+// Main method for a child process.
+int ChildProcessMain();
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_H_
diff --git a/chromium/services/shell/runner/host/child_process_base.cc b/chromium/services/shell/runner/host/child_process_base.cc
new file mode 100644
index 00000000000..b3daa76bf95
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process_base.cc
@@ -0,0 +1,70 @@
+// 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 "services/shell/runner/host/child_process_base.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "services/shell/runner/common/client_util.h"
+
+namespace shell {
+
+namespace {
+
+// Should be created and initialized on the main thread and kept alive as long
+// a Mojo application is running in the current process.
+class ScopedAppContext : public mojo::edk::ProcessDelegate {
+ public:
+ ScopedAppContext()
+ : io_thread_("io_thread"), wait_for_shutdown_event_(true, false) {
+ // Initialize Mojo before starting any threads.
+ mojo::edk::Init();
+
+ // Create and start our I/O thread.
+ base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
+ CHECK(io_thread_.StartWithOptions(io_thread_options));
+ io_runner_ = io_thread_.task_runner().get();
+ CHECK(io_runner_.get());
+
+ mojo::edk::InitIPCSupport(this, io_runner_);
+ mojo::edk::SetParentPipeHandleFromCommandLine();
+ }
+
+ ~ScopedAppContext() override {
+ mojo::edk::ShutdownIPCSupport();
+ wait_for_shutdown_event_.Wait();
+ }
+
+ private:
+ // ProcessDelegate implementation.
+ void OnShutdownComplete() override {
+ wait_for_shutdown_event_.Signal();
+ }
+
+ base::Thread io_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
+
+ // Used to unblock the main thread on shutdown.
+ base::WaitableEvent wait_for_shutdown_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAppContext);
+};
+
+} // namespace
+
+void ChildProcessMain(const RunCallback& callback) {
+ DCHECK(!base::MessageLoop::current());
+
+ ScopedAppContext app_context;
+ callback.Run(GetShellClientRequestFromCommandLine());
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/child_process_base.h b/chromium/services/shell/runner/host/child_process_base.h
new file mode 100644
index 00000000000..367cf88c3db
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process_base.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 SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_BASE_H_
+#define SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_BASE_H_
+
+#include "base/callback.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace shell {
+
+// Child processes call this to establish the connection to the shell and obtain
+// the ShellClientRequest. Once the connection has been established |callback|
+// is run. ChildProcessMain() returns once the the callback completes.
+using RunCallback = base::Callback<void(mojom::ShellClientRequest)>;
+void ChildProcessMain(const RunCallback& callback);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_BASE_H_
diff --git a/chromium/services/shell/runner/host/child_process_host.cc b/chromium/services/shell/runner/host/child_process_host.cc
new file mode 100644
index 00000000000..f9cda1f85fd
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process_host.cc
@@ -0,0 +1,210 @@
+// 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 "services/shell/runner/host/child_process_host.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/bindings/interface_ptr_info.h"
+#include "mojo/public/cpp/system/core.h"
+#include "services/shell/native_runner_delegate.h"
+#include "services/shell/runner/common/client_util.h"
+#include "services/shell/runner/common/switches.h"
+
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+#include "sandbox/linux/services/namespace_sandbox.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "services/shell/runner/host/mach_broker.h"
+#endif
+
+namespace shell {
+
+ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate,
+ bool start_sandboxed,
+ const Identity& target,
+ const base::FilePath& app_path)
+ : launch_process_runner_(launch_process_runner),
+ delegate_(delegate),
+ start_sandboxed_(start_sandboxed),
+ target_(target),
+ app_path_(app_path),
+ start_child_process_event_(false, false),
+ weak_factory_(this) {
+}
+
+ChildProcessHost::~ChildProcessHost() {
+ if (!app_path_.empty()) {
+ CHECK(!mojo_ipc_channel_)
+ << "Destroying ChildProcessHost before calling Join";
+ }
+}
+
+mojom::ShellClientPtr ChildProcessHost::Start(
+ const Identity& target,
+ const ProcessReadyCallback& callback,
+ const base::Closure& quit_closure) {
+ DCHECK(!child_process_.IsValid());
+
+ const base::CommandLine* parent_command_line =
+ base::CommandLine::ForCurrentProcess();
+ base::FilePath target_path = parent_command_line->GetProgram();
+ // |app_path_| can be empty in tests.
+ if (!app_path_.MatchesExtension(FILE_PATH_LITERAL(".mojo")) &&
+ !app_path_.empty()) {
+ target_path = app_path_;
+ }
+
+ std::unique_ptr<base::CommandLine> child_command_line(
+ new base::CommandLine(target_path));
+
+ child_command_line->AppendArguments(*parent_command_line, false);
+
+#ifndef NDEBUG
+ child_command_line->AppendSwitchASCII("n", target.name());
+ child_command_line->AppendSwitchASCII("u", target.user_id());
+#endif
+
+ if (target_path != app_path_)
+ child_command_line->AppendSwitchPath(switches::kChildProcess, app_path_);
+
+ if (start_sandboxed_)
+ child_command_line->AppendSwitch(switches::kEnableSandbox);
+
+ mojo_ipc_channel_.reset(new mojo::edk::PlatformChannelPair);
+ mojo_ipc_channel_->PrepareToPassClientHandleToChildProcess(
+ child_command_line.get(), &handle_passing_info_);
+
+ mojom::ShellClientPtr client =
+ PassShellClientRequestOnCommandLine(child_command_line.get());
+ launch_process_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this),
+ base::Passed(&child_command_line)),
+ base::Bind(&ChildProcessHost::DidStart,
+ weak_factory_.GetWeakPtr(), callback));
+ return client;
+}
+
+void ChildProcessHost::Join() {
+ if (mojo_ipc_channel_)
+ start_child_process_event_.Wait();
+ mojo_ipc_channel_.reset();
+ if (child_process_.IsValid()) {
+ int rv = -1;
+ LOG_IF(ERROR, !child_process_.WaitForExit(&rv))
+ << "Failed to wait for child process";
+ child_process_.Close();
+ }
+}
+
+void ChildProcessHost::DidStart(const ProcessReadyCallback& callback) {
+ if (child_process_.IsValid()) {
+ callback.Run(child_process_.Pid());
+ } else {
+ LOG(ERROR) << "Failed to start child process";
+ mojo_ipc_channel_.reset();
+ callback.Run(base::kNullProcessId);
+ }
+}
+
+void ChildProcessHost::DoLaunch(
+ std::unique_ptr<base::CommandLine> child_command_line) {
+ if (delegate_) {
+ delegate_->AdjustCommandLineArgumentsForTarget(target_,
+ child_command_line.get());
+ }
+
+ base::LaunchOptions options;
+#if defined(OS_WIN)
+ options.handles_to_inherit = &handle_passing_info_;
+#if defined(OFFICIAL_BUILD)
+ CHECK(false) << "Launching mojo process with inherit_handles is insecure!";
+#endif
+ options.inherit_handles = true;
+ options.stdin_handle = INVALID_HANDLE_VALUE;
+ options.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ options.stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+ // Always inherit stdout/stderr as a pair.
+ if (!options.stdout_handle || !options.stdin_handle)
+ options.stdin_handle = options.stdout_handle = nullptr;
+
+ // Pseudo handles are used when stdout and stderr redirect to the console. In
+ // that case, they're automatically inherited by child processes. See
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075.aspx
+ // Trying to add them to the list of handles to inherit causes CreateProcess
+ // to fail. When this process is launched from Python then a real handle is
+ // used. In that case, we do want to add it to the list of handles that is
+ // inherited.
+ if (options.stdout_handle &&
+ GetFileType(options.stdout_handle) != FILE_TYPE_CHAR) {
+ handle_passing_info_.push_back(options.stdout_handle);
+ }
+ if (options.stderr_handle &&
+ GetFileType(options.stderr_handle) != FILE_TYPE_CHAR &&
+ options.stdout_handle != options.stderr_handle) {
+ handle_passing_info_.push_back(options.stderr_handle);
+ }
+#elif defined(OS_POSIX)
+ handle_passing_info_.push_back(std::make_pair(STDIN_FILENO, STDIN_FILENO));
+ handle_passing_info_.push_back(std::make_pair(STDOUT_FILENO, STDOUT_FILENO));
+ handle_passing_info_.push_back(std::make_pair(STDERR_FILENO, STDERR_FILENO));
+ options.fds_to_remap = &handle_passing_info_;
+#endif
+ DVLOG(2) << "Launching child with command line: "
+ << child_command_line->GetCommandLineString();
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+ if (start_sandboxed_) {
+ child_process_ =
+ sandbox::NamespaceSandbox::LaunchProcess(*child_command_line, options);
+ if (!child_process_.IsValid()) {
+ LOG(ERROR) << "Starting the process with a sandbox failed. Missing kernel"
+ << " support.";
+ }
+ } else
+#endif
+ {
+#if defined(OS_MACOSX)
+ MachBroker* mach_broker = MachBroker::GetInstance();
+ base::AutoLock locker(mach_broker->GetLock());
+#endif
+ child_process_ = base::LaunchProcess(*child_command_line, options);
+#if defined(OS_MACOSX)
+ mach_broker->ExpectPid(child_process_.Handle());
+#endif
+ }
+
+ if (child_process_.IsValid()) {
+ if (mojo_ipc_channel_.get()) {
+ mojo_ipc_channel_->ChildProcessLaunched();
+ mojo::edk::ChildProcessLaunched(
+ child_process_.Handle(),
+ mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(
+ mojo_ipc_channel_->PassServerHandle().release().handle)));
+ }
+ }
+ start_child_process_event_.Signal();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/child_process_host.h b/chromium/services/shell/runner/host/child_process_host.h
new file mode 100644
index 00000000000..3234cd90cbe
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process_host.h
@@ -0,0 +1,98 @@
+// 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.
+
+#ifndef SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_HOST_H_
+#define SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_HOST_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/interfaces/shell_client_factory.mojom.h"
+#include "services/shell/runner/host/child_process_host.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace shell {
+
+class Identity;
+class NativeRunnerDelegate;
+
+// This class represents a "child process host". Handles launching and
+// connecting a platform-specific "pipe" to the child, and supports joining the
+// child process. Currently runs a single app (loaded from the file system).
+//
+// This class is not thread-safe. It should be created/used/destroyed on a
+// single thread.
+//
+// Note: Does not currently work on Windows before Vista.
+// Note: After |Start()|, |StartApp| must be called and this object must
+// remained alive until the |on_app_complete| callback is called.
+class ChildProcessHost {
+ public:
+ using ProcessReadyCallback = base::Callback<void(base::ProcessId)>;
+
+ // |name| is just for debugging ease. We will spawn off a process so that it
+ // can be sandboxed if |start_sandboxed| is true. |app_path| is a path to the
+ // mojo application we wish to start.
+ ChildProcessHost(base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate,
+ bool start_sandboxed,
+ const Identity& target,
+ const base::FilePath& app_path);
+ virtual ~ChildProcessHost();
+
+ // |Start()|s the child process; calls |DidStart()| (on the thread on which
+ // |Start()| was called) when the child has been started (or failed to start).
+ mojom::ShellClientPtr Start(const Identity& target,
+ const ProcessReadyCallback& callback,
+ const base::Closure& quit_closure);
+
+ // Waits for the child process to terminate.
+ void Join();
+
+ protected:
+ void DidStart(const ProcessReadyCallback& callback);
+
+ private:
+ void DoLaunch(std::unique_ptr<base::CommandLine> child_command_line);
+
+ scoped_refptr<base::TaskRunner> launch_process_runner_;
+ NativeRunnerDelegate* delegate_ = nullptr;
+ bool start_sandboxed_ = false;
+ Identity target_;
+ const base::FilePath app_path_;
+ base::Process child_process_;
+
+ // Used to initialize the Mojo IPC channel between parent and child.
+ std::unique_ptr<mojo::edk::PlatformChannelPair> mojo_ipc_channel_;
+ mojo::edk::HandlePassingInformation handle_passing_info_;
+
+ // Since Start() calls a method on another thread, we use an event to block
+ // the main thread if it tries to destruct |this| while launching the process.
+ base::WaitableEvent start_child_process_event_;
+
+ base::WeakPtrFactory<ChildProcessHost> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildProcessHost);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_CHILD_PROCESS_HOST_H_
diff --git a/chromium/services/shell/runner/host/child_process_host_unittest.cc b/chromium/services/shell/runner/host/child_process_host_unittest.cc
new file mode 100644
index 00000000000..f4867d4e754
--- /dev/null
+++ b/chromium/services/shell/runner/host/child_process_host_unittest.cc
@@ -0,0 +1,109 @@
+// 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.
+
+// Note: This file also tests child_process.*.
+
+#include "services/shell/runner/host/child_process_host.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "services/shell/native_runner_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace shell {
+namespace {
+
+void ProcessReadyCallbackAdapater(const base::Closure& callback,
+ base::ProcessId process_id) {
+ callback.Run();
+}
+
+class ProcessDelegate : public mojo::edk::ProcessDelegate {
+ public:
+ ProcessDelegate() {}
+ ~ProcessDelegate() override {}
+
+ private:
+ void OnShutdownComplete() override {}
+ DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
+};
+
+class NativeRunnerDelegateImpl : public NativeRunnerDelegate {
+ public:
+ NativeRunnerDelegateImpl() {}
+ ~NativeRunnerDelegateImpl() override {}
+
+ size_t get_and_clear_adjust_count() {
+ size_t count = 0;
+ std::swap(count, adjust_count_);
+ return count;
+ }
+
+ private:
+ // NativeRunnerDelegate:
+ void AdjustCommandLineArgumentsForTarget(
+ const Identity& target,
+ base::CommandLine* command_line) override {
+ adjust_count_++;
+ }
+
+ size_t adjust_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeRunnerDelegateImpl);
+};
+
+#if defined(OS_ANDROID)
+// TODO(qsr): Multiprocess shell tests are not supported on android.
+#define MAYBE_StartJoin DISABLED_StartJoin
+#else
+#define MAYBE_StartJoin StartJoin
+#endif // defined(OS_ANDROID)
+// Just tests starting the child process and joining it (without starting an
+// app).
+TEST(ChildProcessHostTest, MAYBE_StartJoin) {
+ base::FilePath shell_dir;
+ PathService::Get(base::DIR_MODULE, &shell_dir);
+ base::MessageLoop message_loop;
+ scoped_refptr<base::SequencedWorkerPool> blocking_pool(
+ new base::SequencedWorkerPool(3, "blocking_pool"));
+
+ base::Thread io_thread("io_thread");
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ io_thread.StartWithOptions(options);
+
+ ProcessDelegate delegate;
+ mojo::edk::InitIPCSupport(&delegate, io_thread.task_runner());
+
+ NativeRunnerDelegateImpl native_runner_delegate;
+ ChildProcessHost child_process_host(blocking_pool.get(),
+ &native_runner_delegate, false,
+ Identity(), base::FilePath());
+ base::RunLoop run_loop;
+ child_process_host.Start(
+ Identity(),
+ base::Bind(&ProcessReadyCallbackAdapater, run_loop.QuitClosure()),
+ base::Bind(&base::DoNothing));
+ run_loop.Run();
+
+ child_process_host.Join();
+ blocking_pool->Shutdown();
+ mojo::edk::ShutdownIPCSupport();
+ EXPECT_EQ(1u, native_runner_delegate.get_and_clear_adjust_count());
+}
+
+} // namespace
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/host_unittests.cc b/chromium/services/shell/runner/host/host_unittests.cc
new file mode 100644
index 00000000000..37192107ce9
--- /dev/null
+++ b/chromium/services/shell/runner/host/host_unittests.cc
@@ -0,0 +1,36 @@
+// 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 "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "services/shell/runner/common/switches.h"
+#include "services/shell/runner/host/child_process.h"
+#include "services/shell/runner/init.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+int main(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ shell::WaitForDebuggerIfNecessary();
+
+ if (command_line.HasSwitch(switches::kChildProcess)) {
+ base::AtExitManager at_exit;
+
+ return shell::ChildProcessMain();
+ }
+
+ mojo::edk::Init();
+
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/services/shell/runner/host/in_process_native_runner.cc b/chromium/services/shell/runner/host/in_process_native_runner.cc
new file mode 100644
index 00000000000..e18cfa6a2fc
--- /dev/null
+++ b/chromium/services/shell/runner/host/in_process_native_runner.cc
@@ -0,0 +1,95 @@
+// 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 "services/shell/runner/host/in_process_native_runner.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/process/process.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/runner/host/native_application_support.h"
+#include "services/shell/runner/host/out_of_process_native_runner.h"
+#include "services/shell/runner/init.h"
+
+namespace shell {
+
+InProcessNativeRunner::InProcessNativeRunner() : app_library_(nullptr) {}
+
+InProcessNativeRunner::~InProcessNativeRunner() {
+ // It is important to let the thread exit before unloading the DSO (when
+ // app_library_ is destructed), because the library may have registered
+ // thread-local data and destructors to run on thread termination.
+ if (thread_) {
+ DCHECK(thread_->HasBeenStarted());
+ DCHECK(!thread_->HasBeenJoined());
+ thread_->Join();
+ }
+}
+
+mojom::ShellClientPtr InProcessNativeRunner::Start(
+ const base::FilePath& app_path,
+ const Identity& target,
+ bool start_sandboxed,
+ const base::Callback<void(base::ProcessId)>& pid_available_callback,
+ const base::Closure& app_completed_callback) {
+ app_path_ = app_path;
+
+ DCHECK(!request_.is_pending());
+ mojom::ShellClientPtr client;
+ request_ = GetProxy(&client);
+
+ DCHECK(app_completed_callback_runner_.is_null());
+ app_completed_callback_runner_ = base::Bind(
+ &base::TaskRunner::PostTask, base::ThreadTaskRunnerHandle::Get(),
+ FROM_HERE, app_completed_callback);
+
+ DCHECK(!thread_);
+ std::string thread_name = "mojo:app_thread";
+#if defined(OS_WIN)
+ thread_name = base::WideToUTF8(app_path_.BaseName().value());
+#endif
+ thread_.reset(new base::DelegateSimpleThread(this, thread_name));
+ thread_->Start();
+ pid_available_callback.Run(base::Process::Current().Pid());
+
+ return client;
+}
+
+void InProcessNativeRunner::Run() {
+ DVLOG(2) << "Loading/running Mojo app in process from library: "
+ << app_path_.value()
+ << " thread id=" << base::PlatformThread::CurrentId();
+
+ // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
+ base::NativeLibrary app_library = LoadNativeApplication(app_path_);
+ app_library_.Reset(app_library);
+ // This hangs on Windows in the component build, so skip it since it's
+ // unnecessary.
+#if !(defined(COMPONENT_BUILD) && defined(OS_WIN))
+ CallLibraryEarlyInitialization(app_library);
+#endif
+ RunNativeApplication(app_library, std::move(request_));
+ app_completed_callback_runner_.Run();
+ app_completed_callback_runner_.Reset();
+}
+
+std::unique_ptr<NativeRunner> InProcessNativeRunnerFactory::Create(
+ const base::FilePath& app_path) {
+ // Non-Mojo apps are always run in a new process.
+ if (!app_path.MatchesExtension(FILE_PATH_LITERAL(".mojo"))) {
+ return base::WrapUnique(
+ new OutOfProcessNativeRunner(launch_process_runner_, nullptr));
+ }
+ return base::WrapUnique(new InProcessNativeRunner);
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/in_process_native_runner.h b/chromium/services/shell/runner/host/in_process_native_runner.h
new file mode 100644
index 00000000000..8b1af2636b0
--- /dev/null
+++ b/chromium/services/shell/runner/host/in_process_native_runner.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef SERVICES_SHELL_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
+#define SERVICES_SHELL_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/scoped_native_library.h"
+#include "base/threading/simple_thread.h"
+#include "services/shell/native_runner.h"
+#include "services/shell/runner/host/native_application_support.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace shell {
+
+// An implementation of |NativeRunner| that loads/runs the given app (from the
+// file system) on a separate thread (in the current process).
+class InProcessNativeRunner : public NativeRunner,
+ public base::DelegateSimpleThread::Delegate {
+ public:
+ InProcessNativeRunner();
+ ~InProcessNativeRunner() override;
+
+ // NativeRunner:
+ mojom::ShellClientPtr Start(
+ const base::FilePath& app_path,
+ const Identity& target,
+ bool start_sandboxed,
+ const base::Callback<void(base::ProcessId)>& pid_available_callback,
+ const base::Closure& app_completed_callback) override;
+
+ private:
+ // |base::DelegateSimpleThread::Delegate| method:
+ void Run() override;
+
+ base::FilePath app_path_;
+ mojom::ShellClientRequest request_;
+ base::Callback<bool(void)> app_completed_callback_runner_;
+
+ base::ScopedNativeLibrary app_library_;
+ std::unique_ptr<base::DelegateSimpleThread> thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessNativeRunner);
+};
+
+class InProcessNativeRunnerFactory : public NativeRunnerFactory {
+ public:
+ explicit InProcessNativeRunnerFactory(base::TaskRunner* launch_process_runner)
+ : launch_process_runner_(launch_process_runner) {}
+ ~InProcessNativeRunnerFactory() override {}
+
+ std::unique_ptr<NativeRunner> Create(const base::FilePath& app_path) override;
+
+ private:
+ base::TaskRunner* const launch_process_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessNativeRunnerFactory);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
diff --git a/chromium/services/shell/runner/host/in_process_native_runner_unittest.cc b/chromium/services/shell/runner/host/in_process_native_runner_unittest.cc
new file mode 100644
index 00000000000..8f679679497
--- /dev/null
+++ b/chromium/services/shell/runner/host/in_process_native_runner_unittest.cc
@@ -0,0 +1,16 @@
+// 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 "services/shell/runner/host/in_process_native_runner.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace shell {
+
+TEST(InProcessNativeRunnerTest, NotStarted) {
+ InProcessNativeRunner runner;
+ // Shouldn't crash or DCHECK on destruction.
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/linux_sandbox.cc b/chromium/services/shell/runner/host/linux_sandbox.cc
new file mode 100644
index 00000000000..24461a5a645
--- /dev/null
+++ b/chromium/services/shell/runner/host/linux_sandbox.cc
@@ -0,0 +1,167 @@
+// 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 "services/shell/runner/host/linux_sandbox.h"
+
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_sandbox.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/thread_helpers.h"
+
+using sandbox::syscall_broker::BrokerFilePermission;
+
+namespace shell {
+
+namespace {
+
+intptr_t SandboxSIGSYSHandler(const struct sandbox::arch_seccomp_data& args,
+ void* aux) {
+ RAW_CHECK(aux);
+ const sandbox::syscall_broker::BrokerProcess* broker_process =
+ static_cast<const sandbox::syscall_broker::BrokerProcess*>(aux);
+ switch (args.nr) {
+ case __NR_access:
+ return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
+ static_cast<int>(args.args[1]));
+ case __NR_open:
+ return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
+ static_cast<int>(args.args[1]));
+ case __NR_faccessat:
+ if (static_cast<int>(args.args[0]) == AT_FDCWD) {
+ return broker_process->Access(
+ reinterpret_cast<const char*>(args.args[1]),
+ static_cast<int>(args.args[2]));
+ } else {
+ return -EPERM;
+ }
+ case __NR_openat:
+ // Allow using openat() as open().
+ if (static_cast<int>(args.args[0]) == AT_FDCWD) {
+ return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
+ static_cast<int>(args.args[2]));
+ } else {
+ return -EPERM;
+ }
+ default:
+ RAW_CHECK(false);
+ return -ENOSYS;
+ }
+}
+
+class SandboxPolicy : public sandbox::BaselinePolicy {
+ public:
+ explicit SandboxPolicy(sandbox::syscall_broker::BrokerProcess* broker_process)
+ : broker_process_(broker_process) {}
+ ~SandboxPolicy() override {}
+
+ // Overridden from sandbox::bpf_dsl::Policy:
+ sandbox::bpf_dsl::ResultExpr EvaluateSyscall(int sysno) const override {
+ // This policy is only advisory/for noticing FS access for the moment.
+ switch (sysno) {
+#if !defined(__aarch64__)
+ case __NR_access:
+ case __NR_open:
+#endif
+ case __NR_faccessat:
+ case __NR_openat:
+ return sandbox::bpf_dsl::Trap(SandboxSIGSYSHandler, broker_process_);
+ case __NR_sched_getaffinity:
+ return sandbox::RestrictSchedTarget(policy_pid(), sysno);
+ case __NR_ftruncate:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+ defined(__aarch64__)
+ // Per #ifdefs in
+ // content/common/sandbox_linux/bpf_renderer_policy_linux.cc
+ case __NR_getrlimit:
+#endif
+#if defined(__i386__) || defined(__arm__)
+ case __NR_ugetrlimit:
+#endif
+ case __NR_uname:
+#if defined(__arm__) || defined(__x86_64__) || defined(__mips__)
+ case __NR_getsockopt:
+ case __NR_setsockopt:
+#endif
+ return sandbox::bpf_dsl::Allow();
+ }
+
+ return BaselinePolicy::EvaluateSyscall(sysno);
+ }
+
+ private:
+ // Not owned.
+ const sandbox::syscall_broker::BrokerProcess* broker_process_;
+ DISALLOW_COPY_AND_ASSIGN(SandboxPolicy);
+};
+
+} // namespace
+
+LinuxSandbox::LinuxSandbox(const std::vector<BrokerFilePermission>& permissions)
+ : broker_(new sandbox::syscall_broker::BrokerProcess(EPERM, permissions)) {
+ CHECK(broker_->Init(
+ base::Bind<bool (*)()>(&sandbox::Credentials::DropAllCapabilities)));
+ policy_.reset(new SandboxPolicy(broker_.get()));
+}
+
+LinuxSandbox::~LinuxSandbox() {}
+
+void LinuxSandbox::Warmup() {
+ proc_fd_ = sandbox::ProcUtil::OpenProc();
+ warmed_up_ = true;
+
+ // Verify that we haven't started threads or grabbed directory file
+ // descriptors.
+ sandbox::ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
+ CHECK(!sandbox::ProcUtil::HasOpenDirectory(proc_fd_.get()));
+}
+
+void LinuxSandbox::EngageNamespaceSandbox() {
+ CHECK(warmed_up_);
+ CHECK_EQ(1, getpid());
+ CHECK(sandbox::NamespaceSandbox::InNewPidNamespace());
+ CHECK(sandbox::Credentials::MoveToNewUserNS());
+ CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_.get()));
+ CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd_.get()));
+}
+
+void LinuxSandbox::EngageSeccompSandbox() {
+ CHECK(warmed_up_);
+ sandbox::SandboxBPF sandbox(policy_.release());
+ base::ScopedFD proc_fd(HANDLE_EINTR(
+ openat(proc_fd_.get(), ".", O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
+ CHECK(proc_fd.is_valid());
+ sandbox.SetProcFd(std::move(proc_fd));
+ CHECK(
+ sandbox.StartSandbox(sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED))
+ << "Starting the process with a sandbox failed. Missing kernel support.";
+
+ // The Broker is now bound to this process and should only be destroyed when
+ // the process exits or is killed.
+ sandbox::syscall_broker::BrokerProcess* leaked_broker = broker_.release();
+ ALLOW_UNUSED_LOCAL(leaked_broker);
+ ANNOTATE_LEAKING_OBJECT_PTR(leaked_broker);
+}
+
+void LinuxSandbox::Seal() {
+ proc_fd_.reset();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/linux_sandbox.h b/chromium/services/shell/runner/host/linux_sandbox.h
new file mode 100644
index 00000000000..bd1880a54c5
--- /dev/null
+++ b/chromium/services/shell/runner/host/linux_sandbox.h
@@ -0,0 +1,51 @@
+// 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 SERVICES_SHELL_RUNNER_HOST_LINUX_SANDBOX_H_
+#define SERVICES_SHELL_RUNNER_HOST_LINUX_SANDBOX_H_
+
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/syscall_broker/broker_process.h"
+
+namespace shell {
+
+// Encapsulates all tasks related to raising the sandbox for mojo runner.
+class LinuxSandbox {
+ public:
+ explicit LinuxSandbox(
+ const std::vector<sandbox::syscall_broker::BrokerFilePermission>&
+ permissions);
+ ~LinuxSandbox();
+
+ // Grabs a file descriptor to /proc.
+ void Warmup();
+
+ // Puts the user in a new PID namespace.
+ void EngageNamespaceSandbox();
+
+ // Starts a broker process and sets up seccomp-bpf to delegate decisions to
+ // it.
+ void EngageSeccompSandbox();
+
+ // Performs the dropping of access to the outside world (drops the reference
+ // to /proc acquired in Warmup().
+ void Seal();
+
+ private:
+ bool warmed_up_;
+ base::ScopedFD proc_fd_;
+ std::unique_ptr<sandbox::syscall_broker::BrokerProcess> broker_;
+ std::unique_ptr<sandbox::bpf_dsl::Policy> policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(LinuxSandbox);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_LINUX_SANDBOX_H_
diff --git a/chromium/services/shell/runner/host/mach_broker.cc b/chromium/services/shell/runner/host/mach_broker.cc
new file mode 100644
index 00000000000..7f1cd45fa0d
--- /dev/null
+++ b/chromium/services/shell/runner/host/mach_broker.cc
@@ -0,0 +1,43 @@
+// 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 "services/shell/runner/host/mach_broker.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+
+namespace shell {
+
+namespace {
+const char kBootstrapPortName[] = "mojo_shell";
+}
+
+// static
+void MachBroker::SendTaskPortToParent() {
+ bool result = base::MachPortBroker::ChildSendTaskPortToParent(
+ kBootstrapPortName);
+ DCHECK(result);
+}
+
+// static
+MachBroker* MachBroker::GetInstance() {
+ return base::Singleton<MachBroker>::get();
+}
+
+MachBroker::MachBroker() : broker_(kBootstrapPortName) {
+ bool result = broker_.Init();
+ DCHECK(result);
+}
+
+MachBroker::~MachBroker() {}
+
+void MachBroker::ExpectPid(base::ProcessHandle pid) {
+ broker_.AddPlaceholderForPid(pid);
+}
+
+void MachBroker::RemovePid(base::ProcessHandle pid) {
+ broker_.InvalidatePid(pid);
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/mach_broker.h b/chromium/services/shell/runner/host/mach_broker.h
new file mode 100644
index 00000000000..64fa63a6cc7
--- /dev/null
+++ b/chromium/services/shell/runner/host/mach_broker.h
@@ -0,0 +1,52 @@
+// 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 SERVICES_SHELL_RUNNER_HOST_MACH_BROKER_H_
+#define SERVICES_SHELL_RUNNER_HOST_MACH_BROKER_H_
+
+#include "base/mac/mach_port_broker.h"
+
+namespace base {
+template <typename T> struct DefaultSingletonTraits;
+}
+
+namespace shell {
+
+// A global singleton |MachBroker| is used by the shell to provide access to
+// Mach task ports for shell out-of-process applications.
+class MachBroker {
+ public:
+ // Sends the task port of the current process to the parent over Mach IPC.
+ // For use in child processes.
+ static void SendTaskPortToParent();
+
+ // Returns the global |MachBroker|. For use in the shell.
+ static MachBroker* GetInstance();
+
+ // Registers |pid| with a MACH_PORT_NULL task port in the port provider. A
+ // child's pid must be registered before the broker will accept a task port
+ // from that child.
+ // Callers MUST acquire the lock given by GetLock() before calling this method
+ // (and release the lock afterwards).
+ void ExpectPid(base::ProcessHandle pid);
+
+ // Removes |pid| from the port provider.
+ // Callers MUST acquire the lock given by GetLock() before calling this method
+ // (and release the lock afterwards).
+ void RemovePid(base::ProcessHandle pid);
+
+ base::Lock& GetLock() { return broker_.GetLock(); }
+ base::PortProvider* port_provider() { return &broker_; }
+
+ private:
+ MachBroker();
+ ~MachBroker();
+ friend struct base::DefaultSingletonTraits<MachBroker>;
+
+ base::MachPortBroker broker_;
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_MACH_BROKER_H_
diff --git a/chromium/services/shell/runner/host/native_application_support.cc b/chromium/services/shell/runner/host/native_application_support.cc
new file mode 100644
index 00000000000..cb213748cf9
--- /dev/null
+++ b/chromium/services/shell/runner/host/native_application_support.cc
@@ -0,0 +1,106 @@
+// 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 "services/shell/runner/host/native_application_support.h"
+
+#include <stddef.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "mojo/platform_handle/platform_handle_private_thunks.h"
+#include "mojo/public/platform/native/system_thunks.h"
+
+namespace shell {
+
+namespace {
+
+template <typename Thunks>
+bool SetThunks(Thunks (*make_thunks)(),
+ const char* function_name,
+ base::NativeLibrary library) {
+ typedef size_t (*SetThunksFn)(const Thunks* thunks);
+ SetThunksFn set_thunks = reinterpret_cast<SetThunksFn>(
+ base::GetFunctionPointerFromNativeLibrary(library, function_name));
+ if (!set_thunks)
+ return false;
+ Thunks thunks = make_thunks();
+ size_t expected_size = set_thunks(&thunks);
+ if (expected_size > sizeof(Thunks)) {
+ LOG(ERROR) << "Invalid app library: expected " << function_name
+ << " to return thunks of size: " << expected_size;
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+base::NativeLibrary LoadNativeApplication(const base::FilePath& app_path) {
+ DVLOG(2) << "Loading Mojo app in process from library: " << app_path.value();
+
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary app_library = base::LoadNativeLibrary(app_path, &error);
+ LOG_IF(ERROR, !app_library)
+ << "Failed to load app library (path: " << app_path.value() << ")";
+ return app_library;
+}
+
+bool RunNativeApplication(base::NativeLibrary app_library,
+ mojom::ShellClientRequest request) {
+ // Tolerate |app_library| being null, to make life easier for callers.
+ if (!app_library)
+ return false;
+
+// Thunks aren't needed/used in component build, since the thunked methods
+// just live in their own dynamically loaded library.
+#if !defined(COMPONENT_BUILD)
+ if (!SetThunks(&MojoMakeSystemThunks, "MojoSetSystemThunks", app_library)) {
+ LOG(ERROR) << "MojoSetSystemThunks not found";
+ return false;
+ }
+
+#if !defined(OS_WIN)
+ // On Windows, initializing base::CommandLine with null parameters gets the
+ // process's command line from the OS. Other platforms need it to be passed
+ // in. This needs to be passed in before the app initializes the command line,
+ // which is done as soon as it loads.
+ typedef void (*InitCommandLineArgs)(int, const char* const*);
+ InitCommandLineArgs init_command_line_args =
+ reinterpret_cast<InitCommandLineArgs>(
+ base::GetFunctionPointerFromNativeLibrary(app_library,
+ "InitCommandLineArgs"));
+ if (init_command_line_args) {
+ int argc = 0;
+ base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+ const char** argv = new const char*[cmd_line->argv().size()];
+ for (auto& arg : cmd_line->argv())
+ argv[argc++] = arg.c_str();
+ init_command_line_args(argc, argv);
+ }
+#endif
+
+ // Apps need not include platform handle thunks.
+ SetThunks(&MojoMakePlatformHandlePrivateThunks,
+ "MojoSetPlatformHandlePrivateThunks", app_library);
+#endif
+
+ typedef MojoResult (*MojoMainFunction)(MojoHandle);
+ MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
+ base::GetFunctionPointerFromNativeLibrary(app_library, "MojoMain"));
+ if (!main_function) {
+ LOG(ERROR) << "MojoMain not found";
+ return false;
+ }
+ // |MojoMain()| takes ownership of the service handle.
+ MojoHandle handle = request.PassMessagePipe().release().value();
+ MojoResult result = main_function(handle);
+ if (result != MOJO_RESULT_OK) {
+ LOG(ERROR) << "MojoMain returned error (result: " << result << ")";
+ }
+ return true;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/native_application_support.h b/chromium/services/shell/runner/host/native_application_support.h
new file mode 100644
index 00000000000..2f8df6997bc
--- /dev/null
+++ b/chromium/services/shell/runner/host/native_application_support.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef SERVICES_SHELL_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
+#define SERVICES_SHELL_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
+
+#include "base/native_library.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace shell {
+
+// Loads the native Mojo application from the DSO specified by |app_path|.
+// Returns the |base::NativeLibrary| for the application on success (or null on
+// failure).
+//
+// Note: The caller may choose to eventually unload the returned DSO. If so,
+// this should be done only after the thread on which |LoadNativeApplication()|
+// and |RunNativeApplication()| were called has terminated, so that any
+// thread-local destructors have been executed.
+base::NativeLibrary LoadNativeApplication(const base::FilePath& app_path);
+
+// Runs the native Mojo application from the DSO that was loaded using
+// |LoadNativeApplication()|; this tolerates |app_library| being null. This
+// should be called on the same thread as |LoadNativeApplication()|. Returns
+// true if |MojoMain()| was called (even if it returns an error), and false
+// otherwise.
+bool RunNativeApplication(base::NativeLibrary app_library,
+ mojom::ShellClientRequest request);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
diff --git a/chromium/services/shell/runner/host/out_of_process_native_runner.cc b/chromium/services/shell/runner/host/out_of_process_native_runner.cc
new file mode 100644
index 00000000000..eeeb234256b
--- /dev/null
+++ b/chromium/services/shell/runner/host/out_of_process_native_runner.cc
@@ -0,0 +1,75 @@
+// 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 "services/shell/runner/host/out_of_process_native_runner.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/task_runner.h"
+#include "services/shell/runner/common/client_util.h"
+#include "services/shell/runner/host/child_process_host.h"
+#include "services/shell/runner/host/in_process_native_runner.h"
+
+namespace shell {
+
+OutOfProcessNativeRunner::OutOfProcessNativeRunner(
+ base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate)
+ : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
+
+OutOfProcessNativeRunner::~OutOfProcessNativeRunner() {
+ if (child_process_host_ && !app_path_.empty())
+ child_process_host_->Join();
+}
+
+mojom::ShellClientPtr OutOfProcessNativeRunner::Start(
+ const base::FilePath& app_path,
+ const Identity& target,
+ bool start_sandboxed,
+ const base::Callback<void(base::ProcessId)>& pid_available_callback,
+ const base::Closure& app_completed_callback) {
+ app_path_ = app_path;
+
+ DCHECK(app_completed_callback_.is_null());
+ app_completed_callback_ = app_completed_callback;
+
+ child_process_host_.reset(new ChildProcessHost(
+ launch_process_runner_, delegate_, start_sandboxed, target, app_path));
+ return child_process_host_->Start(
+ target, pid_available_callback,
+ base::Bind(&OutOfProcessNativeRunner::AppCompleted,
+ base::Unretained(this)));
+}
+
+void OutOfProcessNativeRunner::AppCompleted() {
+ if (child_process_host_)
+ child_process_host_->Join();
+ child_process_host_.reset();
+ // This object may be deleted by this callback.
+ base::Closure app_completed_callback = app_completed_callback_;
+ app_completed_callback_.Reset();
+ if (!app_completed_callback.is_null())
+ app_completed_callback.Run();
+}
+
+OutOfProcessNativeRunnerFactory::OutOfProcessNativeRunnerFactory(
+ base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate)
+ : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
+OutOfProcessNativeRunnerFactory::~OutOfProcessNativeRunnerFactory() {}
+
+std::unique_ptr<NativeRunner> OutOfProcessNativeRunnerFactory::Create(
+ const base::FilePath& app_path) {
+ return base::WrapUnique(
+ new OutOfProcessNativeRunner(launch_process_runner_, delegate_));
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/host/out_of_process_native_runner.h b/chromium/services/shell/runner/host/out_of_process_native_runner.h
new file mode 100644
index 00000000000..d141c90e0c3
--- /dev/null
+++ b/chromium/services/shell/runner/host/out_of_process_native_runner.h
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef SERVICES_SHELL_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
+#define SERVICES_SHELL_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "services/shell/native_runner.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace shell {
+
+class ChildProcessHost;
+class NativeRunnerDelegate;
+
+// An implementation of |NativeRunner| that loads/runs the given app (from the
+// file system) in a separate process (of its own).
+class OutOfProcessNativeRunner : public NativeRunner {
+ public:
+ OutOfProcessNativeRunner(base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate);
+ ~OutOfProcessNativeRunner() override;
+
+ // NativeRunner:
+ mojom::ShellClientPtr Start(
+ const base::FilePath& app_path,
+ const Identity& identity,
+ bool start_sandboxed,
+ const base::Callback<void(base::ProcessId)>& pid_available_callback,
+ const base::Closure& app_completed_callback) override;
+
+ private:
+ void AppCompleted();
+
+ base::TaskRunner* const launch_process_runner_;
+ NativeRunnerDelegate* delegate_;
+
+ base::FilePath app_path_;
+ base::Closure app_completed_callback_;
+
+ std::unique_ptr<ChildProcessHost> child_process_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(OutOfProcessNativeRunner);
+};
+
+class OutOfProcessNativeRunnerFactory : public NativeRunnerFactory {
+ public:
+ OutOfProcessNativeRunnerFactory(base::TaskRunner* launch_process_runner,
+ NativeRunnerDelegate* delegate);
+ ~OutOfProcessNativeRunnerFactory() override;
+
+ std::unique_ptr<NativeRunner> Create(const base::FilePath& app_path) override;
+
+ private:
+ base::TaskRunner* const launch_process_runner_;
+ NativeRunnerDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(OutOfProcessNativeRunnerFactory);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
diff --git a/chromium/services/shell/runner/init.cc b/chromium/services/shell/runner/init.cc
new file mode 100644
index 00000000000..8d095f0f2fc
--- /dev/null
+++ b/chromium/services/shell/runner/init.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 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 "services/shell/runner/init.h"
+
+#include <stdint.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "services/shell/runner/common/switches.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif (OS_POSIX)
+#include <unistd.h>
+#endif
+
+namespace shell {
+
+void InitializeLogging() {
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+ logging::InitLogging(settings);
+ // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+ logging::SetLogItems(true, // Process ID
+ true, // Thread ID
+ true, // Timestamp
+ true); // Tick count
+}
+
+void WaitForDebuggerIfNecessary() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kWaitForDebugger)) {
+ std::vector<std::string> apps_to_debug = base::SplitString(
+ command_line->GetSwitchValueASCII(switches::kWaitForDebugger), ",",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ std::string app = "launcher";
+ if (command_line->HasSwitch(switches::kChildProcess)) {
+ app = command_line->GetSwitchValuePath(switches::kChildProcess)
+ .BaseName()
+ .RemoveExtension()
+ .MaybeAsASCII();
+ } else {
+ base::FilePath exe_path =
+ command_line->GetProgram().BaseName().RemoveExtension();
+ for (const auto& app_name : apps_to_debug) {
+ if (base::FilePath().AppendASCII(app_name) == exe_path) {
+ app = app_name;
+ break;
+ }
+ }
+ }
+ if (apps_to_debug.empty() || ContainsValue(apps_to_debug, app)) {
+#if defined(OS_WIN)
+ base::string16 appw = base::UTF8ToUTF16(app);
+ base::string16 message = base::UTF8ToUTF16(
+ base::StringPrintf("%s - %d", app.c_str(), GetCurrentProcessId()));
+ MessageBox(NULL, message.c_str(), appw.c_str(), MB_OK | MB_SETFOREGROUND);
+#else
+ LOG(ERROR) << app << " waiting for GDB. pid: " << getpid();
+ base::debug::WaitForDebugger(60, true);
+#endif
+ }
+ }
+}
+
+void CallLibraryEarlyInitialization(base::NativeLibrary app_library) {
+ // Do whatever warming that the mojo application wants.
+
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+ typedef void (*LibraryEarlyInitFunction)(const uint8_t*);
+ LibraryEarlyInitFunction init_function =
+ reinterpret_cast<LibraryEarlyInitFunction>(
+ base::GetFunctionPointerFromNativeLibrary(app_library,
+ "InitializeBase"));
+ if (init_function) {
+ // Get the ICU data that we prewarmed in the runner and then pass it to
+ // the copy of icu in the mojo binary that we're running.
+ const uint8_t* icu_data = base::i18n::GetRawIcuMemory();
+ init_function(icu_data);
+ }
+#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+
+ // TODO(erg): All chromium binaries load base. We might want to make a
+ // general system for other people.
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/runner/init.h b/chromium/services/shell/runner/init.h
new file mode 100644
index 00000000000..dced60d61c1
--- /dev/null
+++ b/chromium/services/shell/runner/init.h
@@ -0,0 +1,23 @@
+// Copyright 2013 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 SERVICES_SHELL_RUNNER_INIT_H_
+#define SERVICES_SHELL_RUNNER_INIT_H_
+
+#include "base/native_library.h"
+
+namespace shell {
+
+// Initialization routines shared by desktop and Android main functions.
+void InitializeLogging();
+
+void WaitForDebuggerIfNecessary();
+
+// Calls "LibraryEarlyInitialization" in |app_library| if it exists. We do
+// common initialization there now.
+void CallLibraryEarlyInitialization(base::NativeLibrary app_library);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_RUNNER_INIT_H_
diff --git a/chromium/services/shell/shell.cc b/chromium/services/shell/shell.cc
new file mode 100644
index 00000000000..c5aa2bdb798
--- /dev/null
+++ b/chromium/services/shell/shell.cc
@@ -0,0 +1,792 @@
+// 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 "services/shell/shell.h"
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/shell/connect_util.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/cpp/names.h"
+#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/shell.mojom.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace shell {
+
+namespace {
+
+const char kCatalogName[] = "mojo:catalog";
+const char kShellName[] = "mojo:shell";
+const char kCapabilityClass_UserID[] = "shell:user_id";
+const char kCapabilityClass_ClientProcess[] = "shell:client_process";
+const char kCapabilityClass_InstanceName[] = "shell:instance_name";
+const char kCapabilityClass_AllUsers[] = "shell:all_users";
+const char kCapabilityClass_ExplicitClass[] = "shell:explicit_class";
+
+} // namespace
+
+Identity CreateShellIdentity() {
+ return Identity(kShellName, mojom::kRootUserID);
+}
+
+Identity CreateCatalogIdentity() {
+ return Identity(kCatalogName, mojom::kRootUserID);
+}
+
+CapabilitySpec GetPermissiveCapabilities() {
+ CapabilitySpec capabilities;
+ CapabilityRequest spec;
+ spec.interfaces.insert("*");
+ capabilities.required["*"] = spec;
+ return capabilities;
+}
+
+CapabilityRequest GetCapabilityRequest(const CapabilitySpec& source_spec,
+ const Identity& target) {
+ CapabilityRequest request;
+
+ // Start by looking for specs specific to the supplied identity.
+ auto it = source_spec.required.find(target.name());
+ if (it != source_spec.required.end()) {
+ std::copy(it->second.classes.begin(), it->second.classes.end(),
+ std::inserter(request.classes, request.classes.begin()));
+ std::copy(it->second.interfaces.begin(), it->second.interfaces.end(),
+ std::inserter(request.interfaces, request.interfaces.begin()));
+ }
+
+ // Apply wild card rules too.
+ it = source_spec.required.find("*");
+ if (it != source_spec.required.end()) {
+ std::copy(it->second.classes.begin(), it->second.classes.end(),
+ std::inserter(request.classes, request.classes.begin()));
+ std::copy(it->second.interfaces.begin(), it->second.interfaces.end(),
+ std::inserter(request.interfaces, request.interfaces.begin()));
+ }
+ return request;
+}
+
+CapabilityRequest GenerateCapabilityRequestForConnection(
+ const CapabilitySpec& source_spec,
+ const Identity& target,
+ const CapabilitySpec& target_spec) {
+ CapabilityRequest request = GetCapabilityRequest(source_spec, target);
+ // Flatten all interfaces from classes requested by the source into the
+ // allowed interface set in the request.
+ for (const auto& class_name : request.classes) {
+ auto it = target_spec.provided.find(class_name);
+ if (it != target_spec.provided.end()) {
+ for (const auto& interface_name : it->second)
+ request.interfaces.insert(interface_name);
+ }
+ }
+ return request;
+}
+
+bool HasClass(const CapabilitySpec& spec, const std::string& class_name) {
+ auto it = spec.required.find(kShellName);
+ if (it == spec.required.end())
+ return false;
+ return it->second.classes.find(class_name) != it->second.classes.end();
+}
+
+// Encapsulates a connection to an instance of an application, tracked by the
+// shell's Shell.
+class Shell::Instance : public mojom::Connector,
+ public mojom::PIDReceiver,
+ public ShellClient,
+ public InterfaceFactory<mojom::Shell>,
+ public mojom::Shell {
+ public:
+ Instance(shell::Shell* shell,
+ const Identity& identity,
+ const CapabilitySpec& capability_spec)
+ : shell_(shell),
+ id_(GenerateUniqueID()),
+ identity_(identity),
+ capability_spec_(capability_spec),
+ allow_any_application_(capability_spec.required.count("*") == 1),
+ pid_receiver_binding_(this),
+ weak_factory_(this) {
+ if (identity_.name() == kShellName || identity_.name() == kCatalogName)
+ pid_ = base::Process::Current().Pid();
+ DCHECK_NE(mojom::kInvalidInstanceID, id_);
+ }
+
+ ~Instance() override {
+ if (parent_)
+ parent_->RemoveChild(this);
+ // |children_| will be modified during destruction.
+ std::set<Instance*> children = children_;
+ for (auto child : children)
+ shell_->OnInstanceError(child);
+
+ // Shutdown all bindings before we close the runner. This way the process
+ // should see the pipes closed and exit, as well as waking up any potential
+ // sync/WaitForIncomingResponse().
+ shell_client_.reset();
+ if (pid_receiver_binding_.is_bound())
+ pid_receiver_binding_.Close();
+ connectors_.CloseAllBindings();
+ shell_bindings_.CloseAllBindings();
+ // Release |runner_| so that if we are called back to OnRunnerCompleted()
+ // we know we're in the destructor.
+ std::unique_ptr<NativeRunner> runner = std::move(runner_);
+ runner.reset();
+ }
+
+ Instance* parent() { return parent_; }
+
+ void AddChild(Instance* child) {
+ children_.insert(child);
+ child->parent_ = this;
+ }
+
+ void RemoveChild(Instance* child) {
+ auto it = children_.find(child);
+ DCHECK(it != children_.end());
+ children_.erase(it);
+ child->parent_ = nullptr;
+ }
+
+ void ConnectToClient(std::unique_ptr<ConnectParams> params) {
+ CHECK(shell_client_.is_bound());
+ params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED,
+ identity_.user_id(), id_);
+ uint32_t source_id = mojom::kInvalidInstanceID;
+ CapabilityRequest request;
+ request.interfaces.insert("*");
+ Instance* source = shell_->GetExistingInstance(params->source());
+ if (source) {
+ request = GenerateCapabilityRequestForConnection(
+ source->capability_spec_, identity_, capability_spec_);
+ source_id = source->id();
+ }
+
+ // The target has specified that sources must request one of its provided
+ // classes instead of specifying a wild-card for interfaces.
+ if (HasClass(capability_spec_, kCapabilityClass_ExplicitClass) &&
+ (request.interfaces.count("*") != 0)) {
+ request.interfaces.erase("*");
+ }
+
+ shell_client_->AcceptConnection(
+ mojom::Identity::From(params->source()), source_id,
+ params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(),
+ mojom::CapabilityRequest::From(request), params->target().name());
+ }
+
+ void StartWithClient(mojom::ShellClientPtr client) {
+ CHECK(!shell_client_);
+ shell_client_ = std::move(client);
+ shell_client_.set_connection_error_handler(
+ base::Bind(&Instance::OnShellClientLost, base::Unretained(this),
+ shell_->GetWeakPtr()));
+ shell_client_->Initialize(mojom::Identity::From(identity_), id_,
+ base::Bind(&Instance::OnInitializeResponse,
+ base::Unretained(this)));
+ }
+
+ void StartWithClientProcessConnection(
+ mojom::ClientProcessConnectionPtr client_process_connection) {
+ mojom::ShellClientPtr client;
+ client.Bind(mojom::ShellClientPtrInfo(
+ std::move(client_process_connection->shell_client), 0));
+ pid_receiver_binding_.Bind(
+ std::move(client_process_connection->pid_receiver_request));
+ StartWithClient(std::move(client));
+ }
+
+ void StartWithFilePath(const base::FilePath& path) {
+ CHECK(!shell_client_);
+ runner_ = shell_->native_runner_factory_->Create(path);
+ bool start_sandboxed = false;
+ mojom::ShellClientPtr client = runner_->Start(
+ path, identity_, start_sandboxed,
+ base::Bind(&Instance::PIDAvailable, weak_factory_.GetWeakPtr()),
+ base::Bind(&Instance::OnRunnerCompleted, weak_factory_.GetWeakPtr()));
+ StartWithClient(std::move(client));
+ }
+
+ mojom::InstanceInfoPtr CreateInstanceInfo() const {
+ mojom::InstanceInfoPtr info(mojom::InstanceInfo::New());
+ info->id = id_;
+ info->identity = mojom::Identity::From(identity_);
+ info->pid = pid_;
+ return info;
+ }
+
+ const CapabilitySpec& capability_spec() const {
+ return capability_spec_;
+ }
+ const Identity& identity() const { return identity_; }
+ uint32_t id() const { return id_; }
+
+ // ShellClient:
+ bool AcceptConnection(Connection* connection) override {
+ connection->AddInterface<mojom::Shell>(this);
+ return true;
+ }
+
+ private:
+ // mojom::Connector implementation:
+ void Connect(mojom::IdentityPtr target_ptr,
+ mojom::InterfaceProviderRequest remote_interfaces,
+ mojom::InterfaceProviderPtr local_interfaces,
+ mojom::ClientProcessConnectionPtr client_process_connection,
+ const ConnectCallback& callback) override {
+ Identity target = target_ptr.To<Identity>();
+ if (target.user_id() == mojom::kInheritUserID)
+ target.set_user_id(identity_.user_id());
+
+ if (!ValidateIdentity(target, callback))
+ return;
+ if (!ValidateClientProcessConnection(&client_process_connection, target,
+ callback)) {
+ return;
+ }
+ if (!ValidateCapabilities(target, callback))
+ return;
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(identity_);
+ params->set_target(target);
+ params->set_remote_interfaces(std::move(remote_interfaces));
+ params->set_local_interfaces(std::move(local_interfaces));
+ params->set_client_process_connection(std::move(client_process_connection));
+ params->set_connect_callback(callback);
+ shell_->Connect(std::move(params));
+ }
+
+ void Clone(mojom::ConnectorRequest request) override {
+ connectors_.AddBinding(this, std::move(request));
+ }
+
+ // mojom::PIDReceiver:
+ void SetPID(uint32_t pid) override {
+ PIDAvailable(pid);
+ }
+
+ // InterfaceFactory<mojom::Shell>:
+ void Create(Connection* connection,
+ mojom::ShellRequest request) override {
+ shell_bindings_.AddBinding(this, std::move(request));
+ }
+
+ // mojom::Shell implementation:
+ void AddInstanceListener(mojom::InstanceListenerPtr listener) override {
+ // TODO(beng): this should only track the instances matching this user, and
+ // root.
+ shell_->AddInstanceListener(std::move(listener));
+ }
+
+ bool ValidateIdentity(const Identity& identity,
+ const ConnectCallback& callback) {
+ if (!IsValidName(identity.name())) {
+ LOG(ERROR) << "Error: invalid Name: " << identity.name();
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+ if (!base::IsValidGUID(identity.user_id())) {
+ LOG(ERROR) << "Error: invalid user_id: " << identity.user_id();
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+ return true;
+ }
+
+ bool ValidateClientProcessConnection(
+ mojom::ClientProcessConnectionPtr* client_process_connection,
+ const Identity& target,
+ const ConnectCallback& callback) {
+ if (!client_process_connection->is_null()) {
+ if (!HasClass(capability_spec_, kCapabilityClass_ClientProcess)) {
+ LOG(ERROR) << "Instance: " << identity_.name() << " attempting "
+ << "to register an instance for a process it created for "
+ << "target: " << target.name() << " without the "
+ << "mojo:shell{client_process} capability class.";
+ callback.Run(mojom::ConnectResult::ACCESS_DENIED,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+
+ if (!(*client_process_connection)->shell_client.is_valid() ||
+ !(*client_process_connection)->pid_receiver_request.is_valid()) {
+ LOG(ERROR) << "Must supply both shell_client AND "
+ << "pid_receiver_request when sending "
+ << "client_process_connection.";
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+ if (shell_->GetExistingInstance(target)) {
+ LOG(ERROR) << "Cannot client process matching existing identity:"
+ << "Name: " << target.name() << " User: "
+ << target.user_id() << " Instance: " << target.instance();
+ callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool ValidateCapabilities(const Identity& target,
+ const ConnectCallback& callback) {
+ // TODO(beng): Need to do the following additional policy validation of
+ // whether this instance is allowed to connect using:
+ // - a non-null client_process_connection.
+ if (target.user_id() != identity_.user_id() &&
+ target.user_id() != mojom::kRootUserID &&
+ !HasClass(capability_spec_, kCapabilityClass_UserID)) {
+ LOG(ERROR) << "Instance: " << identity_.name() << " running as: "
+ << identity_.user_id() << " attempting to connect to: "
+ << target.name() << " as: " << target.user_id() << " without "
+ << " the mojo:shell{user_id} capability class.";
+ callback.Run(mojom::ConnectResult::ACCESS_DENIED,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+ if (!target.instance().empty() &&
+ target.instance() != GetNamePath(target.name()) &&
+ !HasClass(capability_spec_, kCapabilityClass_InstanceName)) {
+ LOG(ERROR) << "Instance: " << identity_.name() << " attempting to "
+ << "connect to " << target.name() << " using Instance name: "
+ << target.instance() << " without the "
+ << "mojo:shell{instance_name} capability class.";
+ callback.Run(mojom::ConnectResult::ACCESS_DENIED,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+
+ }
+
+ if (allow_any_application_ ||
+ capability_spec_.required.find(target.name()) !=
+ capability_spec_.required.end()) {
+ return true;
+ }
+ LOG(ERROR) << "Capabilities prevented connection from: " <<
+ identity_.name() << " to: " << target.name();
+ callback.Run(mojom::ConnectResult::ACCESS_DENIED,
+ mojom::kInheritUserID, mojom::kInvalidInstanceID);
+ return false;
+ }
+
+ uint32_t GenerateUniqueID() const {
+ static uint32_t id = mojom::kInvalidInstanceID;
+ ++id;
+ CHECK_NE(mojom::kInvalidInstanceID, id);
+ return id;
+ }
+
+ void PIDAvailable(base::ProcessId pid) {
+ if (pid == base::kNullProcessId) {
+ shell_->OnInstanceError(this);
+ return;
+ }
+ pid_ = pid;
+ shell_->NotifyPIDAvailable(id_, pid_);
+ }
+
+ void OnShellClientLost(base::WeakPtr<shell::Shell> shell) {
+ shell_client_.reset();
+ OnConnectionLost(shell);
+ }
+
+ void OnConnectionLost(base::WeakPtr<shell::Shell> shell) {
+ // Any time a Connector is lost or we lose the ShellClient connection, it
+ // may have been the last pipe using this Instance. If so, clean up.
+ if (shell && connectors_.empty() && !shell_client_) {
+ // Deletes |this|.
+ shell->OnInstanceError(this);
+ }
+ }
+
+ void OnInitializeResponse(mojom::ConnectorRequest connector_request) {
+ if (connector_request.is_pending()) {
+ connectors_.AddBinding(this, std::move(connector_request));
+ connectors_.set_connection_error_handler(
+ base::Bind(&Instance::OnConnectionLost, base::Unretained(this),
+ shell_->GetWeakPtr()));
+ }
+ }
+
+ // Callback when NativeRunner completes.
+ void OnRunnerCompleted() {
+ if (!runner_.get())
+ return; // We're in the destructor.
+
+ shell_->OnInstanceError(this);
+ }
+
+ shell::Shell* const shell_;
+
+ // An id that identifies this instance. Distinct from pid, as a single process
+ // may vend multiple application instances, and this object may exist before a
+ // process is launched.
+ const uint32_t id_;
+ const Identity identity_;
+ const CapabilitySpec capability_spec_;
+ const bool allow_any_application_;
+ std::unique_ptr<NativeRunner> runner_;
+ mojom::ShellClientPtr shell_client_;
+ mojo::Binding<mojom::PIDReceiver> pid_receiver_binding_;
+ mojo::BindingSet<mojom::Connector> connectors_;
+ mojo::BindingSet<mojom::Shell> shell_bindings_;
+ base::ProcessId pid_ = base::kNullProcessId;
+ Instance* parent_ = nullptr;
+ std::set<Instance*> children_;
+ base::WeakPtrFactory<Instance> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Instance);
+};
+
+// static
+Shell::TestAPI::TestAPI(Shell* shell) : shell_(shell) {}
+Shell::TestAPI::~TestAPI() {}
+
+bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const {
+ for (const auto& entry : shell_->identity_to_instance_) {
+ if (entry.first.name() == name)
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Shell, public:
+
+Shell::Shell(std::unique_ptr<NativeRunnerFactory> native_runner_factory,
+ mojom::ShellClientPtr catalog)
+ : native_runner_factory_(std::move(native_runner_factory)),
+ weak_ptr_factory_(this) {
+ mojom::ShellClientPtr client;
+ mojom::ShellClientRequest request = mojo::GetProxy(&client);
+ Instance* instance = CreateInstance(Identity(), CreateShellIdentity(),
+ GetPermissiveCapabilities());
+ instance->StartWithClient(std::move(client));
+ singletons_.insert(kShellName);
+ shell_connection_.reset(new ShellConnection(this, std::move(request)));
+
+ if (catalog)
+ InitCatalog(std::move(catalog));
+}
+
+Shell::~Shell() {
+ TerminateShellConnections();
+ // Terminate any remaining instances.
+ while (!identity_to_instance_.empty())
+ OnInstanceError(identity_to_instance_.begin()->second);
+ identity_to_resolver_.clear();
+}
+
+void Shell::SetInstanceQuitCallback(
+ base::Callback<void(const Identity&)> callback) {
+ instance_quit_callback_ = callback;
+}
+
+void Shell::Connect(std::unique_ptr<ConnectParams> params) {
+ Connect(std::move(params), nullptr);
+}
+
+mojom::ShellClientRequest Shell::InitInstanceForEmbedder(
+ const std::string& name) {
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+
+ Identity embedder_identity(name, mojom::kRootUserID);
+ params->set_source(embedder_identity);
+ params->set_target(embedder_identity);
+
+ mojom::ShellClientPtr client;
+ mojom::ShellClientRequest request = mojo::GetProxy(&client);
+ Connect(std::move(params), std::move(client));
+
+ return request;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Shell, ShellClient implementation:
+
+bool Shell::AcceptConnection(Connection* connection) {
+ // The only interface we expose is mojom::Shell, and access to this interface
+ // is brokered by a policy specific to each caller, managed by the caller's
+ // instance. Here we look to see who's calling, and forward to the caller's
+ // instance to continue.
+ Instance* instance = nullptr;
+ for (const auto& entry : identity_to_instance_) {
+ if (entry.second->id() == connection->GetRemoteInstanceID()) {
+ instance = entry.second;
+ break;
+ }
+ }
+ DCHECK(instance);
+ return instance->AcceptConnection(connection);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Shell, private:
+
+void Shell::InitCatalog(mojom::ShellClientPtr catalog) {
+ // TODO(beng): It'd be great to build this from the manifest, however there's
+ // a bit of a chicken-and-egg problem.
+ CapabilitySpec spec;
+ Interfaces interfaces;
+ interfaces.insert("filesystem::mojom::Directory");
+ spec.provided["app"] = interfaces;
+ Instance* instance = CreateInstance(CreateShellIdentity(),
+ CreateCatalogIdentity(),
+ spec);
+ singletons_.insert(kCatalogName);
+ instance->StartWithClient(std::move(catalog));
+}
+
+mojom::ShellResolver* Shell::GetResolver(const Identity& identity) {
+ auto iter = identity_to_resolver_.find(identity);
+ if (iter != identity_to_resolver_.end())
+ return iter->second.get();
+
+ mojom::ShellResolverPtr resolver_ptr;
+ ConnectToInterface(this, identity, CreateCatalogIdentity(), &resolver_ptr);
+ mojom::ShellResolver* resolver = resolver_ptr.get();
+ identity_to_resolver_[identity] = std::move(resolver_ptr);
+ return resolver;
+}
+
+void Shell::TerminateShellConnections() {
+ Instance* instance = GetExistingInstance(CreateShellIdentity());
+ DCHECK(instance);
+ OnInstanceError(instance);
+}
+
+void Shell::OnInstanceError(Instance* instance) {
+ const Identity identity = instance->identity();
+ // Remove the shell.
+ auto it = identity_to_instance_.find(identity);
+ DCHECK(it != identity_to_instance_.end());
+ int id = instance->id();
+ identity_to_instance_.erase(it);
+ instance_listeners_.ForAllPtrs([this, id](mojom::InstanceListener* listener) {
+ listener->InstanceDestroyed(id);
+ });
+ delete instance;
+ if (!instance_quit_callback_.is_null())
+ instance_quit_callback_.Run(identity);
+}
+
+void Shell::Connect(std::unique_ptr<ConnectParams> params,
+ mojom::ShellClientPtr client) {
+ TRACE_EVENT_INSTANT1("mojo_shell", "Shell::Connect",
+ TRACE_EVENT_SCOPE_THREAD, "original_name",
+ params->target().name());
+ DCHECK(IsValidName(params->target().name()));
+ DCHECK(base::IsValidGUID(params->target().user_id()));
+ DCHECK_NE(mojom::kInheritUserID, params->target().user_id());
+ DCHECK(!client.is_bound() || !identity_to_instance_.count(params->target()));
+
+ // Connect to an existing matching instance, if possible.
+ if (!client.is_bound() && ConnectToExistingInstance(&params))
+ return;
+
+ // The catalog needs to see the source identity as that of the originating
+ // app so it loads the correct store. Since the catalog is itself run as root
+ // when this re-enters Connect() it'll be handled by
+ // ConnectToExistingInstance().
+ mojom::ShellResolver* resolver =
+ GetResolver(Identity(kShellName, params->target().user_id()));
+
+ std::string name = params->target().name();
+ resolver->ResolveMojoName(
+ name, base::Bind(&shell::Shell::OnGotResolvedName,
+ weak_ptr_factory_.GetWeakPtr(), base::Passed(&params),
+ base::Passed(&client)));
+}
+
+Shell::Instance* Shell::GetExistingInstance(const Identity& identity) const {
+ const auto& it = identity_to_instance_.find(identity);
+ Instance* instance = it != identity_to_instance_.end() ? it->second : nullptr;
+ if (instance)
+ return instance;
+
+ if (singletons_.find(identity.name()) != singletons_.end()) {
+ for (auto entry : identity_to_instance_) {
+ if (entry.first.name() == identity.name() &&
+ entry.first.instance() == identity.instance()) {
+ return entry.second;
+ }
+ }
+ }
+ return nullptr;
+}
+
+void Shell::NotifyPIDAvailable(uint32_t id, base::ProcessId pid) {
+ instance_listeners_.ForAllPtrs([id, pid](mojom::InstanceListener* listener) {
+ listener->InstancePIDAvailable(id, pid);
+ });
+}
+
+bool Shell::ConnectToExistingInstance(std::unique_ptr<ConnectParams>* params) {
+ Instance* instance = GetExistingInstance((*params)->target());
+ if (instance)
+ instance->ConnectToClient(std::move(*params));
+ return !!instance;
+}
+
+Shell::Instance* Shell::CreateInstance(const Identity& source,
+ const Identity& target,
+ const CapabilitySpec& spec) {
+ CHECK(target.user_id() != mojom::kInheritUserID);
+ Instance* instance = new Instance(this, target, spec);
+ DCHECK(identity_to_instance_.find(target) ==
+ identity_to_instance_.end());
+ Instance* source_instance = GetExistingInstance(source);
+ if (source_instance)
+ source_instance->AddChild(instance);
+ identity_to_instance_[target] = instance;
+ mojom::InstanceInfoPtr info = instance->CreateInstanceInfo();
+ instance_listeners_.ForAllPtrs([&info](mojom::InstanceListener* listener) {
+ listener->InstanceCreated(info.Clone());
+ });
+ return instance;
+}
+
+void Shell::AddInstanceListener(mojom::InstanceListenerPtr listener) {
+ // TODO(beng): filter instances provided by those visible to this client.
+ mojo::Array<mojom::InstanceInfoPtr> instances;
+ for (auto& instance : identity_to_instance_)
+ instances.push_back(instance.second->CreateInstanceInfo());
+ listener->SetExistingInstances(std::move(instances));
+
+ instance_listeners_.AddPtr(std::move(listener));
+}
+
+void Shell::CreateShellClientWithFactory(const Identity& shell_client_factory,
+ const std::string& name,
+ mojom::ShellClientRequest request) {
+ mojom::ShellClientFactory* factory =
+ GetShellClientFactory(shell_client_factory);
+ factory->CreateShellClient(std::move(request), name);
+}
+
+mojom::ShellClientFactory* Shell::GetShellClientFactory(
+ const Identity& shell_client_factory_identity) {
+ auto it = shell_client_factories_.find(shell_client_factory_identity);
+ if (it != shell_client_factories_.end())
+ return it->second.get();
+
+ Identity source_identity(kShellName, mojom::kInheritUserID);
+ mojom::ShellClientFactoryPtr factory;
+ ConnectToInterface(this, source_identity, shell_client_factory_identity,
+ &factory);
+ mojom::ShellClientFactory* factory_interface = factory.get();
+ factory.set_connection_error_handler(base::Bind(
+ &shell::Shell::OnShellClientFactoryLost, weak_ptr_factory_.GetWeakPtr(),
+ shell_client_factory_identity));
+ shell_client_factories_[shell_client_factory_identity] = std::move(factory);
+ return factory_interface;
+}
+
+void Shell::OnShellClientFactoryLost(const Identity& which) {
+ // Remove the mapping.
+ auto it = shell_client_factories_.find(which);
+ DCHECK(it != shell_client_factories_.end());
+ shell_client_factories_.erase(it);
+}
+
+void Shell::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
+ mojom::ShellClientPtr client,
+ mojom::ResolveResultPtr result) {
+ std::string instance_name = params->target().instance();
+ if (instance_name == GetNamePath(params->target().name()) &&
+ result->qualifier != GetNamePath(result->resolved_name)) {
+ instance_name = result->qualifier;
+ }
+ Identity target(params->target().name(), params->target().user_id(),
+ instance_name);
+ params->set_target(target);
+
+ // It's possible that when this manifest request was issued, another one was
+ // already in-progress and completed by the time this one did, and so the
+ // requested application may already be running.
+ if (ConnectToExistingInstance(&params))
+ return;
+
+ Identity source = params->source();
+ // |capabilities_ptr| can be null when there is no manifest, e.g. for URL
+ // types not resolvable by the resolver.
+ CapabilitySpec capabilities = GetPermissiveCapabilities();
+ if (!result->capabilities.is_null())
+ capabilities = result->capabilities.To<CapabilitySpec>();
+
+ // Clients that request "all_users" class from the shell are allowed to
+ // field connection requests from any user. They also run with a synthetic
+ // user id generated here. The user id provided via Connect() is ignored.
+ // Additionally apps with the "all_users" class are not tied to the lifetime
+ // of the app that connected to them, instead they are owned by the shell.
+ Identity source_identity_for_creation;
+ if (HasClass(capabilities, kCapabilityClass_AllUsers)) {
+ singletons_.insert(target.name());
+ target.set_user_id(base::GenerateGUID());
+ source_identity_for_creation = CreateShellIdentity();
+ } else {
+ source_identity_for_creation = params->source();
+ }
+
+ mojom::ClientProcessConnectionPtr client_process_connection =
+ params->TakeClientProcessConnection();
+ Instance* instance = CreateInstance(source_identity_for_creation,
+ target, capabilities);
+
+ // Below are various paths through which a new Instance can be bound to a
+ // ShellClient proxy.
+ if (client.is_bound()) {
+ // If a ShellClientPtr was provided, there's no more work to do: someone
+ // is already holding a corresponding ShellClientRequest.
+ instance->StartWithClient(std::move(client));
+ } else if (!client_process_connection.is_null()) {
+ // Likewise if a ClientProcessConnection was given via Connect(), it
+ // provides the ShellClient proxy to use.
+ instance->StartWithClientProcessConnection(
+ std::move(client_process_connection));
+ } else {
+ // Otherwise we create a new ShellClient pipe.
+ mojom::ShellClientRequest request = GetProxy(&client);
+ CHECK(!result->package_path.empty() && !result->capabilities.is_null());
+
+ if (target.name() != result->resolved_name) {
+ instance->StartWithClient(std::move(client));
+ Identity factory(result->resolved_name, target.user_id(),
+ instance_name);
+ CreateShellClientWithFactory(factory, target.name(),
+ std::move(request));
+ } else {
+ instance->StartWithFilePath(result->package_path);
+ }
+ }
+
+ // Now that the instance has a ShellClient, we can connect to it.
+ instance->ConnectToClient(std::move(params));
+}
+
+base::WeakPtr<Shell> Shell::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/shell.gyp b/chromium/services/shell/shell.gyp
new file mode 100644
index 00000000000..054a10d459e
--- /dev/null
+++ b/chromium/services/shell/shell.gyp
@@ -0,0 +1,205 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'shell_lib',
+ 'type': 'static_library',
+ 'sources': [
+ '../catalog/catalog.cc',
+ '../catalog/catalog.h',
+ '../catalog/constants.cc',
+ '../catalog/constants.h',
+ '../catalog/entry.cc',
+ '../catalog/entry.h',
+ '../catalog/instance.cc',
+ '../catalog/instance.h',
+ '../catalog/reader.cc',
+ '../catalog/reader.h',
+ '../catalog/store.cc',
+ '../catalog/store.h',
+ '../catalog/types.h',
+ 'connect_params.cc',
+ 'connect_params.h',
+ 'connect_util.cc',
+ 'connect_util.h',
+ 'native_runner.h',
+ 'native_runner_delegate.h',
+ 'shell.cc',
+ 'shell.h',
+ 'switches.cc',
+ 'switches.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '<(DEPTH)/components/filesystem/filesystem.gyp:filesystem_bindings',
+ '<(DEPTH)/components/filesystem/filesystem.gyp:filesystem_lib',
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
+ 'shell_public.gyp:shell_public',
+ ],
+ 'export_dependent_settings': [
+ '<(DEPTH)/components/filesystem/filesystem.gyp:filesystem_bindings',
+ 'shell_public.gyp:shell_public',
+ ],
+ 'variables': {
+ 'mojom_typemaps': [
+ '<(DEPTH)/mojo/common/common_custom_types.typemap',
+ ],
+ }
+ }, {
+ 'target_name': 'mojo_shell_unittests',
+ 'type': 'executable',
+ 'sources': [
+ 'tests/placeholder_unittest.cc',
+ ],
+ 'dependencies': [
+ 'shell_lib',
+ 'shell_test_public',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
+ '<(DEPTH)/mojo/mojo_edk.gyp:mojo_run_all_unittests',
+ '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ 'shell_public.gyp:shell_public',
+ ]
+ }, {
+ 'target_name': 'shell_test_public',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'shell_test_interfaces',
+ ],
+ }, {
+ 'target_name': 'shell_test_interfaces',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ 'tests/test.mojom',
+ ],
+ },
+ 'includes': [
+ '../../mojo/mojom_bindings_generator_explicit.gypi',
+ ],
+ }, {
+ 'target_name': 'shell_runner_common_lib',
+ 'type': 'static_library',
+ 'sources': [
+ 'runner/common/client_util.cc',
+ 'runner/common/client_util.h',
+ 'runner/common/switches.cc',
+ 'runner/common/switches.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
+ '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_system',
+ 'shell_public.gyp:shell_public',
+ ],
+ 'export_dependent_settings': [
+ 'shell_public.gyp:shell_public',
+ ],
+ }, {
+ 'target_name': 'shell_runner_host_lib',
+ 'type': 'static_library',
+ 'sources': [
+ 'runner/host/child_process.cc',
+ 'runner/host/child_process.h',
+ 'runner/host/child_process_base.cc',
+ 'runner/host/child_process_base.h',
+ 'runner/host/child_process_host.cc',
+ 'runner/host/child_process_host.h',
+ 'runner/host/in_process_native_runner.cc',
+ 'runner/host/in_process_native_runner.h',
+ 'runner/host/native_application_support.cc',
+ 'runner/host/native_application_support.h',
+ 'runner/host/out_of_process_native_runner.cc',
+ 'runner/host/out_of_process_native_runner.h',
+ 'runner/init.cc',
+ 'runner/init.h',
+ ],
+ 'dependencies': [
+ 'shell_lib',
+ 'shell_runner_common_lib',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/base/base.gyp:base_i18n',
+ '<(DEPTH)/base/base.gyp:base_static',
+ '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
+ '<(DEPTH)/mojo/mojo_platform_handle.gyp:platform_handle',
+ 'shell_public.gyp:shell_public',
+ ],
+ 'export_dependent_settings': [
+ 'shell_public.gyp:shell_public',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'sources': [
+ 'runner/host/linux_sandbox.cc',
+ 'runner/host/linux_sandbox.h',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/sandbox/sandbox.gyp:sandbox',
+ '<(DEPTH)/sandbox/sandbox.gyp:sandbox_services',
+ '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf',
+ '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf_helpers',
+ ],
+ }],
+ ['OS=="mac"', {
+ 'sources': [
+ 'runner/host/mach_broker.cc',
+ 'runner/host/mach_broker.h',
+ ],
+ }],
+ ],
+ }, {
+ # GN version: //services/catalog:manifest
+ 'target_name': 'catalog_manifest',
+ 'type': 'none',
+ 'variables': {
+ 'application_type': 'mojo',
+ 'application_name': 'catalog',
+ 'source_manifest': '<(DEPTH)/services/catalog/manifest.json',
+ },
+ 'includes': [
+ '../../mojo/public/mojo_application_manifest.gypi',
+ ],
+ 'hard_dependency': 1,
+ }, {
+ # GN version: //services/shell/public/cpp/tests
+ 'target_name': 'shell_client_lib_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/mojo/mojo_edk.gyp:mojo_run_all_unittests',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ 'shell_public.gyp:shell_public',
+ ],
+ 'sources': [
+ 'public/cpp/tests/interface_registry_unittest.cc',
+ ],
+ }],
+ 'conditions': [
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'mojo_shell_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'mojo_shell_unittests',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'mojo_shell_unittests.isolate',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/services/shell/shell.h b/chromium/services/shell/shell.h
new file mode 100644
index 00000000000..4f7afde70af
--- /dev/null
+++ b/chromium/services/shell/shell.h
@@ -0,0 +1,172 @@
+// 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.
+
+#ifndef SERVICES_SHELL_SHELL_H_
+#define SERVICES_SHELL_SHELL_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "services/shell/connect_params.h"
+#include "services/shell/native_runner.h"
+#include "services/shell/public/cpp/capabilities.h"
+#include "services/shell/public/cpp/identity.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+#include "services/shell/public/interfaces/shell.mojom.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+#include "services/shell/public/interfaces/shell_client_factory.mojom.h"
+#include "services/shell/public/interfaces/shell_resolver.mojom.h"
+
+namespace shell {
+class ShellConnection;
+
+// Creates an identity for the Shell, used when the Shell connects to
+// applications.
+Identity CreateShellIdentity();
+
+class Shell : public ShellClient {
+ public:
+ // API for testing.
+ class TestAPI {
+ public:
+ explicit TestAPI(Shell* shell);
+ ~TestAPI();
+
+ // Returns true if there is a Instance for this name.
+ bool HasRunningInstanceForName(const std::string& name) const;
+ private:
+ Shell* shell_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestAPI);
+ };
+
+ // |native_runner_factory| is an instance of an object capable of vending
+ // implementations of NativeRunner, e.g. for in or out-of-process execution.
+ // See native_runner.h and RunNativeApplication().
+ // |file_task_runner| provides access to a thread to perform file copy
+ // operations on.
+ Shell(std::unique_ptr<NativeRunnerFactory> native_runner_factory,
+ mojom::ShellClientPtr catalog);
+ ~Shell() override;
+
+ // Provide a callback to be notified whenever an instance is destroyed.
+ // Typically the creator of the Shell will use this to determine when some set
+ // of instances it created are destroyed, so it can shut down.
+ void SetInstanceQuitCallback(base::Callback<void(const Identity&)> callback);
+
+ // Completes a connection between a source and target application as defined
+ // by |params|, exchanging InterfaceProviders between them. If no existing
+ // instance of the target application is running, one will be loaded.
+ void Connect(std::unique_ptr<ConnectParams> params);
+
+ // Creates a new Instance identified as |name|. This is intended for use by
+ // the Shell's embedder to register itself with the shell. This must only be
+ // called once.
+ mojom::ShellClientRequest InitInstanceForEmbedder(const std::string& name);
+
+ private:
+ class Instance;
+
+ // ShellClient:
+ bool AcceptConnection(Connection* connection) override;
+
+ void InitCatalog(mojom::ShellClientPtr catalog);
+
+ // Returns the resolver to use for the specified identity.
+ // NOTE: ShellResolvers are cached to ensure we service requests in order. If
+ // we use a separate ShellResolver for each request ordering is not
+ // guaranteed and can lead to random flake.
+ mojom::ShellResolver* GetResolver(const Identity& identity);
+
+ // Destroys all Shell-ends of connections established with Applications.
+ // Applications connected by this Shell will observe pipe errors and have a
+ // chance to shutdown.
+ void TerminateShellConnections();
+
+ // Removes a Instance when it encounters an error.
+ void OnInstanceError(Instance* instance);
+
+ // Completes a connection between a source and target application as defined
+ // by |params|, exchanging InterfaceProviders between them. If no existing
+ // instance of the target application is running, one will be loaded.
+ //
+ // If |client| is not null, there must not be an instance of the target
+ // application already running. The shell will create a new instance and use
+ // |client| to control it.
+ void Connect(std::unique_ptr<ConnectParams> params,
+ mojom::ShellClientPtr client);
+
+ // Returns a running instance matching |identity|. This might be an instance
+ // running as a different user if one is available that services all users.
+ Instance* GetExistingInstance(const Identity& identity) const;
+
+ void NotifyPIDAvailable(uint32_t id, base::ProcessId pid);
+
+ // Attempt to complete the connection requested by |params| by connecting to
+ // an existing instance. If there is an existing instance, |params| is taken,
+ // and this function returns true.
+ bool ConnectToExistingInstance(std::unique_ptr<ConnectParams>* params);
+
+ Instance* CreateInstance(const Identity& source,
+ const Identity& target,
+ const CapabilitySpec& spec);
+
+ // Called from the instance implementing mojom::Shell.
+ void AddInstanceListener(mojom::InstanceListenerPtr listener);
+
+ void CreateShellClientWithFactory(const Identity& shell_client_factory,
+ const std::string& name,
+ mojom::ShellClientRequest request);
+ // Returns a running ShellClientFactory for |shell_client_factory_identity|.
+ // If there is not one running one is started for |source_identity|.
+ mojom::ShellClientFactory* GetShellClientFactory(
+ const Identity& shell_client_factory_identity);
+ void OnShellClientFactoryLost(const Identity& which);
+
+ // Callback when remote Catalog resolves mojo:foo to mojo:bar.
+ // |params| are the params passed to Connect().
+ // |client| if provided is a ShellClientPtr which should be used to manage the
+ // new application instance. This may be null.
+ // |result| contains the result of the resolve operation.
+ void OnGotResolvedName(std::unique_ptr<ConnectParams> params,
+ mojom::ShellClientPtr client,
+ mojom::ResolveResultPtr result);
+
+ base::WeakPtr<Shell> GetWeakPtr();
+
+ std::map<Identity, Instance*> identity_to_instance_;
+
+ // Tracks the names of instances that are allowed to field connection requests
+ // from all users.
+ std::set<std::string> singletons_;
+
+ std::map<Identity, mojom::ShellClientFactoryPtr> shell_client_factories_;
+ // Counter used to assign ids to client factories.
+ uint32_t shell_client_factory_id_counter_;
+
+ std::map<Identity, mojom::ShellResolverPtr> identity_to_resolver_;
+
+ mojo::InterfacePtrSet<mojom::InstanceListener> instance_listeners_;
+
+ base::Callback<void(const Identity&)> instance_quit_callback_;
+ std::unique_ptr<NativeRunnerFactory> native_runner_factory_;
+ std::unique_ptr<ShellConnection> shell_connection_;
+ base::WeakPtrFactory<Shell> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Shell);
+};
+
+mojom::Connector::ConnectCallback EmptyConnectCallback();
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_SHELL_H_
diff --git a/chromium/services/shell/shell_public.gyp b/chromium/services/shell/shell_public.gyp
new file mode 100644
index 00000000000..c8b248725e7
--- /dev/null
+++ b/chromium/services/shell/shell_public.gyp
@@ -0,0 +1,73 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'shell_interfaces',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ '../catalog/public/interfaces/catalog.mojom',
+ 'public/interfaces/capabilities.mojom',
+ 'public/interfaces/connector.mojom',
+ 'public/interfaces/interface_provider.mojom',
+ 'public/interfaces/shell.mojom',
+ 'public/interfaces/shell_client.mojom',
+ 'public/interfaces/shell_client_factory.mojom',
+ 'public/interfaces/shell_resolver.mojom',
+ ],
+ 'mojom_typemaps': [
+ '<(DEPTH)/mojo/common/common_custom_types.typemap',
+ ],
+ },
+ 'includes': [ '../../mojo/mojom_bindings_generator_explicit.gypi' ],
+ 'dependencies': [
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_custom_types_mojom',
+ ],
+ 'export_dependent_settings': [
+ '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_custom_types_mojom',
+ ],
+ },
+ {
+ # GN version: //services/shell/public/cpp
+ 'target_name': 'shell_public',
+ 'type': 'static_library',
+ 'sources': [
+ 'public/cpp/application_runner.h',
+ 'public/cpp/capabilities.h',
+ 'public/cpp/connect.h',
+ 'public/cpp/connection.h',
+ 'public/cpp/connector.h',
+ 'public/cpp/identity.h',
+ 'public/cpp/interface_binder.h',
+ 'public/cpp/interface_factory.h',
+ 'public/cpp/interface_factory_impl.h',
+ 'public/cpp/interface_registry.h',
+ 'public/cpp/lib/application_runner.cc',
+ 'public/cpp/lib/capabilities.cc',
+ 'public/cpp/lib/connection_impl.cc',
+ 'public/cpp/lib/connection_impl.h',
+ 'public/cpp/lib/connector_impl.cc',
+ 'public/cpp/lib/connector_impl.h',
+ 'public/cpp/lib/identity.cc',
+ 'public/cpp/lib/interface_factory_binder.h',
+ 'public/cpp/lib/interface_registry.cc',
+ 'public/cpp/lib/names.cc',
+ 'public/cpp/lib/shell_client.cc',
+ 'public/cpp/lib/shell_connection.cc',
+ 'public/cpp/lib/shell_connection_ref.cc',
+ 'public/cpp/names.h',
+ 'public/cpp/shell_client.h',
+ 'public/cpp/shell_connection.h',
+ 'public/cpp/shell_connection_ref.h',
+ ],
+ 'dependencies': [
+ 'shell_interfaces',
+ '<(DEPTH)/base/base.gyp:base_i18n',
+ '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ ],
+ },
+ ],
+}
diff --git a/chromium/services/shell/standalone/BUILD.gn b/chromium/services/shell/standalone/BUILD.gn
new file mode 100644
index 00000000000..9eb1c021a5f
--- /dev/null
+++ b/chromium/services/shell/standalone/BUILD.gn
@@ -0,0 +1,60 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
+
+executable("standalone") {
+ output_name = "mojo_runner"
+ sources = [
+ "desktop/main.cc",
+ ]
+ deps = [
+ ":lib",
+ "//base",
+ "//build/config/sanitizers:deps",
+ "//build/win:default_exe_manifest",
+ ]
+}
+
+source_set("lib") {
+ sources = [
+ "context.cc",
+ "context.h",
+ "desktop/launcher_process.cc",
+ "desktop/launcher_process.h",
+ "desktop/main_helper.cc",
+ "desktop/main_helper.h",
+ "tracer.cc",
+ "tracer.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//components/tracing:startup_tracing",
+ "//mojo/edk/system",
+ "//services/catalog:lib",
+ "//services/shell",
+ "//services/shell/public/cpp",
+ "//services/shell/runner/host:lib",
+ "//services/tracing/public/cpp",
+ "//services/tracing/public/interfaces",
+ "//url",
+ ]
+
+ data_deps = [
+ "//services/tracing",
+ ]
+
+ # This target includes some files behind #ifdef OS... guards. Since gn is not
+ # smart enough to understand preprocess includes, it does complains about
+ # these includes when not using the build files for that OS. Suppress checking
+ # so we can enable checking for the rest of the targets in this file.
+ # TODO: Might be better to split the files with OS-specific includes out to a
+ # separate source_set so we can leave checking on for the rest of the target.
+ check_includes = false
+}
diff --git a/chromium/services/shell/standalone/DEPS b/chromium/services/shell/standalone/DEPS
new file mode 100644
index 00000000000..4af70245fc9
--- /dev/null
+++ b/chromium/services/shell/standalone/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/tracing",
+ "+services/catalog",
+ "+services/tracing",
+]
diff --git a/chromium/services/shell/standalone/context.cc b/chromium/services/shell/standalone/context.cc
new file mode 100644
index 00000000000..9eb3cb2dc05
--- /dev/null
+++ b/chromium/services/shell/standalone/context.cc
@@ -0,0 +1,262 @@
+// Copyright 2013 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 "services/shell/standalone/context.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/process/process_info.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "components/tracing/tracing_switches.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/util/filename_util.h"
+#include "services/catalog/catalog.h"
+#include "services/catalog/store.h"
+#include "services/shell/connect_params.h"
+#include "services/shell/public/cpp/names.h"
+#include "services/shell/runner/host/in_process_native_runner.h"
+#include "services/shell/runner/host/out_of_process_native_runner.h"
+#include "services/shell/standalone/tracer.h"
+#include "services/shell/switches.h"
+#include "services/tracing/public/cpp/switches.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+
+#if defined(OS_MACOSX)
+#include "services/shell/runner/host/mach_broker.h"
+#endif
+
+namespace shell {
+namespace {
+
+// Used to ensure we only init once.
+class Setup {
+ public:
+ Setup() { mojo::edk::Init(); }
+
+ ~Setup() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Setup);
+};
+
+class TracingInterfaceProvider : public mojom::InterfaceProvider {
+ public:
+ TracingInterfaceProvider(Tracer* tracer,
+ mojom::InterfaceProviderRequest request)
+ : tracer_(tracer), binding_(this, std::move(request)) {}
+ ~TracingInterfaceProvider() override {}
+
+ // mojom::InterfaceProvider:
+ void GetInterface(const mojo::String& interface_name,
+ mojo::ScopedMessagePipeHandle client_handle) override {
+ if (tracer_ && interface_name == tracing::TraceProvider::Name_) {
+ tracer_->ConnectToProvider(
+ mojo::MakeRequest<tracing::TraceProvider>(std::move(client_handle)));
+ }
+ }
+
+ private:
+ Tracer* tracer_;
+ mojo::StrongBinding<mojom::InterfaceProvider> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingInterfaceProvider);
+};
+
+const size_t kMaxBlockingPoolThreads = 3;
+
+std::unique_ptr<base::Thread> CreateIOThread(const char* name) {
+ std::unique_ptr<base::Thread> thread(new base::Thread(name));
+ base::Thread::Options options;
+ options.message_loop_type = base::MessageLoop::TYPE_IO;
+ thread->StartWithOptions(options);
+ return thread;
+}
+
+void OnInstanceQuit(const std::string& name, const Identity& identity) {
+ if (name == identity.name())
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+} // namespace
+
+Context::InitParams::InitParams() {}
+Context::InitParams::~InitParams() {}
+
+Context::Context()
+ : io_thread_(CreateIOThread("io_thread")),
+ main_entry_time_(base::Time::Now()) {}
+
+Context::~Context() {
+ DCHECK(!base::MessageLoop::current());
+ blocking_pool_->Shutdown();
+}
+
+// static
+void Context::EnsureEmbedderIsInitialized() {
+ static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
+ setup.Get();
+}
+
+void Context::Init(std::unique_ptr<InitParams> init_params) {
+ TRACE_EVENT0("mojo_shell", "Context::Init");
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ bool trace_startup = command_line.HasSwitch(::switches::kTraceStartup);
+ if (trace_startup) {
+ tracer_.Start(
+ command_line.GetSwitchValueASCII(::switches::kTraceStartup),
+ command_line.GetSwitchValueASCII(::switches::kTraceStartupDuration),
+ "mojo_runner.trace");
+ }
+
+ if (!init_params || init_params->init_edk)
+ EnsureEmbedderIsInitialized();
+
+ shell_runner_ = base::MessageLoop::current()->task_runner();
+ blocking_pool_ =
+ new base::SequencedWorkerPool(kMaxBlockingPoolThreads, "blocking_pool");
+
+ init_edk_ = !init_params || init_params->init_edk;
+ if (init_edk_) {
+ mojo::edk::InitIPCSupport(this, io_thread_->task_runner().get());
+#if defined(OS_MACOSX)
+ mojo::edk::SetMachPortProvider(MachBroker::GetInstance()->port_provider());
+#endif
+ }
+
+ std::unique_ptr<NativeRunnerFactory> runner_factory;
+ if (command_line.HasSwitch(switches::kSingleProcess)) {
+#if defined(COMPONENT_BUILD)
+ LOG(ERROR) << "Running Mojo in single process component build, which isn't "
+ << "supported because statics in apps interact. Use static build"
+ << " or don't pass --single-process.";
+#endif
+ runner_factory.reset(
+ new InProcessNativeRunnerFactory(blocking_pool_.get()));
+ } else {
+ NativeRunnerDelegate* native_runner_delegate = init_params ?
+ init_params->native_runner_delegate : nullptr;
+ runner_factory.reset(new OutOfProcessNativeRunnerFactory(
+ blocking_pool_.get(), native_runner_delegate));
+ }
+ std::unique_ptr<catalog::Store> store;
+ if (init_params)
+ store = std::move(init_params->catalog_store);
+ catalog_.reset(
+ new catalog::Catalog(blocking_pool_.get(), std::move(store), nullptr));
+ shell_.reset(new Shell(std::move(runner_factory),
+ catalog_->TakeShellClient()));
+
+ mojom::InterfaceProviderPtr tracing_remote_interfaces;
+ mojom::InterfaceProviderPtr tracing_local_interfaces;
+ new TracingInterfaceProvider(&tracer_, GetProxy(&tracing_local_interfaces));
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(CreateShellIdentity());
+ params->set_target(Identity("mojo:tracing", mojom::kRootUserID));
+ params->set_remote_interfaces(mojo::GetProxy(&tracing_remote_interfaces));
+ params->set_local_interfaces(std::move(tracing_local_interfaces));
+ shell_->Connect(std::move(params));
+
+ if (command_line.HasSwitch(tracing::kTraceStartup)) {
+ tracing::TraceCollectorPtr coordinator;
+ auto coordinator_request = GetProxy(&coordinator);
+ tracing_remote_interfaces->GetInterface(
+ tracing::TraceCollector::Name_, coordinator_request.PassMessagePipe());
+ tracer_.StartCollectingFromTracingService(std::move(coordinator));
+ }
+
+ // Record the shell startup metrics used for performance testing.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ tracing::kEnableStatsCollectionBindings)) {
+ tracing::StartupPerformanceDataCollectorPtr collector;
+ tracing_remote_interfaces->GetInterface(
+ tracing::StartupPerformanceDataCollector::Name_,
+ mojo::GetProxy(&collector).PassMessagePipe());
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_LINUX)
+ // CurrentProcessInfo::CreationTime is only defined on some platforms.
+ const base::Time creation_time = base::CurrentProcessInfo::CreationTime();
+ collector->SetShellProcessCreationTime(creation_time.ToInternalValue());
+#endif
+ collector->SetShellMainEntryPointTime(main_entry_time_.ToInternalValue());
+ }
+}
+
+void Context::Shutdown() {
+ // Actions triggered by Shell's destructor may require a current message loop,
+ // so we should destruct it explicitly now as ~Context() occurs post message
+ // loop shutdown.
+ shell_.reset();
+
+ DCHECK_EQ(base::MessageLoop::current()->task_runner(), shell_runner_);
+
+ // If we didn't initialize the edk we should not shut it down.
+ if (!init_edk_)
+ return;
+
+ TRACE_EVENT0("mojo_shell", "Context::Shutdown");
+ // Post a task in case OnShutdownComplete is called synchronously.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(mojo::edk::ShutdownIPCSupport));
+ // We'll quit when we get OnShutdownComplete().
+ base::MessageLoop::current()->Run();
+}
+
+void Context::OnShutdownComplete() {
+ DCHECK_EQ(base::MessageLoop::current()->task_runner(), shell_runner_);
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+void Context::RunCommandLineApplication() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ base::CommandLine::StringVector args = command_line->GetArgs();
+ for (size_t i = 0; i < args.size(); ++i) {
+#if defined(OS_WIN)
+ std::string possible_app = base::WideToUTF8(args[i]);
+#else
+ std::string possible_app = args[i];
+#endif
+ if (GetNameType(possible_app) == "mojo") {
+ Run(possible_app);
+ break;
+ }
+ }
+}
+
+void Context::Run(const std::string& name) {
+ shell_->SetInstanceQuitCallback(base::Bind(&OnInstanceQuit, name));
+
+ mojom::InterfaceProviderPtr remote_interfaces;
+ mojom::InterfaceProviderPtr local_interfaces;
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(CreateShellIdentity());
+ params->set_target(Identity(name, mojom::kRootUserID));
+ params->set_remote_interfaces(mojo::GetProxy(&remote_interfaces));
+ params->set_local_interfaces(std::move(local_interfaces));
+ shell_->Connect(std::move(params));
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/standalone/context.h b/chromium/services/shell/standalone/context.h
new file mode 100644
index 00000000000..1d60d7ca94c
--- /dev/null
+++ b/chromium/services/shell/standalone/context.h
@@ -0,0 +1,85 @@
+// Copyright 2013 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 SERVICES_SHELL_STANDALONE_CONTEXT_H_
+#define SERVICES_SHELL_STANDALONE_CONTEXT_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "mojo/edk/embedder/process_delegate.h"
+#include "services/shell/shell.h"
+#include "services/shell/standalone/tracer.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace catalog {
+class Catalog;
+class Store;
+}
+
+namespace shell {
+class NativeRunnerDelegate;
+
+// The "global" context for the shell's main process.
+class Context : public mojo::edk::ProcessDelegate {
+ public:
+ struct InitParams {
+ InitParams();
+ ~InitParams();
+
+ NativeRunnerDelegate* native_runner_delegate = nullptr;
+ std::unique_ptr<catalog::Store> catalog_store;
+ // If true the edk is initialized.
+ bool init_edk = true;
+ };
+
+ Context();
+ ~Context() override;
+
+ static void EnsureEmbedderIsInitialized();
+
+ // This must be called with a message loop set up for the current thread,
+ // which must remain alive until after Shutdown() is called.
+ void Init(std::unique_ptr<InitParams> init_params);
+
+ // If Init() was called and succeeded, this must be called before destruction.
+ void Shutdown();
+
+ // Run the application specified on the command line.
+ void RunCommandLineApplication();
+
+ Shell* shell() { return shell_.get(); }
+
+ private:
+ // mojo::edk::ProcessDelegate:
+ void OnShutdownComplete() override;
+
+ // Runs the app specified by |name|.
+ void Run(const std::string& name);
+
+ scoped_refptr<base::SingleThreadTaskRunner> shell_runner_;
+ std::unique_ptr<base::Thread> io_thread_;
+ scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
+
+ // Ensure this is destructed before task_runners_ since it owns a message pipe
+ // that needs the IO thread to destruct cleanly.
+ Tracer tracer_;
+ std::unique_ptr<catalog::Catalog> catalog_;
+ std::unique_ptr<Shell> shell_;
+ base::Time main_entry_time_;
+ bool init_edk_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(Context);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_STANDALONE_CONTEXT_H_
diff --git a/chromium/services/shell/standalone/desktop/launcher_process.cc b/chromium/services/shell/standalone/desktop/launcher_process.cc
new file mode 100644
index 00000000000..4403b227e7f
--- /dev/null
+++ b/chromium/services/shell/standalone/desktop/launcher_process.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 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 <stdio.h>
+#include <string.h>
+
+#include <iostream>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_util.h"
+#include "base/i18n/icu_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "services/shell/standalone/context.h"
+#include "services/shell/switches.h"
+
+namespace shell {
+
+int LauncherProcessMain() {
+#if !defined(OFFICIAL_BUILD)
+ base::debug::EnableInProcessStackDumping();
+#endif
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ // http://crbug.com/546644
+ command_line->AppendSwitch(switches::kNoSandbox);
+
+ base::PlatformThread::SetName("mojo_runner");
+
+ // We want the Context to outlive the MessageLoop so that pipes are all
+ // gracefully closed / error-out before we try to shut the Context down.
+ Context shell_context;
+ {
+ base::MessageLoop message_loop;
+ CHECK(base::i18n::InitializeICU());
+ shell_context.Init(nullptr);
+
+ message_loop.PostTask(
+ FROM_HERE,
+ base::Bind(&Context::RunCommandLineApplication,
+ base::Unretained(&shell_context)));
+
+ message_loop.Run();
+
+ // Must be called before |message_loop| is destroyed.
+ shell_context.Shutdown();
+ }
+
+ return 0;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/standalone/desktop/launcher_process.h b/chromium/services/shell/standalone/desktop/launcher_process.h
new file mode 100644
index 00000000000..13cdf5194f0
--- /dev/null
+++ b/chromium/services/shell/standalone/desktop/launcher_process.h
@@ -0,0 +1,17 @@
+// 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 SERVICES_SHELL_STANDALONE_LAUNCHER_PROCESS_H_
+#define SERVICES_SHELL_STANDALONE_LAUNCHER_PROCESS_H_
+
+#include "base/callback_forward.h"
+
+namespace shell {
+
+// Main method for the launcher process.
+int LauncherProcessMain();
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_STANDALONE_LAUNCHER_PROCESS_H_
diff --git a/chromium/services/shell/standalone/desktop/main.cc b/chromium/services/shell/standalone/desktop/main.cc
new file mode 100644
index 00000000000..9a27ab2844c
--- /dev/null
+++ b/chromium/services/shell/standalone/desktop/main.cc
@@ -0,0 +1,9 @@
+// Copyright 2013 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 "services/shell/standalone/desktop/main_helper.h"
+
+int main(int argc, char** argv) {
+ return shell::StandaloneShellMain(argc, argv);
+}
diff --git a/chromium/services/shell/standalone/desktop/main_helper.cc b/chromium/services/shell/standalone/desktop/main_helper.cc
new file mode 100644
index 00000000000..d51f421c1d8
--- /dev/null
+++ b/chromium/services/shell/standalone/desktop/main_helper.cc
@@ -0,0 +1,49 @@
+// 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 "services/shell/standalone/desktop/main_helper.h"
+
+#include "base/at_exit.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/process/launch.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "services/shell/runner/common/switches.h"
+#include "services/shell/runner/host/child_process.h"
+#include "services/shell/runner/init.h"
+#include "services/shell/standalone/desktop/launcher_process.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif (OS_POSIX)
+#include <unistd.h>
+#endif
+
+namespace shell {
+
+int StandaloneShellMain(int argc, char** argv) {
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ base::AtExitManager at_exit;
+ InitializeLogging();
+ WaitForDebuggerIfNecessary();
+
+#if !defined(OFFICIAL_BUILD) && defined(OS_WIN)
+ base::RouteStdioToConsole(false);
+#endif
+
+ if (command_line.HasSwitch(switches::kChildProcess))
+ return ChildProcessMain();
+
+ return LauncherProcessMain();
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/standalone/desktop/main_helper.h b/chromium/services/shell/standalone/desktop/main_helper.h
new file mode 100644
index 00000000000..f326957d328
--- /dev/null
+++ b/chromium/services/shell/standalone/desktop/main_helper.h
@@ -0,0 +1,15 @@
+// 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 SERVICES_SHELL_STANDALONE_DESKTOP_MAIN_HELPER_H
+#define SERVICES_SHELL_STANDALONE_DESKTOP_MAIN_HELPER_H
+
+namespace shell {
+
+// Helper method to start Mojo standalone shell code.
+int StandaloneShellMain(int argc, char** argv);
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_STANDALONE_DESKTOP_MAIN_HELPER_H
diff --git a/chromium/services/shell/standalone/tracer.cc b/chromium/services/shell/standalone/tracer.cc
new file mode 100644
index 00000000000..cffcfe09c55
--- /dev/null
+++ b/chromium/services/shell/standalone/tracer.cc
@@ -0,0 +1,162 @@
+// 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 "services/shell/standalone/tracer.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event.h"
+
+namespace shell {
+
+Tracer::Tracer()
+ : tracing_(false), first_chunk_written_(false), trace_file_(nullptr) {}
+
+Tracer::~Tracer() {
+ StopAndFlushToFile();
+}
+
+void Tracer::Start(const std::string& categories,
+ const std::string& duration_seconds_str,
+ const std::string& filename) {
+ tracing_ = true;
+ trace_filename_ = filename;
+ categories_ = categories;
+ base::trace_event::TraceConfig config(categories,
+ base::trace_event::RECORD_UNTIL_FULL);
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ config, base::trace_event::TraceLog::RECORDING_MODE);
+
+ int trace_duration_secs = 5;
+ if (!duration_seconds_str.empty()) {
+ CHECK(base::StringToInt(duration_seconds_str, &trace_duration_secs))
+ << "Could not parse --trace-startup-duration value "
+ << duration_seconds_str;
+ }
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&Tracer::StopAndFlushToFile, base::Unretained(this)),
+ base::TimeDelta::FromSeconds(trace_duration_secs));
+}
+
+void Tracer::StartCollectingFromTracingService(
+ tracing::TraceCollectorPtr coordinator) {
+ coordinator_ = std::move(coordinator);
+ mojo::DataPipe data_pipe;
+ coordinator_->Start(std::move(data_pipe.producer_handle), categories_);
+ drainer_.reset(new mojo::common::DataPipeDrainer(
+ this, std::move(data_pipe.consumer_handle)));
+}
+
+void Tracer::StopAndFlushToFile() {
+ if (tracing_)
+ StopTracingAndFlushToDisk();
+}
+
+void Tracer::ConnectToProvider(
+ mojo::InterfaceRequest<tracing::TraceProvider> request) {
+ trace_provider_impl_.Bind(std::move(request));
+}
+
+void Tracer::StopTracingAndFlushToDisk() {
+ tracing_ = false;
+ trace_file_ = fopen(trace_filename_.c_str(), "w+");
+ PCHECK(trace_file_);
+ static const char kStart[] = "{\"traceEvents\":[";
+ PCHECK(fwrite(kStart, 1, strlen(kStart), trace_file_) == strlen(kStart));
+
+ // At this point we might be connected to the tracing service, in which case
+ // we want to tell it to stop tracing and we will send the data we've
+ // collected in process to it.
+ if (coordinator_) {
+ coordinator_->StopAndFlush();
+ } else {
+ // Or we might not be connected. If we aren't connected to the tracing
+ // service we want to collect the tracing data gathered ourselves and flush
+ // it to disk. We do this in a blocking fashion (for this thread) so we can
+ // gather as much data as possible on shutdown.
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ {
+ base::WaitableEvent flush_complete_event(false, false);
+ // TraceLog::Flush requires a message loop but we've already shut ours
+ // down.
+ // Spin up a new thread to flush things out.
+ base::Thread flush_thread("mojo_runner_trace_event_flush");
+ flush_thread.Start();
+ flush_thread.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&Tracer::EndTraceAndFlush, base::Unretained(this),
+ trace_filename_,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&flush_complete_event))));
+ base::trace_event::TraceLog::GetInstance()
+ ->SetCurrentThreadBlocksMessageLoop();
+ flush_complete_event.Wait();
+ }
+ }
+}
+
+void Tracer::WriteFooterAndClose() {
+ static const char kEnd[] = "]}";
+ PCHECK(fwrite(kEnd, 1, strlen(kEnd), trace_file_) == strlen(kEnd));
+ PCHECK(fclose(trace_file_) == 0);
+ trace_file_ = nullptr;
+ LOG(ERROR) << "Wrote trace data to " << trace_filename_;
+}
+
+void Tracer::EndTraceAndFlush(const std::string& filename,
+ const base::Closure& done_callback) {
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ base::trace_event::TraceLog::GetInstance()->Flush(base::Bind(
+ &Tracer::WriteTraceDataCollected, base::Unretained(this), done_callback));
+}
+
+void Tracer::WriteTraceDataCollected(
+ const base::Closure& done_callback,
+ const scoped_refptr<base::RefCountedString>& events_str,
+ bool has_more_events) {
+ if (events_str->size()) {
+ WriteCommaIfNeeded();
+
+ PCHECK(fwrite(events_str->data().c_str(), 1, events_str->data().length(),
+ trace_file_) == events_str->data().length());
+ }
+
+ if (!has_more_events && !done_callback.is_null())
+ done_callback.Run();
+}
+
+void Tracer::OnDataAvailable(const void* data, size_t num_bytes) {
+ const char* chars = static_cast<const char*>(data);
+ trace_service_data_.append(chars, num_bytes);
+}
+
+void Tracer::OnDataComplete() {
+ if (!trace_service_data_.empty()) {
+ WriteCommaIfNeeded();
+ const char* const chars = trace_service_data_.data();
+ size_t num_bytes = trace_service_data_.length();
+ PCHECK(fwrite(chars, 1, num_bytes, trace_file_) == num_bytes);
+ trace_service_data_ = std::string();
+ }
+ drainer_.reset();
+ coordinator_.reset();
+ WriteFooterAndClose();
+}
+
+void Tracer::WriteCommaIfNeeded() {
+ if (first_chunk_written_)
+ PCHECK(fwrite(",", 1, 1, trace_file_) == 1);
+ first_chunk_written_ = true;
+}
+
+} // namespace shell
diff --git a/chromium/services/shell/standalone/tracer.h b/chromium/services/shell/standalone/tracer.h
new file mode 100644
index 00000000000..173f3ab2ddb
--- /dev/null
+++ b/chromium/services/shell/standalone/tracer.h
@@ -0,0 +1,101 @@
+// 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 SERVICES_SHELL_STANDALONE_TRACER_H_
+#define SERVICES_SHELL_STANDALONE_TRACER_H_
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "mojo/common/data_pipe_drainer.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+
+namespace shell {
+
+// Tracer collects tracing data from base/trace_event and from externally
+// configured sources, aggregates it into a single stream, and writes it out to
+// a file. It should be constructed very early in a process' lifetime before any
+// initialization that may be interesting to trace has occured and be shut down
+// as late as possible to capture as much initialization/shutdown code as
+// possible.
+class Tracer : public mojo::common::DataPipeDrainer::Client {
+ public:
+ Tracer();
+ ~Tracer() override;
+
+ // Starts tracing the current process with the given set of categories. The
+ // tracing results will be saved into the specified filename when
+ // StopAndFlushToFile() is called.
+ void Start(const std::string& categories,
+ const std::string& duration_seconds_str,
+ const std::string& filename);
+
+ // Starts collecting data from the tracing service with the given set of
+ // categories.
+ void StartCollectingFromTracingService(
+ tracing::TraceCollectorPtr coordinator);
+
+ // Stops tracing and flushes all collected trace data to the file specified in
+ // Start(). Blocks until the file write is complete. May be called after the
+ // message loop is shut down.
+ void StopAndFlushToFile();
+
+ void ConnectToProvider(
+ mojo::InterfaceRequest<tracing::TraceProvider> request);
+
+ private:
+ void StopTracingAndFlushToDisk();
+
+ // Called from the flush thread. When all data is collected this runs
+ // |done_callback| on the flush thread.
+ void EndTraceAndFlush(const std::string& filename,
+ const base::Closure& done_callback);
+
+ // Called from the flush thread.
+ void WriteTraceDataCollected(
+ const base::Closure& done_callback,
+ const scoped_refptr<base::RefCountedString>& events_str,
+ bool has_more_events);
+
+ // mojo::common::DataPipeDrainer::Client implementation.
+ void OnDataAvailable(const void* data, size_t num_bytes) override;
+ void OnDataComplete() override;
+
+ // Emits a comma if needed.
+ void WriteCommaIfNeeded();
+
+ // Writes trace file footer and closes out the file.
+ void WriteFooterAndClose();
+
+ // Set when connected to the tracing service.
+ tracing::TraceCollectorPtr coordinator_;
+ std::unique_ptr<mojo::common::DataPipeDrainer> drainer_;
+
+ mojo::TraceProviderImpl trace_provider_impl_;
+ // Whether we're currently tracing.
+ bool tracing_;
+ // Categories to trace.
+ std::string categories_;
+
+ // Whether we've written the first chunk.
+ bool first_chunk_written_;
+ std::string trace_service_data_;
+
+ // Trace file, if open.
+ FILE* trace_file_;
+ std::string trace_filename_;
+
+ DISALLOW_COPY_AND_ASSIGN(Tracer);
+};
+
+} // namespace shell
+
+#endif // SERVICES_SHELL_STANDALONE_TRACER_H_
diff --git a/chromium/services/shell/switches.cc b/chromium/services/shell/switches.cc
new file mode 100644
index 00000000000..10dc430c04d
--- /dev/null
+++ b/chromium/services/shell/switches.cc
@@ -0,0 +1,17 @@
+// Copyright 2013 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 "services/shell/switches.h"
+
+namespace shell {
+namespace switches {
+
+// Disables the sandbox for debugging.
+const char kNoSandbox[] = "no-sandbox";
+
+// Load apps in a single processes.
+const char kSingleProcess[] = "single-process";
+
+} // namespace switches
+} // namespace shell
diff --git a/chromium/services/shell/switches.h b/chromium/services/shell/switches.h
new file mode 100644
index 00000000000..1a442e172f4
--- /dev/null
+++ b/chromium/services/shell/switches.h
@@ -0,0 +1,22 @@
+// Copyright 2013 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 SERVICES_SHELL_SWITCHES_H_
+#define SERVICES_SHELL_SWITCHES_H_
+
+#include <set>
+#include <string>
+
+namespace shell {
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kNoSandbox[];
+extern const char kSingleProcess[];
+
+} // namespace switches
+} // namespace shell
+
+#endif // SERVICES_SHELL_SWITCHES_H_
diff --git a/chromium/services/tracing/BUILD.gn b/chromium/services/tracing/BUILD.gn
new file mode 100644
index 00000000000..e63d3700d81
--- /dev/null
+++ b/chromium/services/tracing/BUILD.gn
@@ -0,0 +1,47 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+
+mojo_native_application("tracing") {
+ sources = [
+ "main.cc",
+ ]
+
+ avoid_runner_cycle = true
+
+ deps = [
+ ":lib",
+ "//mojo/public/cpp/system",
+ "//services/shell/public/cpp",
+ ]
+
+ data_deps = [
+ ":manifest",
+ ]
+}
+
+mojo_application_manifest("manifest") {
+ application_name = "tracing"
+ source = "manifest.json"
+}
+
+source_set("lib") {
+ sources = [
+ "trace_data_sink.cc",
+ "trace_data_sink.h",
+ "trace_recorder_impl.cc",
+ "trace_recorder_impl.h",
+ "tracing_app.cc",
+ "tracing_app.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/common:common_base",
+ "//services/shell/public/cpp",
+ "//services/tracing/public/interfaces",
+ ]
+}
diff --git a/chromium/services/tracing/OWNERS b/chromium/services/tracing/OWNERS
new file mode 100644
index 00000000000..4733a4f06bf
--- /dev/null
+++ b/chromium/services/tracing/OWNERS
@@ -0,0 +1 @@
+erg@chromium.org
diff --git a/chromium/services/tracing/main.cc b/chromium/services/tracing/main.cc
new file mode 100644
index 00000000000..758efedf985
--- /dev/null
+++ b/chromium/services/tracing/main.cc
@@ -0,0 +1,12 @@
+// 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 "mojo/public/c/system/main.h"
+#include "services/shell/public/cpp/application_runner.h"
+#include "services/tracing/tracing_app.h"
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+ shell::ApplicationRunner runner(new tracing::TracingApp);
+ return runner.Run(shell_handle);
+}
diff --git a/chromium/services/tracing/manifest.json b/chromium/services/tracing/manifest.json
new file mode 100644
index 00000000000..a8197395b2b
--- /dev/null
+++ b/chromium/services/tracing/manifest.json
@@ -0,0 +1,16 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:tracing",
+ "display_name": "Tracing Collector",
+ "capabilities": {
+ "provided": {
+ "app": [
+ "tracing::TracingCollector",
+ "tracing::StartupPerformanceDataCollector"
+ ]
+ },
+ "required": {
+ "mojo:shell": { "classes": [ "shell:all_users" ] }
+ }
+ }
+}
diff --git a/chromium/services/tracing/public/cpp/BUILD.gn b/chromium/services/tracing/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..7fa6eab5d02
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/BUILD.gn
@@ -0,0 +1,21 @@
+# 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.
+
+source_set("cpp") {
+ sources = [
+ "switches.cc",
+ "switches.h",
+ "trace_provider_impl.cc",
+ "trace_provider_impl.h",
+ "tracing_impl.cc",
+ "tracing_impl.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ "//services/shell/public/cpp",
+ "//services/tracing/public/interfaces",
+ ]
+}
diff --git a/chromium/services/tracing/public/cpp/switches.cc b/chromium/services/tracing/public/cpp/switches.cc
new file mode 100644
index 00000000000..279c890708d
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/switches.cc
@@ -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.
+
+#include "services/tracing/public/cpp/switches.h"
+
+namespace tracing {
+
+// Specifies if the |StatsCollectionController| needs to be bound in html pages.
+// This binding happens on per-frame basis and hence can potentially be a
+// performance bottleneck. One should only enable it when running a test that
+// needs to access the provided statistics.
+const char kEnableStatsCollectionBindings[] =
+ "enable-stats-collection-bindings";
+
+const char kTraceStartup[] = "trace-startup";
+
+#ifdef NDEBUG
+const char kEarlyTracing[] = "early-tracing";
+#endif
+
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/switches.h b/chromium/services/tracing/public/cpp/switches.h
new file mode 100644
index 00000000000..b127d566a85
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/switches.h
@@ -0,0 +1,24 @@
+// 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 SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
+#define SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
+
+namespace tracing {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kEnableStatsCollectionBindings[];
+
+extern const char kTraceStartup[];
+
+#ifdef NDEBUG
+// In release builds, specifying this flag will force reporting of tracing
+// before the main Application is initialized.
+extern const char kEarlyTracing[];
+#endif
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
diff --git a/chromium/services/tracing/public/cpp/trace_provider_impl.cc b/chromium/services/tracing/public/cpp/trace_provider_impl.cc
new file mode 100644
index 00000000000..08a80110869
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/trace_provider_impl.cc
@@ -0,0 +1,102 @@
+// 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 "services/tracing/public/cpp/trace_provider_impl.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event.h"
+#include "services/shell/public/cpp/connection.h"
+
+namespace mojo {
+
+TraceProviderImpl::TraceProviderImpl()
+ : binding_(this), tracing_forced_(false), weak_factory_(this) {}
+
+TraceProviderImpl::~TraceProviderImpl() {
+ StopTracing();
+}
+
+void TraceProviderImpl::Bind(InterfaceRequest<tracing::TraceProvider> request) {
+ if (!binding_.is_bound()) {
+ binding_.Bind(std::move(request));
+ } else {
+ LOG(ERROR) << "Cannot accept two connections to TraceProvider.";
+ }
+}
+
+void TraceProviderImpl::StartTracing(const String& categories,
+ tracing::TraceRecorderPtr recorder) {
+ DCHECK(!recorder_);
+ recorder_ = std::move(recorder);
+ tracing_forced_ = false;
+ if (!base::trace_event::TraceLog::GetInstance()->IsEnabled()) {
+ std::string categories_str = categories.To<std::string>();
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceConfig(categories_str,
+ base::trace_event::RECORD_UNTIL_FULL),
+ base::trace_event::TraceLog::RECORDING_MODE);
+ }
+}
+
+void TraceProviderImpl::StopTracing() {
+ if (recorder_) {
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+
+ base::trace_event::TraceLog::GetInstance()->Flush(
+ base::Bind(&TraceProviderImpl::SendChunk, base::Unretained(this)));
+ }
+}
+
+void TraceProviderImpl::ForceEnableTracing() {
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ base::trace_event::TraceConfig("*", base::trace_event::RECORD_UNTIL_FULL),
+ base::trace_event::TraceLog::RECORDING_MODE);
+ tracing_forced_ = true;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&TraceProviderImpl::DelayedStop, weak_factory_.GetWeakPtr()));
+}
+
+void TraceProviderImpl::DelayedStop() {
+ // We use this indirection to account for cases where the Initialize app
+ // method (within which TraceProviderImpl is created) takes more than one
+ // second to finish; thus we start the countdown only when the current thread
+ // is unblocked.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&TraceProviderImpl::StopIfForced, weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(1));
+}
+
+void TraceProviderImpl::StopIfForced() {
+ if (!tracing_forced_) {
+ return;
+ }
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ base::trace_event::TraceLog::GetInstance()->Flush(
+ base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+ bool)>());
+}
+
+void TraceProviderImpl::SendChunk(
+ const scoped_refptr<base::RefCountedString>& events_str,
+ bool has_more_events) {
+ DCHECK(recorder_);
+ // The string will be empty if an error eccured or there were no trace
+ // events. Empty string is not a valid chunk to record so skip in this case.
+ if (!events_str->data().empty()) {
+ recorder_->Record(mojo::String(events_str->data()));
+ }
+ if (!has_more_events) {
+ recorder_.reset();
+ }
+}
+
+} // namespace mojo
diff --git a/chromium/services/tracing/public/cpp/trace_provider_impl.h b/chromium/services/tracing/public/cpp/trace_provider_impl.h
new file mode 100644
index 00000000000..975781b4a2e
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/trace_provider_impl.h
@@ -0,0 +1,51 @@
+// 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 SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
+#define SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+
+namespace mojo {
+
+class TraceProviderImpl : public tracing::TraceProvider {
+ public:
+ TraceProviderImpl();
+ ~TraceProviderImpl() override;
+
+ void Bind(InterfaceRequest<tracing::TraceProvider> request);
+
+ // Enable tracing without waiting for an inbound connection. It will stop if
+ // no TraceRecorder is sent within a set time.
+ void ForceEnableTracing();
+
+ private:
+ // tracing::TraceProvider implementation:
+ void StartTracing(const String& categories,
+ tracing::TraceRecorderPtr recorder) override;
+ void StopTracing() override;
+
+ void SendChunk(const scoped_refptr<base::RefCountedString>& events_str,
+ bool has_more_events);
+
+ void DelayedStop();
+ // Stop the collection of traces if no external connection asked for them yet.
+ void StopIfForced();
+
+ Binding<tracing::TraceProvider> binding_;
+ bool tracing_forced_;
+ tracing::TraceRecorderPtr recorder_;
+
+ base::WeakPtrFactory<TraceProviderImpl> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(TraceProviderImpl);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
diff --git a/chromium/services/tracing/public/cpp/tracing_impl.cc b/chromium/services/tracing/public/cpp/tracing_impl.cc
new file mode 100644
index 00000000000..6b6f68fb64f
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/tracing_impl.cc
@@ -0,0 +1,75 @@
+// 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 "services/tracing/public/cpp/tracing_impl.h"
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "services/shell/public/cpp/connector.h"
+
+#ifdef NDEBUG
+#include "base/command_line.h"
+#include "services/tracing/public/cpp/switches.h"
+#endif
+
+namespace mojo {
+namespace {
+
+// Controls access to |g_tracing_singleton_created|, which can be accessed from
+// different threads.
+base::LazyInstance<base::Lock>::Leaky g_singleton_lock =
+ LAZY_INSTANCE_INITIALIZER;
+
+// Whether we are the first TracingImpl to be created in this mojo
+// application. The first TracingImpl in a physical mojo application connects
+// to the mojo:tracing service.
+//
+// If this is a ContentHandler, it will outlive all its served Applications. If
+// this is a raw mojo application, it is the only Application served.
+bool g_tracing_singleton_created = false;
+
+}
+
+TracingImpl::TracingImpl() {
+}
+
+TracingImpl::~TracingImpl() {
+}
+
+void TracingImpl::Initialize(shell::Connector* connector,
+ const std::string& url) {
+ {
+ base::AutoLock lock(g_singleton_lock.Get());
+ if (g_tracing_singleton_created)
+ return;
+ g_tracing_singleton_created = true;
+ }
+
+ // This will only set the name for the first app in a loaded mojo file. It's
+ // up to something like CoreServices to name its own child threads.
+ base::PlatformThread::SetName(url);
+
+ connection_ = connector->Connect("mojo:tracing");
+ connection_->AddInterface(this);
+
+#ifdef NDEBUG
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ tracing::kEarlyTracing)) {
+ provider_impl_.ForceEnableTracing();
+ }
+#else
+ provider_impl_.ForceEnableTracing();
+#endif
+}
+
+void TracingImpl::Create(shell::Connection* connection,
+ InterfaceRequest<tracing::TraceProvider> request) {
+ provider_impl_.Bind(std::move(request));
+}
+
+} // namespace mojo
diff --git a/chromium/services/tracing/public/cpp/tracing_impl.h b/chromium/services/tracing/public/cpp/tracing_impl.h
new file mode 100644
index 00000000000..ed780e5ee42
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/tracing_impl.h
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
+#define SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
+
+#include "base/macros.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+
+namespace shell {
+class Connection;
+class Connector;
+}
+
+namespace mojo {
+
+// Connects to mojo:tracing during your Application's Initialize() call once
+// per process.
+//
+// We need to deal with multiple ways of packaging mojo applications
+// together. We'll need to deal with packages that use the mojo.ContentHandler
+// interface to bundle several Applciations into a single physical on disk
+// mojo binary, and with those same services each in their own mojo binary.
+//
+// Have your bundle ContentHandler own a TracingImpl, and each Application own
+// a TracingImpl. In bundles, the second TracingImpl will be a no-op.
+class TracingImpl : public shell::InterfaceFactory<tracing::TraceProvider> {
+ public:
+ TracingImpl();
+ ~TracingImpl() override;
+
+ // This connects to the tracing service and registers ourselves to provide
+ // tracing data on demand.
+ void Initialize(shell::Connector* connector, const std::string& url);
+
+ private:
+ // InterfaceFactory<tracing::TraceProvider> implementation.
+ void Create(shell::Connection* connection,
+ InterfaceRequest<tracing::TraceProvider> request) override;
+
+ std::unique_ptr<shell::Connection> connection_;
+ TraceProviderImpl provider_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingImpl);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
diff --git a/chromium/services/tracing/public/interfaces/BUILD.gn b/chromium/services/tracing/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..8323805231a
--- /dev/null
+++ b/chromium/services/tracing/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "tracing.mojom",
+ ]
+}
diff --git a/chromium/services/tracing/public/interfaces/OWNERS b/chromium/services/tracing/public/interfaces/OWNERS
new file mode 100644
index 00000000000..9e621796752
--- /dev/null
+++ b/chromium/services/tracing/public/interfaces/OWNERS
@@ -0,0 +1,13 @@
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=mkwst@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=palmer@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/chromium/services/tracing/public/interfaces/tracing.mojom b/chromium/services/tracing/public/interfaces/tracing.mojom
new file mode 100644
index 00000000000..b624f81e24f
--- /dev/null
+++ b/chromium/services/tracing/public/interfaces/tracing.mojom
@@ -0,0 +1,62 @@
+// 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.
+
+module tracing;
+
+// To participate in the tracing ecosystem, implement the TraceProvider
+// interface and connect to the tracing app. Then, when the provider's Start()
+// function is called collect tracing data and pass it back via the provided
+// TraceRecorder interface up until Stop() is called.
+
+interface TraceProvider {
+ // Categories can either be the empty string to mean the default set of
+ // categories or a comma-delimited list of categories to trace.
+ StartTracing(string categories, TraceRecorder recorder);
+ StopTracing();
+};
+
+interface TraceRecorder {
+ Record(string json);
+};
+
+interface TraceCollector {
+ // Request tracing data from all connected providers to stream to
+ // |stream|.
+ Start(handle<data_pipe_producer> stream, string categories);
+
+ // Stop tracing and flush results to the |stream| passed in to Start().
+ // Closes |stream| when all data is collected.
+ StopAndFlush();
+};
+
+// These times are used to determine startup performance metrics.
+// TODO(msw): Find a way to convert *_time metrics into TimeTicks earlier (ref:
+// https://goo.gl/vZ8dZW).
+struct StartupPerformanceTimes {
+ // TODO(msw): Rename to match "BrowserMainEntryTimeAbsolute" metric?
+ int64 shell_process_creation_time;
+ int64 shell_main_entry_point_time;
+ int64 browser_message_loop_start_ticks;
+ int64 browser_window_display_ticks;
+ int64 browser_open_tabs_time_delta;
+ // TODO(msw): Rename to avoid "web contents"?
+ int64 first_web_contents_main_frame_load_ticks;
+ // TODO(msw): Rename to match "FirstWebContents.NonEmptyPaint" metric?
+ int64 first_visually_non_empty_layout_ticks;
+};
+
+// This interface accepts startup performance timing from a variety of sources.
+interface StartupPerformanceDataCollector {
+ // These setters may be called many times, only the first time is recorded.
+ SetShellProcessCreationTime(int64 time);
+ SetShellMainEntryPointTime(int64 time);
+ SetBrowserMessageLoopStartTicks(int64 ticks);
+ SetBrowserWindowDisplayTicks(int64 ticks);
+ SetBrowserOpenTabsTimeDelta(int64 delta);
+ SetFirstWebContentsMainFrameLoadTicks(int64 ticks);
+ SetFirstVisuallyNonEmptyLayoutTicks(int64 ticks);
+
+ // Get the currently available startup performance times.
+ GetStartupPerformanceTimes() => (StartupPerformanceTimes times);
+};
diff --git a/chromium/services/tracing/trace_data_sink.cc b/chromium/services/tracing/trace_data_sink.cc
new file mode 100644
index 00000000000..b278956648b
--- /dev/null
+++ b/chromium/services/tracing/trace_data_sink.cc
@@ -0,0 +1,32 @@
+// 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 "services/tracing/trace_data_sink.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "mojo/common/data_pipe_utils.h"
+
+using mojo::common::BlockingCopyFromString;
+
+namespace tracing {
+
+TraceDataSink::TraceDataSink(mojo::ScopedDataPipeProducerHandle pipe)
+ : pipe_(std::move(pipe)), empty_(true) {}
+
+TraceDataSink::~TraceDataSink() {
+ if (pipe_.is_valid())
+ pipe_.reset();
+ DCHECK(!pipe_.is_valid());
+}
+
+void TraceDataSink::AddChunk(const std::string& json) {
+ if (!empty_)
+ BlockingCopyFromString(",", pipe_);
+ empty_ = false;
+ BlockingCopyFromString(json, pipe_);
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/trace_data_sink.h b/chromium/services/tracing/trace_data_sink.h
new file mode 100644
index 00000000000..6862faa08ba
--- /dev/null
+++ b/chromium/services/tracing/trace_data_sink.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef SERVICES_TRACING_TRACE_DATA_SINK_H_
+#define SERVICES_TRACING_TRACE_DATA_SINK_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+
+namespace tracing {
+
+class TraceDataSink {
+ public:
+ explicit TraceDataSink(mojo::ScopedDataPipeProducerHandle pipe);
+ ~TraceDataSink();
+
+ void AddChunk(const std::string& json);
+
+ private:
+ mojo::ScopedDataPipeProducerHandle pipe_;
+ bool empty_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceDataSink);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_TRACE_DATA_SINK_H_
diff --git a/chromium/services/tracing/trace_recorder_impl.cc b/chromium/services/tracing/trace_recorder_impl.cc
new file mode 100644
index 00000000000..f7057929bac
--- /dev/null
+++ b/chromium/services/tracing/trace_recorder_impl.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 "services/tracing/trace_recorder_impl.h"
+
+#include <utility>
+
+namespace tracing {
+
+TraceRecorderImpl::TraceRecorderImpl(
+ mojo::InterfaceRequest<TraceRecorder> request,
+ TraceDataSink* sink)
+ : sink_(sink), binding_(this, std::move(request)) {}
+
+TraceRecorderImpl::~TraceRecorderImpl() {
+}
+
+void TraceRecorderImpl::TryRead() {
+ binding_.WaitForIncomingMethodCall(MojoDeadline(0));
+}
+
+mojo::Handle TraceRecorderImpl::TraceRecorderHandle() const {
+ return binding_.handle();
+}
+
+void TraceRecorderImpl::Record(const mojo::String& json) {
+ sink_->AddChunk(json.To<std::string>());
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/trace_recorder_impl.h b/chromium/services/tracing/trace_recorder_impl.h
new file mode 100644
index 00000000000..2e63e31ce88
--- /dev/null
+++ b/chromium/services/tracing/trace_recorder_impl.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 SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
+#define SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/string.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/trace_data_sink.h"
+
+namespace tracing {
+
+class TraceRecorderImpl : public TraceRecorder {
+ public:
+ TraceRecorderImpl(mojo::InterfaceRequest<TraceRecorder> request,
+ TraceDataSink* sink);
+ ~TraceRecorderImpl() override;
+
+ // TryRead attempts to read a single chunk from the TraceRecorder pipe if one
+ // is available and passes it to the TraceDataSink. Returns immediately if no
+ // chunk is available.
+ void TryRead();
+
+ // TraceRecorderHandle returns the handle value of the TraceRecorder
+ // binding which can be used to wait until chunks are available.
+ mojo::Handle TraceRecorderHandle() const;
+
+ private:
+ // tracing::TraceRecorder implementation.
+ void Record(const mojo::String& json) override;
+
+ TraceDataSink* sink_;
+ mojo::Binding<TraceRecorder> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceRecorderImpl);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
diff --git a/chromium/services/tracing/tracing.gyp b/chromium/services/tracing/tracing.gyp
new file mode 100644
index 00000000000..38ff437c71f
--- /dev/null
+++ b/chromium/services/tracing/tracing.gyp
@@ -0,0 +1,61 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'tracing_interfaces',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ 'public/interfaces/tracing.mojom',
+ ],
+ 'mojom_include_path': '<(DEPTH)/mojo/services',
+ },
+ 'includes': [
+ '../../mojo/mojom_bindings_generator_explicit.gypi',
+ ],
+ },
+ {
+ # Technically, these should be in the mojo_services.gyp, but this causes
+ # a cycle since the ios generator can't have gyp files refer to each
+ # other, even if the targets don't form a cycle.
+ #
+ # GN version: //services/tracing:lib
+ 'target_name': 'tracing_lib',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'tracing_public',
+ '../../mojo/mojo_edk.gyp:mojo_system_impl',
+ '../shell/shell_public.gyp:shell_public',
+ ],
+ 'sources': [
+ 'trace_data_sink.cc',
+ 'trace_data_sink.h',
+ 'trace_recorder_impl.cc',
+ 'trace_recorder_impl.h',
+ 'tracing_app.cc',
+ 'tracing_app.h',
+ ],
+ },
+ {
+ # GN version: //mojo/services/public/cpp
+ 'target_name': 'tracing_public',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'tracing_interfaces',
+ '../../mojo/mojo_edk.gyp:mojo_system_impl',
+ '../shell/shell_public.gyp:shell_public',
+ ],
+ 'sources': [
+ 'public/cpp/switches.cc',
+ 'public/cpp/switches.h',
+ 'public/cpp/tracing_impl.cc',
+ 'public/cpp/tracing_impl.h',
+ 'public/cpp/trace_provider_impl.cc',
+ 'public/cpp/trace_provider_impl.h',
+ ],
+ },
+ ],
+}
diff --git a/chromium/services/tracing/tracing_app.cc b/chromium/services/tracing/tracing_app.cc
new file mode 100644
index 00000000000..2dff117753a
--- /dev/null
+++ b/chromium/services/tracing/tracing_app.cc
@@ -0,0 +1,186 @@
+// 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 "services/tracing/tracing_app.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+
+namespace tracing {
+
+TracingApp::TracingApp() : collector_binding_(this), tracing_active_(false) {
+}
+
+TracingApp::~TracingApp() {
+}
+
+bool TracingApp::AcceptConnection(shell::Connection* connection) {
+ connection->AddInterface<TraceCollector>(this);
+ connection->AddInterface<StartupPerformanceDataCollector>(this);
+
+ // If someone connects to us they may want to use the TraceCollector
+ // interface and/or they may want to expose themselves to be traced. Attempt
+ // to connect to the TraceProvider interface to see if the application
+ // connecting to us wants to be traced. They can refuse the connection or
+ // close the pipe if not.
+ TraceProviderPtr provider_ptr;
+ connection->GetInterface(&provider_ptr);
+ if (tracing_active_) {
+ TraceRecorderPtr recorder_ptr;
+ recorder_impls_.push_back(
+ new TraceRecorderImpl(GetProxy(&recorder_ptr), sink_.get()));
+ provider_ptr->StartTracing(tracing_categories_, std::move(recorder_ptr));
+ }
+ provider_ptrs_.AddPtr(std::move(provider_ptr));
+ return true;
+}
+
+bool TracingApp::ShellConnectionLost() {
+ // TODO(beng): This is only required because TracingApp isn't run by
+ // ApplicationRunner - instead it's launched automatically by the standalone
+ // shell. It shouldn't be.
+ base::MessageLoop::current()->QuitWhenIdle();
+ return false;
+}
+
+void TracingApp::Create(shell::Connection* connection,
+ mojo::InterfaceRequest<TraceCollector> request) {
+ collector_binding_.Bind(std::move(request));
+}
+
+void TracingApp::Create(
+ shell::Connection* connection,
+ mojo::InterfaceRequest<StartupPerformanceDataCollector> request) {
+ startup_performance_data_collector_bindings_.AddBinding(this,
+ std::move(request));
+}
+
+void TracingApp::Start(mojo::ScopedDataPipeProducerHandle stream,
+ const mojo::String& categories) {
+ tracing_categories_ = categories;
+ sink_.reset(new TraceDataSink(std::move(stream)));
+ provider_ptrs_.ForAllPtrs([categories, this](TraceProvider* controller) {
+ TraceRecorderPtr ptr;
+ recorder_impls_.push_back(
+ new TraceRecorderImpl(GetProxy(&ptr), sink_.get()));
+ controller->StartTracing(categories, std::move(ptr));
+ });
+ tracing_active_ = true;
+}
+
+void TracingApp::StopAndFlush() {
+ // Remove any collectors that closed their message pipes before we called
+ // StopTracing().
+ for (int i = static_cast<int>(recorder_impls_.size()) - 1; i >= 0; --i) {
+ if (!recorder_impls_[i]->TraceRecorderHandle().is_valid()) {
+ recorder_impls_.erase(recorder_impls_.begin() + i);
+ }
+ }
+
+ tracing_active_ = false;
+ provider_ptrs_.ForAllPtrs(
+ [](TraceProvider* controller) { controller->StopTracing(); });
+
+ // Sending the StopTracing message to registered controllers will request that
+ // they send trace data back via the collector interface and, when they are
+ // done, close the collector pipe. We don't know how long they will take. We
+ // want to read all data that any collector might send until all collectors or
+ // closed or an (arbitrary) deadline has passed. Since the bindings don't
+ // support this directly we do our own MojoWaitMany over the handles and read
+ // individual messages until all are closed or our absolute deadline has
+ // elapsed.
+ static const MojoDeadline kTimeToWaitMicros = 1000 * 1000;
+ MojoTimeTicks end = MojoGetTimeTicksNow() + kTimeToWaitMicros;
+
+ while (!recorder_impls_.empty()) {
+ MojoTimeTicks now = MojoGetTimeTicksNow();
+ if (now >= end) // Timed out?
+ break;
+
+ MojoDeadline mojo_deadline = end - now;
+ std::vector<mojo::Handle> handles;
+ std::vector<MojoHandleSignals> signals;
+ for (const auto& it : recorder_impls_) {
+ handles.push_back(it->TraceRecorderHandle());
+ signals.push_back(MOJO_HANDLE_SIGNAL_READABLE |
+ MOJO_HANDLE_SIGNAL_PEER_CLOSED);
+ }
+ std::vector<MojoHandleSignalsState> signals_states(signals.size());
+ const mojo::WaitManyResult wait_many_result =
+ mojo::WaitMany(handles, signals, mojo_deadline, &signals_states);
+ if (wait_many_result.result == MOJO_RESULT_DEADLINE_EXCEEDED) {
+ // Timed out waiting, nothing more to read.
+ LOG(WARNING) << "Timed out waiting for trace flush";
+ break;
+ }
+ if (wait_many_result.IsIndexValid()) {
+ // Iterate backwards so we can remove closed pipes from |recorder_impls_|
+ // without invalidating subsequent offsets.
+ for (size_t i = signals_states.size(); i != 0; --i) {
+ size_t index = i - 1;
+ MojoHandleSignals satisfied = signals_states[index].satisfied_signals;
+ // To avoid dropping data, don't close unless there's no
+ // readable signal.
+ if (satisfied & MOJO_HANDLE_SIGNAL_READABLE)
+ recorder_impls_[index]->TryRead();
+ else if (satisfied & MOJO_HANDLE_SIGNAL_PEER_CLOSED)
+ recorder_impls_.erase(recorder_impls_.begin() + index);
+ }
+ }
+ }
+ AllDataCollected();
+}
+
+void TracingApp::SetShellProcessCreationTime(int64_t time) {
+ if (startup_performance_times_.shell_process_creation_time == 0)
+ startup_performance_times_.shell_process_creation_time = time;
+}
+
+void TracingApp::SetShellMainEntryPointTime(int64_t time) {
+ if (startup_performance_times_.shell_main_entry_point_time == 0)
+ startup_performance_times_.shell_main_entry_point_time = time;
+}
+
+void TracingApp::SetBrowserMessageLoopStartTicks(int64_t ticks) {
+ if (startup_performance_times_.browser_message_loop_start_ticks == 0)
+ startup_performance_times_.browser_message_loop_start_ticks = ticks;
+}
+
+void TracingApp::SetBrowserWindowDisplayTicks(int64_t ticks) {
+ if (startup_performance_times_.browser_window_display_ticks == 0)
+ startup_performance_times_.browser_window_display_ticks = ticks;
+}
+
+void TracingApp::SetBrowserOpenTabsTimeDelta(int64_t delta) {
+ if (startup_performance_times_.browser_open_tabs_time_delta == 0)
+ startup_performance_times_.browser_open_tabs_time_delta = delta;
+}
+
+void TracingApp::SetFirstWebContentsMainFrameLoadTicks(int64_t ticks) {
+ if (startup_performance_times_.first_web_contents_main_frame_load_ticks == 0)
+ startup_performance_times_.first_web_contents_main_frame_load_ticks = ticks;
+}
+
+void TracingApp::SetFirstVisuallyNonEmptyLayoutTicks(int64_t ticks) {
+ if (startup_performance_times_.first_visually_non_empty_layout_ticks == 0)
+ startup_performance_times_.first_visually_non_empty_layout_ticks = ticks;
+}
+
+void TracingApp::GetStartupPerformanceTimes(
+ const GetStartupPerformanceTimesCallback& callback) {
+ callback.Run(startup_performance_times_.Clone());
+}
+
+void TracingApp::AllDataCollected() {
+ recorder_impls_.clear();
+ sink_.reset();
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/tracing_app.h b/chromium/services/tracing/tracing_app.h
new file mode 100644
index 00000000000..6ba6bfd49ad
--- /dev/null
+++ b/chromium/services/tracing/tracing_app.h
@@ -0,0 +1,82 @@
+// 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 SERVICES_TRACING_TRACING_APP_H_
+#define SERVICES_TRACING_TRACING_APP_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/trace_data_sink.h"
+#include "services/tracing/trace_recorder_impl.h"
+
+namespace tracing {
+
+class TracingApp
+ : public shell::ShellClient,
+ public shell::InterfaceFactory<TraceCollector>,
+ public TraceCollector,
+ public shell::InterfaceFactory<StartupPerformanceDataCollector>,
+ public StartupPerformanceDataCollector {
+ public:
+ TracingApp();
+ ~TracingApp() override;
+
+ private:
+ // shell::ShellClient implementation.
+ bool AcceptConnection(shell::Connection* connection) override;
+ bool ShellConnectionLost() override;
+
+ // shell::InterfaceFactory<TraceCollector> implementation.
+ void Create(shell::Connection* connection,
+ mojo::InterfaceRequest<TraceCollector> request) override;
+
+ // shell::InterfaceFactory<StartupPerformanceDataCollector> implementation.
+ void Create(
+ shell::Connection* connection,
+ mojo::InterfaceRequest<StartupPerformanceDataCollector> request) override;
+
+ // tracing::TraceCollector implementation.
+ void Start(mojo::ScopedDataPipeProducerHandle stream,
+ const mojo::String& categories) override;
+ void StopAndFlush() override;
+
+ // StartupPerformanceDataCollector implementation.
+ void SetShellProcessCreationTime(int64_t time) override;
+ void SetShellMainEntryPointTime(int64_t time) override;
+ void SetBrowserMessageLoopStartTicks(int64_t ticks) override;
+ void SetBrowserWindowDisplayTicks(int64_t ticks) override;
+ void SetBrowserOpenTabsTimeDelta(int64_t delta) override;
+ void SetFirstWebContentsMainFrameLoadTicks(int64_t ticks) override;
+ void SetFirstVisuallyNonEmptyLayoutTicks(int64_t ticks) override;
+ void GetStartupPerformanceTimes(
+ const GetStartupPerformanceTimesCallback& callback) override;
+
+ void AllDataCollected();
+
+ std::unique_ptr<TraceDataSink> sink_;
+ ScopedVector<TraceRecorderImpl> recorder_impls_;
+ mojo::InterfacePtrSet<TraceProvider> provider_ptrs_;
+ mojo::Binding<TraceCollector> collector_binding_;
+ mojo::BindingSet<StartupPerformanceDataCollector>
+ startup_performance_data_collector_bindings_;
+ StartupPerformanceTimes startup_performance_times_;
+ bool tracing_active_;
+ mojo::String tracing_categories_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingApp);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_TRACING_APP_H_
diff --git a/chromium/services/user/BUILD.gn b/chromium/services/user/BUILD.gn
new file mode 100644
index 00000000000..d30ff4660ef
--- /dev/null
+++ b/chromium/services/user/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+
+source_set("lib") {
+ sources = [
+ "user_id_map.cc",
+ "user_id_map.h",
+ "user_service.cc",
+ "user_service.h",
+ "user_shell_client.cc",
+ "user_shell_client.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/filesystem:lib",
+ "//components/filesystem/public/interfaces",
+ "//components/leveldb:lib",
+ "//components/leveldb/public/interfaces",
+ "//mojo/common",
+ "//mojo/common:common_base",
+ "//mojo/platform_handle",
+ "//services/shell/public/cpp",
+ "//services/shell/public/interfaces",
+ "//services/tracing/public/cpp",
+ "//services/user/public/interfaces",
+ "//url",
+ ]
+
+ data_deps = [
+ ":manifest",
+ ]
+}
+
+mojo_application_manifest("manifest") {
+ application_name = "user"
+ source = "manifest.json"
+}
diff --git a/chromium/services/user/DEPS b/chromium/services/user/DEPS
new file mode 100644
index 00000000000..5f2952d7211
--- /dev/null
+++ b/chromium/services/user/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/filesystem",
+ "+components/leveldb",
+ "+services/tracing/public/cpp",
+]
diff --git a/chromium/services/user/OWNERS b/chromium/services/user/OWNERS
new file mode 100644
index 00000000000..4733a4f06bf
--- /dev/null
+++ b/chromium/services/user/OWNERS
@@ -0,0 +1 @@
+erg@chromium.org
diff --git a/chromium/services/user/manifest.json b/chromium/services/user/manifest.json
new file mode 100644
index 00000000000..246d3922147
--- /dev/null
+++ b/chromium/services/user/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 1,
+ "name": "mojo:user",
+ "process-group": "browser",
+ "display_name": "User Service",
+ "capabilities": {
+ "required": {
+ "*": { "classes": [ "app" ] }
+ }
+ }
+}
diff --git a/chromium/services/user/public/cpp/BUILD.gn b/chromium/services/user/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..f341a18b19a
--- /dev/null
+++ b/chromium/services/user/public/cpp/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+source_set("cpp") {
+ sources = [
+ "constants.cc",
+ "constants.h",
+ ]
+}
diff --git a/chromium/services/user/public/cpp/constants.cc b/chromium/services/user/public/cpp/constants.cc
new file mode 100644
index 00000000000..963fb12375e
--- /dev/null
+++ b/chromium/services/user/public/cpp/constants.cc
@@ -0,0 +1,11 @@
+// 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 "services/user/public/cpp/constants.h"
+
+namespace user_service {
+
+const char kUserServiceName[] = "mojo:user";
+
+} // namespace user_service
diff --git a/chromium/services/user/public/cpp/constants.h b/chromium/services/user/public/cpp/constants.h
new file mode 100644
index 00000000000..64a18c2b5df
--- /dev/null
+++ b/chromium/services/user/public/cpp/constants.h
@@ -0,0 +1,14 @@
+// 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 SERVICES_USER_PUBLIC_CPP_CONSTANTS_H_
+#define SERVICES_USER_PUBLIC_CPP_CONSTANTS_H_
+
+namespace user_service {
+
+extern const char kUserServiceName[];
+
+} // namespace user_service
+
+#endif // SERVICES_USER_PUBLIC_CPP_CONSTANTS_H_
diff --git a/chromium/services/user/public/interfaces/BUILD.gn b/chromium/services/user/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..0f2415baa1d
--- /dev/null
+++ b/chromium/services/user/public/interfaces/BUILD.gn
@@ -0,0 +1,15 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "user_service.mojom",
+ ]
+
+ deps = [
+ "//components/filesystem/public/interfaces",
+ ]
+}
diff --git a/chromium/services/user/public/interfaces/OWNERS b/chromium/services/user/public/interfaces/OWNERS
new file mode 100644
index 00000000000..9e621796752
--- /dev/null
+++ b/chromium/services/user/public/interfaces/OWNERS
@@ -0,0 +1,13 @@
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=mkwst@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=palmer@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/chromium/services/user/public/interfaces/user_service.mojom b/chromium/services/user/public/interfaces/user_service.mojom
new file mode 100644
index 00000000000..f1cf6337d07
--- /dev/null
+++ b/chromium/services/user/public/interfaces/user_service.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module user_service.mojom;
+
+import "components/filesystem/public/interfaces/directory.mojom";
+import "components/filesystem/public/interfaces/types.mojom";
+
+// An encapsulation around the per-profile storage.
+//
+// TODO(erg): An instance of UserService should be strongly bound to a specific
+// user id; eventually during startup of the User Service process, we sandbox
+// the process so the only directory it has access to is the user's directory.
+interface UserService {
+ // Returns the user profile directory.
+ GetDirectory(filesystem.mojom.Directory& dir) => ();
+
+ // Returns a subdirectory under the profile dir. Returns a filesystem error
+ // when we fail to create the subdirectory.
+ GetSubDirectory(string dir_path, filesystem.mojom.Directory& dir)
+ => (filesystem.mojom.FileError err);
+};
diff --git a/chromium/services/user/user.gyp b/chromium/services/user/user.gyp
new file mode 100644
index 00000000000..328fc6cf1db
--- /dev/null
+++ b/chromium/services/user/user.gyp
@@ -0,0 +1,95 @@
+# 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.
+
+{
+ 'variables': {
+ # This turns on e.g. the filename-based detection of which
+ # platforms to include source files on (e.g. files ending in
+ # _mac.h or _mac.cc are only compiled on MacOSX).
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ # GN version: //services/user:lib
+ 'target_name': 'user_service_lib',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'user_id_map.cc',
+ 'user_id_map.h',
+ 'user_service.cc',
+ 'user_service.h',
+ 'user_shell_client.cc',
+ 'user_shell_client.h',
+ ],
+ 'dependencies': [
+ 'user_app_manifest',
+ 'user_service_bindings',
+ '../../base/base.gyp:base',
+ '../../components/filesystem/filesystem.gyp:filesystem_lib',
+ '../../components/leveldb/leveldb.gyp:leveldb_lib',
+ '../../services/shell/shell_public.gyp:shell_public',
+ '../../services/tracing/tracing.gyp:tracing_lib',
+ '../../mojo/mojo_edk.gyp:mojo_system_impl',
+ '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '../../mojo/mojo_platform_handle.gyp:platform_handle',
+ '../../url/url.gyp:url_lib',
+ ],
+ 'export_dependent_settings': [
+ 'user_service_bindings',
+ ],
+ },
+ {
+ # GN version: //services/user/public/interfaces
+ 'target_name': 'user_service_bindings',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'user_service_bindings_mojom',
+ ],
+ },
+ {
+ 'target_name': 'user_service_bindings_mojom',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ 'public/interfaces/user_service.mojom',
+ ],
+ },
+ 'dependencies': [
+ '../../components/filesystem/filesystem.gyp:filesystem_bindings_mojom',
+ '../../components/leveldb/leveldb.gyp:leveldb_bindings_mojom',
+ ],
+ 'includes': [
+ '../../mojo/mojom_bindings_generator_explicit.gypi',
+ ],
+ },
+ {
+ 'target_name': 'user_service_public_lib',
+ 'type': 'static_library',
+ 'sources': [
+ 'public/cpp/constants.cc',
+ 'public/cpp/constants.h',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ },
+ {
+ # GN version: //services/user:manifest
+ 'target_name': 'user_app_manifest',
+ 'type': 'none',
+ 'variables': {
+ 'application_type': 'mojo',
+ 'application_name': 'user',
+ 'source_manifest': '<(DEPTH)/services/user/manifest.json',
+ },
+ 'includes': [
+ '../../mojo/public/mojo_application_manifest.gypi',
+ ],
+ 'hard_dependency': 1,
+ },
+ ],
+}
diff --git a/chromium/services/user/user_id_map.cc b/chromium/services/user/user_id_map.cc
new file mode 100644
index 00000000000..0195f96b432
--- /dev/null
+++ b/chromium/services/user/user_id_map.cc
@@ -0,0 +1,29 @@
+// 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 "services/user/user_id_map.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+
+namespace user_service {
+
+namespace {
+base::LazyInstance<std::map<std::string, base::FilePath>>
+ g_user_id_to_data_dir = LAZY_INSTANCE_INITIALIZER;
+} // namespace
+
+void AssociateMojoUserIDWithUserDir(const std::string& user_id,
+ const base::FilePath& user_dir) {
+ g_user_id_to_data_dir.Get()[user_id] = user_dir;
+}
+
+base::FilePath GetUserDirForUserID(const std::string& user_id) {
+ auto it = g_user_id_to_data_dir.Get().find(user_id);
+ DCHECK(it != g_user_id_to_data_dir.Get().end());
+ return it->second;
+}
+
+} // namespace user_service
diff --git a/chromium/services/user/user_id_map.h b/chromium/services/user/user_id_map.h
new file mode 100644
index 00000000000..217a15c6189
--- /dev/null
+++ b/chromium/services/user/user_id_map.h
@@ -0,0 +1,31 @@
+// 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 SERVICES_USER_USER_ID_MAP_H_
+#define SERVICES_USER_USER_ID_MAP_H_
+
+#include <string>
+#include "base/files/file_path.h"
+
+namespace user_service {
+
+// Currently, UserApp is run from within the chrome process. This means that
+// the ApplicationLoader is registered during MojoShellContext startup, even
+// though the application itself is not started. As soon as a BrowserContext is
+// created, the BrowserContext will choose a |user_id| for itself and call us
+// to register the mapping from |user_id| to |user_dir|.
+//
+// This data is then accessed when we get our Initialize() call.
+//
+// TODO(erg): This is a temporary hack until we redo how we initialize mojo
+// applications inside of chrome in general; this system won't work once
+// UserApp gets put in its own sandboxed process.
+void AssociateMojoUserIDWithUserDir(const std::string& user_id,
+ const base::FilePath& user_dir);
+
+base::FilePath GetUserDirForUserID(const std::string& user_id);
+
+} // namespace user_service
+
+#endif // SERVICES_USER_USER_ID_MAP_H_
diff --git a/chromium/services/user/user_service.cc b/chromium/services/user/user_service.cc
new file mode 100644
index 00000000000..59d91107fcf
--- /dev/null
+++ b/chromium/services/user/user_service.cc
@@ -0,0 +1,57 @@
+// 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 "services/user/user_service.h"
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/filesystem/directory_impl.h"
+#include "components/filesystem/lock_table.h"
+#include "components/filesystem/public/interfaces/types.mojom.h"
+#include "services/shell/public/cpp/connection.h"
+
+namespace user_service {
+
+UserService::UserService(const base::FilePath& base_user_dir,
+ const scoped_refptr<filesystem::LockTable>& lock_table)
+ : lock_table_(lock_table), path_(base_user_dir) {
+ base::CreateDirectory(path_);
+}
+
+UserService::~UserService() {}
+
+void UserService::GetDirectory(filesystem::mojom::DirectoryRequest request,
+ const GetDirectoryCallback& callback) {
+ new filesystem::DirectoryImpl(std::move(request), path_,
+ scoped_refptr<filesystem::SharedTempDir>(),
+ lock_table_);
+ callback.Run();
+}
+
+void UserService::GetSubDirectory(const mojo::String& sub_directory_path,
+ filesystem::mojom::DirectoryRequest request,
+ const GetSubDirectoryCallback& callback) {
+ // Ensure that we've made |subdirectory| recursively under our user dir.
+ base::FilePath subdir = path_.Append(
+#if defined(OS_WIN)
+ base::UTF8ToWide(sub_directory_path.To<std::string>()));
+#else
+ sub_directory_path.To<std::string>());
+#endif
+ base::File::Error error;
+ if (!base::CreateDirectoryAndGetError(subdir, &error)) {
+ callback.Run(static_cast<filesystem::mojom::FileError>(error));
+ return;
+ }
+
+ new filesystem::DirectoryImpl(std::move(request), subdir,
+ scoped_refptr<filesystem::SharedTempDir>(),
+ lock_table_);
+ callback.Run(filesystem::mojom::FileError::OK);
+}
+
+} // namespace user_service
diff --git a/chromium/services/user/user_service.h b/chromium/services/user/user_service.h
new file mode 100644
index 00000000000..2aeee76f5be
--- /dev/null
+++ b/chromium/services/user/user_service.h
@@ -0,0 +1,44 @@
+// 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 SERVICES_USER_USER_SERVICE_IMPL_H_
+#define SERVICES_USER_USER_SERVICE_IMPL_H_
+
+#include "base/files/file_path.h"
+#include "components/filesystem/public/interfaces/directory.mojom.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/user/public/interfaces/user_service.mojom.h"
+
+namespace filesystem {
+class LockTable;
+}
+
+namespace user_service {
+
+// A service which serves directories to callers.
+class UserService : public mojom::UserService {
+ public:
+ UserService(const base::FilePath& base_user_dir,
+ const scoped_refptr<filesystem::LockTable>& lock_table);
+ ~UserService() override;
+
+ // Overridden from mojom::UserService:
+ void GetDirectory(filesystem::mojom::DirectoryRequest request,
+ const GetDirectoryCallback& callback) override;
+ void GetSubDirectory(const mojo::String& sub_directory_path,
+ filesystem::mojom::DirectoryRequest request,
+ const GetSubDirectoryCallback& callback) override;
+
+ private:
+ scoped_refptr<filesystem::LockTable> lock_table_;
+ base::FilePath path_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserService);
+};
+
+} // namespace user_service
+
+#endif // SERVICES_USER_USER_SERVICE_IMPL_H_
diff --git a/chromium/services/user/user_shell_client.cc b/chromium/services/user/user_shell_client.cc
new file mode 100644
index 00000000000..bd20927959b
--- /dev/null
+++ b/chromium/services/user/user_shell_client.cc
@@ -0,0 +1,126 @@
+// 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 "services/user/user_shell_client.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "components/filesystem/lock_table.h"
+#include "components/leveldb/leveldb_service_impl.h"
+#include "mojo/public/cpp/bindings/callback.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/user/user_id_map.h"
+#include "services/user/user_service.h"
+
+namespace user_service {
+
+class UserShellClient::UserServiceObjects
+ : public base::SupportsWeakPtr<UserServiceObjects> {
+ public:
+ // Created on the main thread.
+ UserServiceObjects(base::FilePath user_dir) : user_dir_(user_dir) {}
+
+ // Destroyed on the |user_service_runner_|.
+ ~UserServiceObjects() {}
+
+ // Called on the |user_service_runner_|.
+ void OnUserServiceRequest(shell::Connection* connection,
+ mojom::UserServiceRequest request) {
+ if (!lock_table_)
+ lock_table_ = new filesystem::LockTable;
+ user_service_bindings_.AddBinding(new UserService(user_dir_, lock_table_),
+ std::move(request));
+ }
+
+ private:
+ mojo::BindingSet<mojom::UserService> user_service_bindings_;
+ scoped_refptr<filesystem::LockTable> lock_table_;
+ base::FilePath user_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserServiceObjects);
+};
+
+class UserShellClient::LevelDBServiceObjects
+ : public base::SupportsWeakPtr<LevelDBServiceObjects> {
+ public:
+ // Created on the main thread.
+ LevelDBServiceObjects(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+
+ // Destroyed on the |leveldb_service_runner_|.
+ ~LevelDBServiceObjects() {}
+
+ // Called on the |leveldb_service_runner_|.
+ void OnLevelDBServiceRequest(shell::Connection* connection,
+ leveldb::mojom::LevelDBServiceRequest request) {
+ if (!leveldb_service_)
+ leveldb_service_.reset(new leveldb::LevelDBServiceImpl(task_runner_));
+ leveldb_bindings_.AddBinding(leveldb_service_.get(), std::move(request));
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Variables that are only accessible on the |leveldb_service_runner_| thread.
+ std::unique_ptr<leveldb::mojom::LevelDBService> leveldb_service_;
+ mojo::BindingSet<leveldb::mojom::LevelDBService> leveldb_bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(LevelDBServiceObjects);
+};
+
+std::unique_ptr<shell::ShellClient> CreateUserShellClient(
+ scoped_refptr<base::SingleThreadTaskRunner> user_service_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner,
+ const base::Closure& quit_closure) {
+ return base::WrapUnique(new UserShellClient(
+ std::move(user_service_runner), std::move(leveldb_service_runner)));
+}
+
+UserShellClient::UserShellClient(
+ scoped_refptr<base::SingleThreadTaskRunner> user_service_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner)
+ : user_service_runner_(std::move(user_service_runner)),
+ leveldb_service_runner_(std::move(leveldb_service_runner)) {}
+
+UserShellClient::~UserShellClient() {
+ user_service_runner_->DeleteSoon(FROM_HERE, user_objects_.release());
+ leveldb_service_runner_->DeleteSoon(FROM_HERE, leveldb_objects_.release());
+}
+
+void UserShellClient::Initialize(shell::Connector* connector,
+ const shell::Identity& identity,
+ uint32_t id) {
+ user_objects_.reset(new UserShellClient::UserServiceObjects(
+ GetUserDirForUserID(identity.user_id())));
+ leveldb_objects_.reset(
+ new UserShellClient::LevelDBServiceObjects(leveldb_service_runner_));
+}
+
+bool UserShellClient::AcceptConnection(shell::Connection* connection) {
+ connection->AddInterface<leveldb::mojom::LevelDBService>(this);
+ connection->AddInterface<mojom::UserService>(this);
+ return true;
+}
+
+void UserShellClient::Create(shell::Connection* connection,
+ mojom::UserServiceRequest request) {
+ user_service_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UserShellClient::UserServiceObjects::OnUserServiceRequest,
+ user_objects_->AsWeakPtr(), connection,
+ base::Passed(&request)));
+}
+
+void UserShellClient::Create(shell::Connection* connection,
+ leveldb::mojom::LevelDBServiceRequest request) {
+ leveldb_service_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &UserShellClient::LevelDBServiceObjects::OnLevelDBServiceRequest,
+ leveldb_objects_->AsWeakPtr(), connection,
+ base::Passed(&request)));
+}
+
+} // namespace user_service
diff --git a/chromium/services/user/user_shell_client.h b/chromium/services/user/user_shell_client.h
new file mode 100644
index 00000000000..205e4168e98
--- /dev/null
+++ b/chromium/services/user/user_shell_client.h
@@ -0,0 +1,68 @@
+// 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 SERVICES_USER_USER_SHELL_CLIENT_H_
+#define SERVICES_USER_USER_SHELL_CLIENT_H_
+
+#include "base/memory/ref_counted.h"
+#include "components/filesystem/lock_table.h"
+#include "components/leveldb/public/interfaces/leveldb.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/user/public/interfaces/user_service.mojom.h"
+
+namespace user_service {
+
+std::unique_ptr<shell::ShellClient> CreateUserShellClient(
+ scoped_refptr<base::SingleThreadTaskRunner> user_service_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner,
+ const base::Closure& quit_closure);
+
+class UserShellClient
+ : public shell::ShellClient,
+ public shell::InterfaceFactory<mojom::UserService>,
+ public shell::InterfaceFactory<leveldb::mojom::LevelDBService> {
+ public:
+ UserShellClient(
+ scoped_refptr<base::SingleThreadTaskRunner> user_service_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner);
+ ~UserShellClient() override;
+
+ private:
+ // |ShellClient| override:
+ void Initialize(shell::Connector* connector,
+ const shell::Identity& identity,
+ uint32_t id) override;
+ bool AcceptConnection(shell::Connection* connection) override;
+
+ // |InterfaceFactory<mojom::UserService>| implementation:
+ void Create(shell::Connection* connection,
+ mojom::UserServiceRequest request) override;
+
+ // |InterfaceFactory<LevelDBService>| implementation:
+ void Create(shell::Connection* connection,
+ leveldb::mojom::LevelDBServiceRequest request) override;
+
+ void OnLevelDBServiceRequest(shell::Connection* connection,
+ leveldb::mojom::LevelDBServiceRequest request);
+ void OnLevelDBServiceError();
+
+ scoped_refptr<base::SingleThreadTaskRunner> user_service_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner_;
+
+ // We create these two objects so we can delete them on the correct task
+ // runners.
+ class UserServiceObjects;
+ std::unique_ptr<UserServiceObjects> user_objects_;
+
+ class LevelDBServiceObjects;
+ std::unique_ptr<LevelDBServiceObjects> leveldb_objects_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserShellClient);
+};
+
+} // namespace user_service
+
+#endif // SERVICES_USER_USER_SHELL_CLIENT_H_