[CrOS MultiDevice] Create a skeleton MultiDeviceSetup service.
See go/unified-better-together-cros for an outline of this service.
This CL does the following:
(1) Creates a Mojo interface for the service, adding only a single
function for now.
(2) Creates the MultiDeviceSetupService and MultiDeviceSetupImpl classes
which implement this interface, as well as a test for the service.
(3) Registers the service in the browser process via ProfileImpl.
(4) Generates JavaScript files for the interface; because these files
are the first resources generated in //chromeos, this CL also adds a
new chromeos_resources.grd.
(5) Adds the new "multidevice_setup" capability to the content_browser
manifest file so that it can be used by content_renderer.
(6) Adds a new button on the chrome://proximity-auth debug WebUI page
which makes a Mojo call to the service.
Change-Id: I0b74373b78a1c92fe01d789028342707321c2134
Reviewed-on: https://chromium-review.googlesource.com/954010
Reviewed-by: Steven Bennetts <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: agrieve <[email protected]>
Reviewed-by: anthonyvd <[email protected]>
Reviewed-by: Ken Rockot <[email protected]>
Commit-Queue: Kyle Horimoto <[email protected]>
Cr-Commit-Position: refs/heads/master@{#543894}
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index f4c072e4..e8a76552 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -644,8 +644,8 @@
":power_manager_proto",
":test_support",
":test_support_without_gmock",
- "//base/test:run_all_unittests",
"//base/test:test_support",
+ "//chromeos/services:unit_tests",
"//components/onc",
"//components/prefs:test_support",
"//components/proxy_config",
@@ -655,6 +655,7 @@
"//dbus:test_support",
"//google_apis",
"//media/base:video_facing",
+ "//mojo/edk",
"//net",
"//net:test_support",
"//testing/gmock",
@@ -736,6 +737,7 @@
"printing/printer_translator_unittest.cc",
"process_proxy/process_output_watcher_unittest.cc",
"process_proxy/process_proxy_unittest.cc",
+ "run_all_unittests.cc",
"settings/timezone_settings_unittest.cc",
"system/cpu_temperature_reader_unittest.cc",
"system/name_value_pairs_parser_unittest.cc",
diff --git a/chromeos/DEPS b/chromeos/DEPS
index abc781f..775ac1a9 100644
--- a/chromeos/DEPS
+++ b/chromeos/DEPS
@@ -10,6 +10,7 @@
"+components/user_manager/known_user.h",
"+crypto",
"+media/base/video_facing.h",
+ "+mojo/edk/embedder/embedder.h",
"+net",
"+third_party/cros_system_api",
"+third_party/protobuf",
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn
index 7b111253..636f4bc 100644
--- a/chromeos/components/BUILD.gn
+++ b/chromeos/components/BUILD.gn
@@ -16,7 +16,6 @@
deps = [
"//base",
"//base/test:test_support",
- "//chromeos/components/multidevice_setup:unit_tests",
"//chromeos/components/tether:unit_tests",
]
}
diff --git a/chromeos/components/multidevice_setup/BUILD.gn b/chromeos/components/multidevice_setup/BUILD.gn
deleted file mode 100644
index 12b843b..0000000
--- a/chromeos/components/multidevice_setup/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2018 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.
-
-assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
-
-static_library("multidevice_setup") {
- sources = []
-
- deps = [
- "//base",
- ]
-}
-
-static_library("test_support") {
- testonly = true
-
- sources = []
-
- public_deps = [
- ":multidevice_setup",
- ]
-
- deps = [
- "//base",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
-
- sources = []
-
- deps = [
- ":multidevice_setup",
- ":test_support",
- "//base/test:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
diff --git a/chromeos/components/multidevice_setup/DEPS b/chromeos/components/multidevice_setup/DEPS
deleted file mode 100644
index 48e88750..0000000
--- a/chromeos/components/multidevice_setup/DEPS
+++ /dev/null
@@ -1,2 +0,0 @@
-include_rules = [
-]
diff --git a/chromeos/components/multidevice_setup/OWNERS b/chromeos/components/multidevice_setup/OWNERS
deleted file mode 100644
index 1d672ca..0000000
--- a/chromeos/components/multidevice_setup/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
[email protected]
[email protected]
-
-# COMPONENT: UI>ProximityAuth
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn
new file mode 100644
index 0000000..4b64e4e5
--- /dev/null
+++ b/chromeos/resources/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2018 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("//tools/grit/grit_rule.gni")
+
+assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
+
+grit("resources") {
+ source = "chromeos_resources.grd"
+
+ source_is_generated = true
+
+ outputs = [
+ "grit/chromeos_resources.h",
+ "chromeos_resources.pak",
+ ]
+ output_dir = "$root_gen_dir/chromeos"
+
+ grit_flags = [
+ "-E",
+ "mojom_root=" + rebase_path(root_gen_dir, root_build_dir),
+ ]
+
+ deps = [
+ "//chromeos/services/multidevice_setup/public/mojom:mojom_js",
+ ]
+}
diff --git a/chromeos/resources/chromeos_resources.grd b/chromeos/resources/chromeos_resources.grd
new file mode 100644
index 0000000..169869e
--- /dev/null
+++ b/chromeos/resources/chromeos_resources.grd
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+ <outputs>
+ <output filename="grit/chromeos_resources.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="chromeos_resources.pak" type="data_package" />
+ </outputs>
+ <release seq="1">
+ <includes>
+ <include name="IDR_MULTIDEVICE_SETUP_MOJOM_JS"
+ file="${mojom_root}/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.js"
+ use_base_dir="false"
+ type="BINDATA" />
+ <include name="IDR_MULTIDEVICE_SETUP_CONSTANTS_MOJOM_JS"
+ file="${mojom_root}/chromeos/services/multidevice_setup/public/mojom/constants.mojom.js"
+ use_base_dir="false"
+ type="BINDATA" />
+ </includes>
+ </release>
+</grit>
diff --git a/chromeos/run_all_unittests.cc b/chromeos/run_all_unittests.cc
new file mode 100644
index 0000000..3efc1c0
--- /dev/null
+++ b/chromeos/run_all_unittests.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/edk/embedder/embedder.h"
+
+int main(int argc, char** argv) {
+ // Some unit tests make Mojo calls.
+ 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/chromeos/services/BUILD.gn b/chromeos/services/BUILD.gn
index 5e25e1ff..32bf290 100644
--- a/chromeos/services/BUILD.gn
+++ b/chromeos/services/BUILD.gn
@@ -8,14 +8,29 @@
import("//services/service_manager/public/tools/test/service_test.gni")
import("//testing/test.gni")
-# This is modeled after //services:services_unittests
-# One Big Target for services to register their unit test sources. This exists
-# to avoid having to maintain a separate test binary for every service.
+assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
+
+# Use this target for adding new unit tests. To add a unit test to this target,
+# create a "unit_tests" source_set in your service and add it as a dependency
+# here.
#
-# To add tests for a new service, please define a "tests" source_set in the
-# service subdirectory and add it as a dependency here. If your unit tests
-# use the ServiceTest framework, you must also include corresponding catalog
-# entries in the "chromeos_services_unittests_catalog" target below.
+# Unit tests are generally preferred over service tests as they are simpler to
+# create and maintain. Check out service_manager::TestConnectorFactory for an
+# easy way to test your services.
+source_set("unit_tests") {
+ testonly = true
+ deps = [
+ "//chromeos/services/multidevice_setup:unit_tests",
+ ]
+}
+
+# Use this target for adding new service tests. To add a unit test to this
+# target, create a "tests" source_set in your service and add it as a dependency
+# here.
+#
+# If your unit tests use the ServiceTest framework, you must also include
+# corresponding catalog entries in the "chromeos_services_unittests_catalog"
+# target below.
service_test("chromeos_services_unittests") {
deps = []
diff --git a/chromeos/services/DEPS b/chromeos/services/DEPS
new file mode 100644
index 0000000..a8e1150f
--- /dev/null
+++ b/chromeos/services/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/edk/embedder/embedder.h"
+]
diff --git a/chromeos/services/multidevice_setup/BUILD.gn b/chromeos/services/multidevice_setup/BUILD.gn
new file mode 100644
index 0000000..c26c0db
--- /dev/null
+++ b/chromeos/services/multidevice_setup/BUILD.gn
@@ -0,0 +1,69 @@
+# Copyright 2018 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("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+import("//services/service_manager/public/tools/test/service_test.gni")
+
+assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
+
+static_library("multidevice_setup") {
+ sources = [
+ "multidevice_setup_impl.cc",
+ "multidevice_setup_impl.h",
+ "multidevice_setup_service.cc",
+ "multidevice_setup_service.h",
+ ]
+
+ deps = [
+ "//base",
+ "//chromeos/services/multidevice_setup/public/mojom",
+ "//components/proximity_auth/logging",
+ "//services/service_manager/public/cpp",
+ ]
+}
+
+service_manifest("manifest") {
+ name = "multidevice_setup"
+ source = "manifest.json"
+}
+
+static_library("test_support") {
+ testonly = true
+
+ sources = [
+ "fake_multidevice_setup_observer.cc",
+ "fake_multidevice_setup_observer.h",
+ ]
+
+ public_deps = [
+ ":multidevice_setup",
+ ]
+
+ deps = [
+ ":multidevice_setup",
+ "//base",
+ "//chromeos/services/multidevice_setup/public/mojom",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "multidevice_setup_service_unittest.cc",
+ ]
+
+ deps = [
+ ":multidevice_setup",
+ ":test_support",
+ "//base/test:test_support",
+ "//chromeos/services/multidevice_setup/public/mojom",
+ "//services/service_manager/public/cpp/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromeos/services/multidevice_setup/DEPS b/chromeos/services/multidevice_setup/DEPS
new file mode 100644
index 0000000..5f70575e
--- /dev/null
+++ b/chromeos/services/multidevice_setup/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+components/proximity_auth/logging/logging.h",
+ "+mojo/public/cpp/bindings/binding_set.h",
+ "+services/service_manager/public",
+]
diff --git a/chromeos/services/multidevice_setup/OWNERS b/chromeos/services/multidevice_setup/OWNERS
new file mode 100644
index 0000000..8b584e9
--- /dev/null
+++ b/chromeos/services/multidevice_setup/OWNERS
@@ -0,0 +1,7 @@
[email protected]
[email protected]
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>ProximityAuth
diff --git a/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.cc b/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.cc
new file mode 100644
index 0000000..7dc544b
--- /dev/null
+++ b/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 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 "chromeos/services/multidevice_setup/fake_multidevice_setup_observer.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+FakeMultiDeviceSetupObserver::FakeMultiDeviceSetupObserver() = default;
+
+FakeMultiDeviceSetupObserver::~FakeMultiDeviceSetupObserver() = default;
+
+multidevice_setup::mojom::MultiDeviceSetupObserverPtr
+FakeMultiDeviceSetupObserver::GenerateInterfacePtr() {
+ multidevice_setup::mojom::MultiDeviceSetupObserverPtr interface_ptr;
+ bindings_.AddBinding(this, mojo::MakeRequest(&interface_ptr));
+ return interface_ptr;
+}
+
+void FakeMultiDeviceSetupObserver::OnPotentialHostExistsForNewUser() {
+ ++num_new_user_events_handled_;
+}
+
+void FakeMultiDeviceSetupObserver::OnConnectedHostSwitchedForExistingUser() {
+ ++num_existing_user_host_switched_events_handled_;
+}
+
+void FakeMultiDeviceSetupObserver::OnNewChromebookAddedForExistingUser() {
+ ++num_existing_user_chromebook_added_events_handled_;
+}
+
+} // namespace multidevice
+
+} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.h b/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.h
new file mode 100644
index 0000000..a62b14ba
--- /dev/null
+++ b/chromeos/services/multidevice_setup/fake_multidevice_setup_observer.h
@@ -0,0 +1,55 @@
+// Copyright 2018 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 CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_MULTIDEVICE_SETUP_OBSERVER_H_
+#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_MULTIDEVICE_SETUP_OBSERVER_H_
+
+#include "base/macros.h"
+#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+// Fake MultiDeviceSetupObserver implementation for tests.
+class FakeMultiDeviceSetupObserver
+ : public multidevice_setup::mojom::MultiDeviceSetupObserver {
+ public:
+ FakeMultiDeviceSetupObserver();
+ ~FakeMultiDeviceSetupObserver() override;
+
+ multidevice_setup::mojom::MultiDeviceSetupObserverPtr GenerateInterfacePtr();
+
+ size_t num_new_user_events_handled() { return num_new_user_events_handled_; }
+
+ size_t num_existing_user_host_switched_events_handled() {
+ return num_existing_user_host_switched_events_handled_;
+ }
+
+ size_t num_existing_user_chromebook_added_events_handled() {
+ return num_existing_user_chromebook_added_events_handled_;
+ }
+
+ // multidevice_setup::mojom::MultiDeviceSetupObserver:
+ void OnPotentialHostExistsForNewUser() override;
+ void OnConnectedHostSwitchedForExistingUser() override;
+ void OnNewChromebookAddedForExistingUser() override;
+
+ private:
+ size_t num_new_user_events_handled_ = 0u;
+ size_t num_existing_user_host_switched_events_handled_ = 0u;
+ size_t num_existing_user_chromebook_added_events_handled_ = 0u;
+
+ mojo::BindingSet<multidevice_setup::mojom::MultiDeviceSetupObserver>
+ bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeMultiDeviceSetupObserver);
+};
+
+} // namespace multidevice
+
+} // namespace chromeos
+
+#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_MULTIDEVICE_SETUP_OBSERVER_H_
diff --git a/chromeos/services/multidevice_setup/manifest.json b/chromeos/services/multidevice_setup/manifest.json
new file mode 100644
index 0000000..bb20ab69
--- /dev/null
+++ b/chromeos/services/multidevice_setup/manifest.json
@@ -0,0 +1,11 @@
+{
+ "name": "multidevice_setup",
+ "display_name": "MultiDevice Setup Service",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "multidevice_setup" : [ "multidevice_setup::mojom::MultiDeviceSetup" ]
+ }
+ }
+ }
+}
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
new file mode 100644
index 0000000..5d8a5e3
--- /dev/null
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
@@ -0,0 +1,88 @@
+// Copyright 2018 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 "chromeos/services/multidevice_setup/multidevice_setup_impl.h"
+
+#include "components/proximity_auth/logging/logging.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+namespace {
+
+using EventType = multidevice_setup::mojom::EventTypeForDebugging;
+
+std::string EventTypeEnumToString(EventType type) {
+ switch (type) {
+ case EventType::kNewUserPotentialHostExists:
+ return "kNewUserPotentialHostExists";
+ case EventType::kExistingUserConnectedHostSwitched:
+ return "kExistingUserConnectedHostSwitched";
+ case EventType::kExistingUserNewChromebookAdded:
+ return "kExistingUserNewChromebookAdded";
+ default:
+ NOTREACHED();
+ return "[invalid input]";
+ }
+}
+
+} // namespace
+
+MultiDeviceSetupImpl::MultiDeviceSetupImpl() = default;
+
+MultiDeviceSetupImpl::~MultiDeviceSetupImpl() = default;
+
+void MultiDeviceSetupImpl::BindRequest(
+ multidevice_setup::mojom::MultiDeviceSetupRequest request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void MultiDeviceSetupImpl::SetObserver(
+ multidevice_setup::mojom::MultiDeviceSetupObserverPtr observer,
+ SetObserverCallback callback) {
+ if (observer_.is_bound()) {
+ PA_LOG(ERROR) << "SetObserver() called when a MultiDeviceSetupObserver was "
+ << "already set. Replacing the previously-set "
+ << "MultiDeviceSetupObserver.";
+ }
+
+ PA_LOG(INFO) << "MultiDeviceSetupImpl::SetObserver()";
+ observer_ = std::move(observer);
+ std::move(callback).Run();
+}
+
+void MultiDeviceSetupImpl::TriggerEventForDebugging(
+ EventType type,
+ TriggerEventForDebuggingCallback callback) {
+ PA_LOG(INFO) << "TriggerEventForDebugging(" << EventTypeEnumToString(type)
+ << ") called.";
+
+ if (!observer_.is_bound()) {
+ PA_LOG(ERROR) << "No MultiDeviceSetupObserver has been set. Cannot "
+ << "proceed.";
+ std::move(callback).Run(false /* success */);
+ return;
+ }
+
+ switch (type) {
+ case EventType::kNewUserPotentialHostExists:
+ observer_->OnPotentialHostExistsForNewUser();
+ break;
+ case EventType::kExistingUserConnectedHostSwitched:
+ observer_->OnConnectedHostSwitchedForExistingUser();
+ break;
+ case EventType::kExistingUserNewChromebookAdded:
+ observer_->OnNewChromebookAddedForExistingUser();
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ std::move(callback).Run(true /* success */);
+}
+
+} // namespace multidevice
+
+} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.h b/chromeos/services/multidevice_setup/multidevice_setup_impl.h
new file mode 100644
index 0000000..7d4d3163
--- /dev/null
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2018 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 CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_IMPL_H_
+#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_IMPL_H_
+
+#include <memory>
+
+#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+// Concrete MultiDeviceSetup implementation.
+class MultiDeviceSetupImpl : public multidevice_setup::mojom::MultiDeviceSetup {
+ public:
+ MultiDeviceSetupImpl();
+ ~MultiDeviceSetupImpl() override;
+
+ // Binds a request to this implementation. Should be called each time that the
+ // service receives a request.
+ void BindRequest(multidevice_setup::mojom::MultiDeviceSetupRequest request);
+
+ // multidevice_setup::mojom::MultiDeviceSetup:
+ void SetObserver(
+ multidevice_setup::mojom::MultiDeviceSetupObserverPtr presenter,
+ SetObserverCallback callback) override;
+ void TriggerEventForDebugging(
+ multidevice_setup::mojom::EventTypeForDebugging type,
+ TriggerEventForDebuggingCallback callback) override;
+
+ private:
+ multidevice_setup::mojom::MultiDeviceSetupObserverPtr observer_;
+ mojo::BindingSet<multidevice_setup::mojom::MultiDeviceSetup> bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupImpl);
+};
+
+} // namespace multidevice
+
+} // namespace chromeos
+
+#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_IMPL_H_
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service.cc b/chromeos/services/multidevice_setup/multidevice_setup_service.cc
new file mode 100644
index 0000000..79b80d3b
--- /dev/null
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service.cc
@@ -0,0 +1,41 @@
+// Copyright 2018 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 "chromeos/services/multidevice_setup/multidevice_setup_service.h"
+
+#include "chromeos/services/multidevice_setup/multidevice_setup_impl.h"
+#include "components/proximity_auth/logging/logging.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+MultiDeviceSetupService::MultiDeviceSetupService()
+ : multidevice_setup_impl_(std::make_unique<MultiDeviceSetupImpl>()) {}
+
+MultiDeviceSetupService::~MultiDeviceSetupService() = default;
+
+void MultiDeviceSetupService::OnStart() {
+ PA_LOG(INFO) << "MultiDeviceSetupService::OnStart()";
+ registry_.AddInterface(base::Bind(&MultiDeviceSetupService::BindRequest,
+ base::Unretained(this)));
+}
+
+void MultiDeviceSetupService::OnBindInterface(
+ const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ PA_LOG(INFO) << "MultiDeviceSetupService::OnBindInterface() from interface "
+ << interface_name << ".";
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
+}
+
+void MultiDeviceSetupService::BindRequest(
+ multidevice_setup::mojom::MultiDeviceSetupRequest request) {
+ multidevice_setup_impl_->BindRequest(std::move(request));
+}
+
+} // namespace multidevice
+
+} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service.h b/chromeos/services/multidevice_setup/multidevice_setup_service.h
new file mode 100644
index 0000000..8a1b8fb
--- /dev/null
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service.h
@@ -0,0 +1,48 @@
+// Copyright 2018 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 CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_SERVICE_H_
+#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_SERVICE_H_
+
+#include <memory>
+
+#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+class MultiDeviceSetupImpl;
+
+// Service which provides an implementation for
+// multidevice_setup::mojom::MultiDeviceSetup. This service creates one
+// implementation and shares it among all connection requests.
+class MultiDeviceSetupService : public service_manager::Service {
+ public:
+ MultiDeviceSetupService();
+ ~MultiDeviceSetupService() override;
+
+ private:
+ // service_manager::Service:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ void BindRequest(multidevice_setup::mojom::MultiDeviceSetupRequest request);
+
+ std::unique_ptr<MultiDeviceSetupImpl> multidevice_setup_impl_;
+
+ service_manager::BinderRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupService);
+};
+
+} // namespace multidevice
+
+} // namespace chromeos
+
+#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_MULTIDEVICE_SETUP_SERVICE_H_
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc
new file mode 100644
index 0000000..aaabf71
--- /dev/null
+++ b/chromeos/services/multidevice_setup/multidevice_setup_service_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright 2018 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/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "chromeos/services/multidevice_setup/fake_multidevice_setup_observer.h"
+#include "chromeos/services/multidevice_setup/multidevice_setup_service.h"
+#include "chromeos/services/multidevice_setup/public/mojom/constants.mojom.h"
+#include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace multidevice {
+
+using EventType = multidevice_setup::mojom::EventTypeForDebugging;
+
+class MultiDeviceSetupServiceTest : public testing::Test {
+ protected:
+ MultiDeviceSetupServiceTest() = default;
+ ~MultiDeviceSetupServiceTest() override = default;
+
+ void SetUp() override {
+ fake_multidevice_setup_observer_ =
+ std::make_unique<FakeMultiDeviceSetupObserver>();
+ connector_factory_ =
+ service_manager::TestConnectorFactory::CreateForUniqueService(
+ std::make_unique<MultiDeviceSetupService>());
+ }
+
+ multidevice_setup::mojom::MultiDeviceSetup* GetMultiDeviceSetup() {
+ if (!multidevice_setup_) {
+ EXPECT_EQ(nullptr, connector_);
+
+ // Create the Connector and bind it to |multidevice_setup_|.
+ connector_ = connector_factory_->CreateConnector();
+ connector_->BindInterface(multidevice_setup::mojom::kServiceName,
+ &multidevice_setup_);
+
+ // Set |fake_multidevice_setup_observer_|.
+ CallSetObserver();
+ }
+
+ return multidevice_setup_.get();
+ }
+
+ FakeMultiDeviceSetupObserver* fake_multidevice_setup_observer() {
+ return fake_multidevice_setup_observer_.get();
+ }
+
+ void CallSetObserver() {
+ base::RunLoop run_loop;
+ multidevice_setup_->SetObserver(
+ fake_multidevice_setup_observer_->GenerateInterfacePtr(),
+ base::BindRepeating(
+ &MultiDeviceSetupServiceTest::OnNotificationPresenterRegistered,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ void CallTriggerEventForDebugging(EventType type) {
+ base::RunLoop run_loop;
+ GetMultiDeviceSetup()->TriggerEventForDebugging(
+ type, base::BindRepeating(
+ &MultiDeviceSetupServiceTest::OnNotificationTriggered,
+ base::Unretained(this), run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ private:
+ void OnNotificationPresenterRegistered(
+ const base::RepeatingClosure& quit_closure) {
+ quit_closure.Run();
+ }
+
+ void OnNotificationTriggered(const base::RepeatingClosure& quit_closure,
+ bool success) {
+ // NotificationPresenter is set in GetMultiDeviceSetup().
+ EXPECT_TRUE(success);
+ quit_closure.Run();
+ }
+
+ const base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
+ std::unique_ptr<service_manager::Connector> connector_;
+
+ std::unique_ptr<FakeMultiDeviceSetupObserver>
+ fake_multidevice_setup_observer_;
+ multidevice_setup::mojom::MultiDeviceSetupPtr multidevice_setup_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupServiceTest);
+};
+
+TEST_F(MultiDeviceSetupServiceTest,
+ TriggerEventForDebugging_kNewUserPotentialHostExists) {
+ CallTriggerEventForDebugging(EventType::kNewUserPotentialHostExists);
+
+ EXPECT_EQ(1u,
+ fake_multidevice_setup_observer()->num_new_user_events_handled());
+}
+
+TEST_F(MultiDeviceSetupServiceTest,
+ TriggerEventForDebugging_kExistingUserConnectedHostSwitched) {
+ CallTriggerEventForDebugging(EventType::kExistingUserConnectedHostSwitched);
+
+ EXPECT_EQ(1u, fake_multidevice_setup_observer()
+ ->num_existing_user_host_switched_events_handled());
+}
+
+TEST_F(MultiDeviceSetupServiceTest,
+ TriggerEventForDebugging_kExistingUserNewChromebookAdded) {
+ CallTriggerEventForDebugging(EventType::kExistingUserNewChromebookAdded);
+
+ EXPECT_EQ(1u, fake_multidevice_setup_observer()
+ ->num_existing_user_chromebook_added_events_handled());
+}
+
+} // namespace multidevice
+
+} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/public/mojom/BUILD.gn b/chromeos/services/multidevice_setup/public/mojom/BUILD.gn
new file mode 100644
index 0000000..a123fc6d
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/mojom/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2018 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("mojom") {
+ sources = [
+ "constants.mojom",
+ "multidevice_setup.mojom",
+ ]
+}
diff --git a/chromeos/services/multidevice_setup/public/mojom/OWNERS b/chromeos/services/multidevice_setup/public/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromeos/services/multidevice_setup/public/mojom/constants.mojom b/chromeos/services/multidevice_setup/public/mojom/constants.mojom
new file mode 100644
index 0000000..ccdc66d
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/mojom/constants.mojom
@@ -0,0 +1,7 @@
+// Copyright 2018 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 multidevice_setup.mojom;
+
+const string kServiceName = "multidevice_setup";
diff --git a/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom b/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom
new file mode 100644
index 0000000..c8da6e8
--- /dev/null
+++ b/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom
@@ -0,0 +1,51 @@
+// Copyright 2018 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 multidevice_setup.mojom;
+
+// Handles events dispatched by MultiDeviceSetup.
+interface MultiDeviceSetupObserver {
+ // Callback which indicates that one or more MultiDevice host phones are
+ // available for setup with the MultiDevice setup flow. This function is only
+ // called if the current user has not yet set up MultiDevice features.
+ OnPotentialHostExistsForNewUser();
+
+ // Callback which indicates that the currently-connected MultiDevice host has
+ // changed. This likely means that the user has changed MultiDevice settings
+ // on another device. This function is only called if the current user has
+ // already set up MultiDevice features.
+ OnConnectedHostSwitchedForExistingUser();
+
+ // Callback which indicates that a new Chromebook was added to the account of
+ // the current user. This function is only called if the current user has
+ // already set up MultiDevice features.
+ OnNewChromebookAddedForExistingUser();
+};
+
+// Enumeration of event types which can be dispatched. Only used for debugging
+// purposes.
+enum EventTypeForDebugging {
+ kNewUserPotentialHostExists,
+ kExistingUserConnectedHostSwitched,
+ kExistingUserNewChromebookAdded,
+};
+
+// Provides an API to the MultiDevice Setup flow. Designed to be exposed
+// primarily to the MultiDevice setup flow at chrome://multidevice-setup (normal
+// usage) as well as the ProximityAuth debug WebUI page at
+// chrome://proximity-auth (debugging only).
+// TODO(khorimoto): Finish fleshing out this interface.
+interface MultiDeviceSetup {
+ // Registers the observer to be used by the service. Once this function has
+ // been called, the service will begin monitoring changes to synced devices
+ // and will notify |observer| when appropriate. Only one observer can be
+ // active at a time; calling this function a second time will remove the
+ // first observer added.
+ SetObserver(MultiDeviceSetupObserver observer) => ();
+
+ // Triggers an event to be dispatched by the service. This API function is
+ // intended to be used only for debugging in the chrome://proximity-auth page.
+ // During normal usage, events are triggered internally within the service.
+ TriggerEventForDebugging(EventTypeForDebugging type) => (bool success);
+};