Commit 4f3725c4 authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS MultiDevice] Implement basic DeviceSync service functionality.

This CL implements the initialization flow for the service as well as
the implementation for GetSyncedDevices() and observer callbacks.
Additionally, it tweaks the API for Force{Enrollment,Sync}Now() to
return a boolean of whether the forced action was successfully
handled by the service (it cannot be handled before the service
starts up).

Bug: 824568, 752273
Change-Id: I787c5ac9cb5fe6011e26e0ddb8217910b9c495f0
Reviewed-on: https://chromium-review.googlesource.com/998795
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJonathan Ross <jonross@chromium.org>
Reviewed-by: default avatarJeremy Klein <jlklein@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551474}
parent e1b73f45
...@@ -36,6 +36,7 @@ static_library("device_sync") { ...@@ -36,6 +36,7 @@ static_library("device_sync") {
"//chromeos/services/device_sync/public/mojom", "//chromeos/services/device_sync/public/mojom",
"//net", "//net",
"//services/identity/public/cpp", "//services/identity/public/cpp",
"//services/preferences/public/cpp",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
] ]
} }
...@@ -78,10 +79,13 @@ source_set("unit_tests") { ...@@ -78,10 +79,13 @@ source_set("unit_tests") {
":test_support", ":test_support",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//chromeos",
"//chromeos/services/device_sync/public/mojom", "//chromeos/services/device_sync/public/mojom",
"//chromeos/services/device_sync/public/mojom:unit_tests", "//chromeos/services/device_sync/public/mojom:unit_tests",
"//components/cryptauth", "//components/cryptauth",
"//components/cryptauth:test_support", "//components/cryptauth:test_support",
"//components/gcm_driver:test_support",
"//components/prefs:test_support",
"//mojo/common", "//mojo/common",
"//services/identity/public/cpp:test_support", "//services/identity/public/cpp:test_support",
"//services/service_manager/public/cpp:service_test_support", "//services/service_manager/public/cpp:service_test_support",
......
include_rules = [ include_rules = [
"+components/cryptauth", "+components/cryptauth",
"+components/gcm_driver",
"+components/proximity_auth/logging", "+components/proximity_auth/logging",
"+components/signin/core/browser", "+components/signin/core/browser",
"+google_apis/gaia", "+google_apis/gaia",
"+mojo/public/cpp", "+mojo/public/cpp",
"+net/url_request", "+net/url_request",
"+services/identity", "+services/identity",
"+services/preferences/public",
"+services/service_manager/public/cpp", "+services/service_manager/public/cpp",
"+components/cryptauth" "+components/cryptauth"
] ]
...@@ -6,34 +6,167 @@ ...@@ -6,34 +6,167 @@
#define CHROMEOS_SERVICES_DEVICE_SYNC_DEVICE_SYNC_IMPL_H_ #define CHROMEOS_SERVICES_DEVICE_SYNC_DEVICE_SYNC_IMPL_H_
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h" #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
#include "components/cryptauth/cryptauth_enrollment_manager.h"
#include "components/cryptauth/cryptauth_gcm_manager.h"
#include "components/cryptauth/remote_device_provider.h"
#include "components/signin/core/browser/account_info.h"
#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/preferences/public/cpp/pref_service_factory.h"
#include "services/preferences/public/mojom/preferences.mojom.h"
class PrefService;
namespace base {
class Clock;
} // namespace base
namespace cryptauth {
class CryptAuthDeviceManager;
class GcmDeviceInfoProvider;
} // namespace cryptauth
namespace gcm {
class GCMDriver;
} // namespace gcm
namespace identity {
class IdentityManager;
} // namespace identity
namespace net {
class URLRequestContextGetter;
} // namespace net
namespace service_manager {
class Connector;
} // namespace service_manager
namespace chromeos { namespace chromeos {
namespace device_sync { namespace device_sync {
// Concrete DeviceSync implementation. // Concrete DeviceSync implementation. When DeviceSyncImpl is constructed, it
class DeviceSyncImpl : public mojom::DeviceSync { // starts an initialization flow with the following steps:
// (1) Verify that the primary user is logged in with a valid account ID.
// (2) Connect to the Prefs Service associated with that account.
// (3) Instantiate classes which communicate with the CryptAuth back-end.
// (4) Check enrollment state; if not yet enrolled, enroll the device.
// (5) When enrollment is valid, listen for device sync updates.
class DeviceSyncImpl : public mojom::DeviceSync,
public cryptauth::CryptAuthEnrollmentManager::Observer,
public cryptauth::RemoteDeviceProvider::Observer {
public: public:
DeviceSyncImpl(); class Factory {
public:
static std::unique_ptr<DeviceSyncImpl> NewInstance(
identity::IdentityManager* identity_manager,
gcm::GCMDriver* gcm_driver,
service_manager::Connector* connector,
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
scoped_refptr<net::URLRequestContextGetter> url_request_context);
static void SetInstanceForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<DeviceSyncImpl> BuildInstance(
identity::IdentityManager* identity_manager,
gcm::GCMDriver* gcm_driver,
service_manager::Connector* connector,
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
scoped_refptr<net::URLRequestContextGetter> url_request_context);
private:
static Factory* test_factory_instance_;
};
~DeviceSyncImpl() override; ~DeviceSyncImpl() override;
// Binds a request to this implementation. Should be called each time that the // Binds a request to this implementation. Should be called each time that the
// service receives a request. // service receives a request.
void BindRequest(mojom::DeviceSyncRequest request); void BindRequest(mojom::DeviceSyncRequest request);
protected:
// mojom::DeviceSync: // mojom::DeviceSync:
void ForceEnrollmentNow() override;
void ForceSyncNow() override;
void AddObserver(mojom::DeviceSyncObserverPtr observer, void AddObserver(mojom::DeviceSyncObserverPtr observer,
AddObserverCallback callback) override; AddObserverCallback callback) override;
void ForceEnrollmentNow(ForceEnrollmentNowCallback callback) override;
void ForceSyncNow(ForceSyncNowCallback callback) override;
void GetSyncedDevices(GetSyncedDevicesCallback callback) override;
// cryptauth::CryptAuthEnrollmentManager::Observer:
void OnEnrollmentFinished(bool success) override;
// cryptauth::RemoteDeviceProvider::Observer:
void OnSyncDeviceListChanged() override;
private: private:
friend class DeviceSyncServiceTest;
enum class Status {
FETCHING_ACCOUNT_INFO,
CONNECTING_TO_USER_PREFS,
WAITING_FOR_ENROLLMENT,
READY
};
// Wrapper around preferences code. This class is necessary so that tests can
// override this functionality to use a fake PrefService rather than a real
// connection to the Preferences service.
class PrefConnectionDelegate {
public:
virtual ~PrefConnectionDelegate();
virtual scoped_refptr<PrefRegistrySimple> CreatePrefRegistry();
virtual void ConnectToPrefService(
service_manager::Connector* connector,
scoped_refptr<PrefRegistrySimple> pref_registry,
prefs::ConnectCallback callback);
};
DeviceSyncImpl(
identity::IdentityManager* identity_manager,
gcm::GCMDriver* gcm_driver,
service_manager::Connector* connector,
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
scoped_refptr<net::URLRequestContextGetter> url_request_context,
base::Clock* clock,
std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate);
void ProcessPrimaryAccountInfo(const AccountInfo& primary_account_info);
void ConnectToPrefStore();
void OnConnectedToPrefService(std::unique_ptr<PrefService> pref_service);
void InitializeCryptAuthManagementObjects();
void CompleteInitializationAfterSuccessfulEnrollment();
void SetPrefConnectionDelegateForTesting(
std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate);
identity::IdentityManager* identity_manager_;
gcm::GCMDriver* gcm_driver_;
service_manager::Connector* connector_;
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
base::Clock* clock_;
std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate_;
Status status_;
AccountInfo primary_account_info_;
std::unique_ptr<PrefService> pref_service_;
std::unique_ptr<cryptauth::CryptAuthGCMManager> cryptauth_gcm_manager_;
std::unique_ptr<cryptauth::CryptAuthEnrollmentManager>
cryptauth_enrollment_manager_;
std::unique_ptr<cryptauth::CryptAuthDeviceManager> cryptauth_device_manager_;
std::unique_ptr<cryptauth::RemoteDeviceProvider> remote_device_provider_;
mojo::InterfacePtrSet<mojom::DeviceSyncObserver> observers_; mojo::InterfacePtrSet<mojom::DeviceSyncObserver> observers_;
mojo::BindingSet<mojom::DeviceSync> bindings_; mojo::BindingSet<mojom::DeviceSync> bindings_;
base::WeakPtrFactory<DeviceSyncImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DeviceSyncImpl); DISALLOW_COPY_AND_ASSIGN(DeviceSyncImpl);
}; };
......
...@@ -6,18 +6,34 @@ ...@@ -6,18 +6,34 @@
#include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/device_sync/device_sync_impl.h" #include "chromeos/services/device_sync/device_sync_impl.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace chromeos { namespace chromeos {
namespace device_sync { namespace device_sync {
DeviceSyncService::DeviceSyncService() DeviceSyncService::DeviceSyncService(
: device_sync_impl_(std::make_unique<DeviceSyncImpl>()) {} identity::IdentityManager* identity_manager,
gcm::GCMDriver* gcm_driver,
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
scoped_refptr<net::URLRequestContextGetter> url_request_context)
: identity_manager_(identity_manager),
gcm_driver_(gcm_driver),
gcm_device_info_provider_(gcm_device_info_provider),
url_request_context_(url_request_context) {}
DeviceSyncService::~DeviceSyncService() = default; DeviceSyncService::~DeviceSyncService() = default;
void DeviceSyncService::OnStart() { void DeviceSyncService::OnStart() {
PA_LOG(INFO) << "DeviceSyncService::OnStart()"; PA_LOG(INFO) << "DeviceSyncService::OnStart()";
// context() cannot be invoked until after the constructor is run, so
// |device_sync_impl_| cannot be initialized until OnStart().
device_sync_impl_ = DeviceSyncImpl::Factory::NewInstance(
identity_manager_, gcm_driver_, context()->connector(),
gcm_device_info_provider_, url_request_context_);
registry_.AddInterface(base::Bind(&DeviceSyncImpl::BindRequest, registry_.AddInterface(base::Bind(&DeviceSyncImpl::BindRequest,
base::Unretained(device_sync_impl_.get()))); base::Unretained(device_sync_impl_.get())));
} }
......
...@@ -7,10 +7,27 @@ ...@@ -7,10 +7,27 @@
#include <memory> #include <memory>
#include "base/memory/ref_counted.h"
#include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h" #include "chromeos/services/device_sync/public/mojom/device_sync.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h" #include "services/service_manager/public/cpp/service.h"
namespace cryptauth {
class GcmDeviceInfoProvider;
} // namespace cryptauth
namespace gcm {
class GCMDriver;
} // namespace gcm
namespace identity {
class IdentityManager;
} // namespace identity
namespace net {
class URLRequestContextGetter;
} // namespace net
namespace chromeos { namespace chromeos {
namespace device_sync { namespace device_sync {
...@@ -22,7 +39,11 @@ class DeviceSyncImpl; ...@@ -22,7 +39,11 @@ class DeviceSyncImpl;
// implementation and shares it among all connection requests. // implementation and shares it among all connection requests.
class DeviceSyncService : public service_manager::Service { class DeviceSyncService : public service_manager::Service {
public: public:
DeviceSyncService(); DeviceSyncService(
identity::IdentityManager* identity_manager,
gcm::GCMDriver* gcm_driver,
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider,
scoped_refptr<net::URLRequestContextGetter> url_request_context);
~DeviceSyncService() override; ~DeviceSyncService() override;
protected: protected:
...@@ -33,6 +54,11 @@ class DeviceSyncService : public service_manager::Service { ...@@ -33,6 +54,11 @@ class DeviceSyncService : public service_manager::Service {
mojo::ScopedMessagePipeHandle interface_pipe) override; mojo::ScopedMessagePipeHandle interface_pipe) override;
private: private:
identity::IdentityManager* identity_manager_;
gcm::GCMDriver* gcm_driver_;
cryptauth::GcmDeviceInfoProvider* gcm_device_info_provider_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
std::unique_ptr<DeviceSyncImpl> device_sync_impl_; std::unique_ptr<DeviceSyncImpl> device_sync_impl_;
service_manager::BinderRegistry registry_; service_manager::BinderRegistry registry_;
......
...@@ -12,34 +12,18 @@ FakeDeviceSyncObserver::FakeDeviceSyncObserver() = default; ...@@ -12,34 +12,18 @@ FakeDeviceSyncObserver::FakeDeviceSyncObserver() = default;
FakeDeviceSyncObserver::~FakeDeviceSyncObserver() = default; FakeDeviceSyncObserver::~FakeDeviceSyncObserver() = default;
void FakeDeviceSyncObserver::SetDelegate(Delegate* delegate) {
delegate_ = delegate;
}
mojom::DeviceSyncObserverPtr FakeDeviceSyncObserver::GenerateInterfacePtr() { mojom::DeviceSyncObserverPtr FakeDeviceSyncObserver::GenerateInterfacePtr() {
mojom::DeviceSyncObserverPtr interface_ptr; mojom::DeviceSyncObserverPtr interface_ptr;
bindings_.AddBinding(this, mojo::MakeRequest(&interface_ptr)); bindings_.AddBinding(this, mojo::MakeRequest(&interface_ptr));
return interface_ptr; return interface_ptr;
} }
void FakeDeviceSyncObserver::OnEnrollmentFinished(bool success) { void FakeDeviceSyncObserver::OnEnrollmentFinished() {
if (success) ++num_enrollment_events_;
++num_enrollment_success_events_;
else
++num_enrollment_failure_events_;
if (delegate_)
delegate_->OnEnrollmentFinishedCalled();
} }
void FakeDeviceSyncObserver::OnDevicesSynced(bool success) { void FakeDeviceSyncObserver::OnNewDevicesSynced() {
if (success) ++num_sync_events_;
++num_sync_success_events_;
else
++num_sync_failure_events_;
if (delegate_)
delegate_->OnDevicesSyncedCalled();
} }
} // namespace device_sync } // namespace device_sync
......
...@@ -19,41 +19,18 @@ class FakeDeviceSyncObserver : public device_sync::mojom::DeviceSyncObserver { ...@@ -19,41 +19,18 @@ class FakeDeviceSyncObserver : public device_sync::mojom::DeviceSyncObserver {
FakeDeviceSyncObserver(); FakeDeviceSyncObserver();
~FakeDeviceSyncObserver() override; ~FakeDeviceSyncObserver() override;
// Receives callbacks when the relevant DeviceSyncObserver functions have been
// handled.
class Delegate {
public:
virtual void OnEnrollmentFinishedCalled() = 0;
virtual void OnDevicesSyncedCalled() = 0;
};
void SetDelegate(Delegate* delegate);
mojom::DeviceSyncObserverPtr GenerateInterfacePtr(); mojom::DeviceSyncObserverPtr GenerateInterfacePtr();
size_t num_enrollment_success_events() { size_t num_enrollment_events() { return num_enrollment_events_; }
return num_enrollment_success_events_; size_t num_sync_events() { return num_sync_events_; }
}
size_t num_enrollment_failure_events() {
return num_enrollment_failure_events_;
}
size_t num_sync_success_events() { return num_sync_success_events_; }
size_t num_sync_failure_events() { return num_sync_failure_events_; }
// device_sync::mojom::DeviceSyncObserver: // device_sync::mojom::DeviceSyncObserver:
void OnEnrollmentFinished(bool success) override; void OnEnrollmentFinished() override;
void OnDevicesSynced(bool success) override; void OnNewDevicesSynced() override;
private: private:
Delegate* delegate_ = nullptr; size_t num_enrollment_events_ = 0u;
size_t num_sync_events_ = 0u;
size_t num_enrollment_success_events_ = 0u;
size_t num_enrollment_failure_events_ = 0u;
size_t num_sync_success_events_ = 0u;
size_t num_sync_failure_events_ = 0u;
mojo::BindingSet<mojom::DeviceSyncObserver> bindings_; mojo::BindingSet<mojom::DeviceSyncObserver> bindings_;
......
...@@ -52,71 +52,43 @@ struct RemoteDevice { ...@@ -52,71 +52,43 @@ struct RemoteDevice {
array<BeaconSeed> beacon_seeds; array<BeaconSeed> beacon_seeds;
}; };
enum ResultCode {
SUCCESS,
ERROR_INTERNAL,
ERROR_NO_VALID_ACCESS_TOKEN,
ERROR_SERVER_FAILED_TO_RESPOND,
ERROR_CANNOT_PARSE_SERVER_RESPONSE,
};
enum PromotableFeature {
EASY_UNLOCK,
};
struct SetCapabilityResponse {
ResultCode result_code;
};
struct IneligibleDevice {
string device_id;
string reason; // Reason why the device is not eligible.
};
struct FindEligibleDevicesResponse {
ResultCode result_code;
// Only set when result_code == SUCCESS.
array<string> eligible_device_ids;
array<IneligibleDevice> ineligible_devices;
};
struct IsCapabilityPromotableResponse {
ResultCode result_code;
// Only set when result_code == SUCCESS.
bool is_promotable;
};
// Properties associated with a device which can be set and retrieved by calls
// to the server.
// TODO(khorimoto): Add additional capabilities, including the Tether
// capability.
enum RemoteDeviceCapability {
UNLOCK_KEY,
};
interface DeviceSyncObserver { interface DeviceSyncObserver {
// Invoked when the current device has finished enrolling itself (i.e., when // Invoked when the current device has successfully completed enrollment. Note
// it has contacted the server to provide device metadata). Devices must // that enrollment occurs once when the device first starts up, then the
// enroll themselves before other device can establish connections to them, // device re-enrolls periodically (and on-command when ForceEnrollmentNow() is
// and they continue to re-enroll themselves on a periodic basis after that. // called).
OnEnrollmentFinished(bool success); OnEnrollmentFinished();
// Invoked when new devices have been synced from the server. // Invoked when new devices have been synced from the server. Note that this
OnDevicesSynced(bool success); // function is not invoked if a device sync failed or if a device sync
// succeeded but did not result in a change of devices.
OnNewDevicesSynced();
}; };
// TODO(khorimoto): Flesh out API. // TODO(khorimoto): Flesh out API.
interface DeviceSync { interface DeviceSync {
// Triggers an enrollment. Result of the enrollment will be relayed via the
// OnEnrollmentFinished() observer function.
ForceEnrollmentNow();
// Triggers a device sync. Result of the sync will be relayed via the
// OnDevicesSynced() observer function.
ForceSyncNow();
// Adds an Observer of this API. // Adds an Observer of this API.
AddObserver(DeviceSyncObserver observer) => (); AddObserver(DeviceSyncObserver observer) => ();
// Triggers an enrollment; result is relayed via the OnEnrollmentFinished()
// observer function. Returns whether the call could be completed
// successfully. If the function returns false, this means that the device has
// not yet completed registration with the back-end; clients should observe
// this service and wait for an OnEnrollmentFinished() callback before
// retrying.
[Sync]
ForceEnrollmentNow() => (bool success);
// Triggers a device sync; result is relayed via the OnDevicesSynced()
// observer function. Returns whether the call could be completed
// successfully. If the function returns false, this means that the device has
// not yet completed registration with the back-end; clients should observe
// this service and wait for an OnEnrollmentFinished() callback before
// retrying.
[Sync]
ForceSyncNow() => (bool success);
// Returns all synced devices associated with the primary account.
[Sync]
GetSyncedDevices() => (array<RemoteDevice> devices);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment