Sharing Device registration implementation

Bug: 966034
Change-Id: I6942c435906b40dcdbed04beaeb73586a8a60ae6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1669302
Reviewed-by: Ryan Hamilton <[email protected]>
Reviewed-by: Nicolas Zea <[email protected]>
Reviewed-by: Richard Knoll <[email protected]>
Commit-Queue: Himanshu Jaju <[email protected]>
Cr-Commit-Position: refs/heads/master@{#673810}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b252ce4..16c0d514 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1502,10 +1502,14 @@
     "sharing/ack_message_handler.h",
     "sharing/click_to_call/feature.cc",
     "sharing/click_to_call/feature.h",
+    "sharing/fcm_constants.cc",
+    "sharing/fcm_constants.h",
     "sharing/features.cc",
     "sharing/features.h",
     "sharing/sharing_device_info.cc",
     "sharing/sharing_device_info.h",
+    "sharing/sharing_device_registration.cc",
+    "sharing/sharing_device_registration.h",
     "sharing/sharing_fcm_handler.cc",
     "sharing/sharing_fcm_handler.h",
     "sharing/sharing_fcm_sender.cc",
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 4f5a428..5e0ecea3 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -84,6 +84,7 @@
 #include "chrome/browser/push_messaging/push_messaging_service_factory.h"
 #include "chrome/browser/push_messaging/push_messaging_service_impl.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/sharing/sharing_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/site_isolation/site_isolation_policy.h"
@@ -756,6 +757,10 @@
     delegate_->OnProfileCreated(this, true, IsNewProfile());
   }
 
+  // Ensure that the SharingService is initialized now that io_data_ is
+  // initialized.
+  SharingServiceFactory::GetForBrowserContext(this);
+
   {
     SCOPED_UMA_HISTOGRAM_TIMER("Profile.NotifyProfileCreatedTime");
     content::NotificationService::current()->Notify(
diff --git a/chrome/browser/sharing/fake_local_device_info_provider.cc b/chrome/browser/sharing/fake_local_device_info_provider.cc
new file mode 100644
index 0000000..0380fcb9
--- /dev/null
+++ b/chrome/browser/sharing/fake_local_device_info_provider.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 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 "chrome/browser/sharing/fake_local_device_info_provider.h"
+
+#include "base/time/time.h"
+
+FakeLocalDeviceInfoProvider::FakeLocalDeviceInfoProvider()
+    : device_info_("id",
+                   "name",
+                   "chrome_version",
+                   "user_agent",
+                   sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
+                   "device_id",
+                   /* last_updated_timestamp= */ base::Time::Now(),
+                   /* send_tab_to_self_receiving_enabled= */ false) {}
+
+FakeLocalDeviceInfoProvider::~FakeLocalDeviceInfoProvider() = default;
+
+version_info::Channel FakeLocalDeviceInfoProvider::GetChannel() const {
+  NOTIMPLEMENTED();
+  return version_info::Channel::UNKNOWN;
+}
+
+const syncer::DeviceInfo* FakeLocalDeviceInfoProvider::GetLocalDeviceInfo()
+    const {
+  return &device_info_;
+}
+
+std::unique_ptr<FakeLocalDeviceInfoProvider::Subscription>
+FakeLocalDeviceInfoProvider::RegisterOnInitializedCallback(
+    const base::RepeatingClosure& callback) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
diff --git a/chrome/browser/sharing/fake_local_device_info_provider.h b/chrome/browser/sharing/fake_local_device_info_provider.h
new file mode 100644
index 0000000..8133c32
--- /dev/null
+++ b/chrome/browser/sharing/fake_local_device_info_provider.h
@@ -0,0 +1,31 @@
+// Copyright 2019 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 CHROME_BROWSER_SHARING_FAKE_LOCAL_DEVICE_INFO_PROVIDER_H_
+#define CHROME_BROWSER_SHARING_FAKE_LOCAL_DEVICE_INFO_PROVIDER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/sync_device_info/device_info.h"
+#include "components/sync_device_info/local_device_info_provider.h"
+
+class FakeLocalDeviceInfoProvider : public syncer::LocalDeviceInfoProvider {
+ public:
+  FakeLocalDeviceInfoProvider();
+  ~FakeLocalDeviceInfoProvider() override;
+
+  // Overrides for syncer::LocalDeviceInfoProvider.
+  version_info::Channel GetChannel() const override;
+  const syncer::DeviceInfo* GetLocalDeviceInfo() const override;
+  std::unique_ptr<Subscription> RegisterOnInitializedCallback(
+      const base::RepeatingClosure& callback) override;
+
+ private:
+  syncer::DeviceInfo device_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeLocalDeviceInfoProvider);
+};
+
+#endif  // CHROME_BROWSER_SHARING_FAKE_LOCAL_DEVICE_INFO_PROVIDER_H_
diff --git a/chrome/browser/sharing/fcm_constants.cc b/chrome/browser/sharing/fcm_constants.cc
new file mode 100644
index 0000000..6abe9e9
--- /dev/null
+++ b/chrome/browser/sharing/fcm_constants.cc
@@ -0,0 +1,9 @@
+// Copyright 2019 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 "chrome/browser/sharing/fcm_constants.h"
+
+const char kFCMScope[] = "GCM";
+
+const char kSharingFCMAppID[] = "com.google.chrome.sharing.fcm";
diff --git a/chrome/browser/sharing/fcm_constants.h b/chrome/browser/sharing/fcm_constants.h
new file mode 100644
index 0000000..b5d3e30
--- /dev/null
+++ b/chrome/browser/sharing/fcm_constants.h
@@ -0,0 +1,14 @@
+// Copyright 2019 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 CHROME_BROWSER_SHARING_FCM_CONSTANTS_H_
+#define CHROME_BROWSER_SHARING_FCM_CONSTANTS_H_
+
+// InstanceID scope for Google Cloud Messaging to get GCM enabled token.
+extern const char kFCMScope[];
+
+// Sender ID linked to GCM messages for Sharing.
+extern const char kSharingFCMAppID[];
+
+#endif  // CHROME_BROWSER_SHARING_FCM_CONSTANTS_H_
diff --git a/chrome/browser/sharing/sharing_device_info.h b/chrome/browser/sharing/sharing_device_info.h
index 22f04eb..4f40303 100644
--- a/chrome/browser/sharing/sharing_device_info.h
+++ b/chrome/browser/sharing/sharing_device_info.h
@@ -32,7 +32,7 @@
   // Returns the time at which this device was last online.
   base::Time last_online_timestamp() const;
 
-  // Gets a bitmask of available capaiblities of the device, defined in
+  // Gets a bitmask of available capabilities of the device, defined in
   // SharingDeviceCapability enum.
   int capabilities() const;
 
diff --git a/chrome/browser/sharing/sharing_device_registration.cc b/chrome/browser/sharing/sharing_device_registration.cc
new file mode 100644
index 0000000..3084725
--- /dev/null
+++ b/chrome/browser/sharing/sharing_device_registration.cc
@@ -0,0 +1,102 @@
+// Copyright 2019 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 "chrome/browser/sharing/sharing_device_registration.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/base64url.h"
+#include "base/bind.h"
+#include "base/optional.h"
+#include "chrome/browser/sharing/fcm_constants.h"
+#include "chrome/browser/sharing/sharing_device_info.h"
+#include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "components/gcm_driver/crypto/p256_key_util.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/sync_device_info/device_info.h"
+#include "components/sync_device_info/local_device_info_provider.h"
+#include "crypto/ec_private_key.h"
+
+SharingDeviceRegistration::SharingDeviceRegistration(
+    SharingSyncPreference* sharing_sync_preference,
+    instance_id::InstanceIDDriver* instance_id_driver,
+    VapidKeyManager* vapid_key_manager,
+    gcm::GCMDriver* gcm_driver,
+    syncer::LocalDeviceInfoProvider* local_device_info_provider)
+    : sharing_sync_preference_(sharing_sync_preference),
+      instance_id_driver_(instance_id_driver),
+      vapid_key_manager_(vapid_key_manager),
+      gcm_driver_(gcm_driver),
+      local_device_info_provider_(local_device_info_provider),
+      weak_ptr_factory_(this) {}
+
+SharingDeviceRegistration::~SharingDeviceRegistration() = default;
+
+void SharingDeviceRegistration::RegisterDevice(RegistrationCallback callback) {
+  // TODO(himanshujaju) : Extract a static function to convert ECPrivateKey* to
+  // Base64PublicKey in library.
+  crypto::ECPrivateKey* vapid_key = vapid_key_manager_->GetOrCreateKey();
+  if (!vapid_key) {
+    std::move(callback).Run(Result::FAILURE);
+    return;
+  }
+
+  std::string public_key;
+  if (!gcm::GetRawPublicKey(*vapid_key, &public_key)) {
+    std::move(callback).Run(Result::FAILURE);
+    return;
+  }
+
+  std::string base64_public_key;
+  base::Base64UrlEncode(public_key, base::Base64UrlEncodePolicy::OMIT_PADDING,
+                        &base64_public_key);
+
+  instance_id_driver_->GetInstanceID(kSharingFCMAppID)
+      ->GetToken(
+          base64_public_key, kFCMScope,
+          /*options=*/{},
+          /*is_lazy=*/false,
+          base::BindOnce(&SharingDeviceRegistration::OnFCMTokenReceived,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void SharingDeviceRegistration::OnFCMTokenReceived(
+    RegistrationCallback callback,
+    const std::string& fcm_registration_token,
+    instance_id::InstanceID::Result result) {
+  if (result != instance_id::InstanceID::SUCCESS) {
+    std::move(callback).Run(Result::FAILURE);
+    return;
+  }
+
+  gcm_driver_->GetEncryptionInfo(
+      kSharingFCMAppID,
+      base::AdaptCallbackForRepeating(
+          base::BindOnce(&SharingDeviceRegistration::OnEncryptionInfoReceived,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                         fcm_registration_token)));
+}
+
+void SharingDeviceRegistration::OnEncryptionInfoReceived(
+    RegistrationCallback callback,
+    const std::string& fcm_registration_token,
+    const std::string& p256dh,
+    const std::string& auth_secret) const {
+  int device_capabilities = GetDeviceCapabilities();
+  std::string device_guid =
+      local_device_info_provider_->GetLocalDeviceInfo()->guid();
+  SharingSyncPreference::Device device(fcm_registration_token, p256dh,
+                                       auth_secret, device_capabilities);
+
+  sharing_sync_preference_->SetSyncDevice(device_guid, device);
+  std::move(callback).Run(Result::SUCCESS);
+}
+
+int SharingDeviceRegistration::GetDeviceCapabilities() const {
+  int device_capabilities = static_cast<int>(SharingDeviceCapability::kNone);
+  return device_capabilities;
+}
diff --git a/chrome/browser/sharing/sharing_device_registration.h b/chrome/browser/sharing/sharing_device_registration.h
new file mode 100644
index 0000000..22b6ad5
--- /dev/null
+++ b/chrome/browser/sharing/sharing_device_registration.h
@@ -0,0 +1,91 @@
+// Copyright 2019 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 CHROME_BROWSER_SHARING_SHARING_DEVICE_REGISTRATION_H_
+#define CHROME_BROWSER_SHARING_SHARING_DEVICE_REGISTRATION_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/gcm_driver/instance_id/instance_id.h"
+
+namespace instance_id {
+class InstanceIDDriver;
+}
+
+namespace gcm {
+class GCMDriver;
+}
+
+namespace syncer {
+class LocalDeviceInfoProvider;
+}
+
+class SharingSyncPreference;
+
+class VapidKeyManager;
+
+// Responsible for registering and unregistering device with
+// SharingSyncPreference.
+class SharingDeviceRegistration {
+ public:
+  // Result of device registration with Sharing.
+  enum class Result {
+    // Device registered successfully.
+    SUCCESS = 0,
+    // Device registration failed.
+    FAILURE = 1
+  };
+
+  using RegistrationCallback = base::OnceCallback<void(Result)>;
+
+  SharingDeviceRegistration(
+      SharingSyncPreference* prefs,
+      instance_id::InstanceIDDriver* instance_id_driver,
+      VapidKeyManager* vapid_key_manager,
+      gcm::GCMDriver* gcm_driver,
+      syncer::LocalDeviceInfoProvider* device_info_tracker);
+  ~SharingDeviceRegistration();
+
+  // Registers device with sharing sync preferences. Takes a |callback| function
+  // which receives the result of FCM registration for device.
+  void RegisterDevice(RegistrationCallback callback);
+
+ private:
+  // Callback function responsible for validating FCM registration token and
+  // retrieving public encryption key and authentication secret associated with
+  // FCM App ID of Sharing. Also responsible for calling |callback| with
+  // |result| of GetToken.
+  void OnFCMTokenReceived(RegistrationCallback callback,
+                          const std::string& fcm_registration_token,
+                          instance_id::InstanceID::Result result);
+
+  // Callback function responsible for saving device registration information in
+  // SharingSyncPreference.
+  void OnEncryptionInfoReceived(RegistrationCallback callback,
+                                const std::string& fcm_registration_token,
+                                const std::string& p256dh,
+                                const std::string& auth_secret) const;
+
+  // Computes and returns a bitmask of all capabilities supported by the device.
+  int GetDeviceCapabilities() const;
+
+  SharingSyncPreference* sharing_sync_preference_;
+
+  instance_id::InstanceIDDriver* instance_id_driver_;
+
+  VapidKeyManager* vapid_key_manager_;
+
+  gcm::GCMDriver* gcm_driver_;
+
+  syncer::LocalDeviceInfoProvider* local_device_info_provider_;
+
+  base::WeakPtrFactory<SharingDeviceRegistration> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharingDeviceRegistration);
+};
+
+#endif  // CHROME_BROWSER_SHARING_SHARING_DEVICE_REGISTRATION_H_
diff --git a/chrome/browser/sharing/sharing_device_registration_unittest.cc b/chrome/browser/sharing/sharing_device_registration_unittest.cc
new file mode 100644
index 0000000..ac088831
--- /dev/null
+++ b/chrome/browser/sharing/sharing_device_registration_unittest.cc
@@ -0,0 +1,184 @@
+// Copyright 2019 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 "chrome/browser/sharing/sharing_device_registration.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "chrome/browser/sharing/fake_local_device_info_provider.h"
+#include "chrome/browser/sharing/sharing_device_info.h"
+#include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "components/gcm_driver/fake_gcm_driver.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/sync_device_info/device_info.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "google_apis/gcm/engine/account_mapping.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace gcm;
+using namespace instance_id;
+using namespace testing;
+
+namespace {
+const char kAppID[] = "test_app_id";
+const char kFCMToken[] = "test_fcm_token";
+const char kDevicep256dh[] = "test_p256_dh";
+const char kDeviceAuthSecret[] = "test_auth_secret";
+
+class MockInstanceIDDriver : public InstanceIDDriver {
+ public:
+  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
+  ~MockInstanceIDDriver() override = default;
+
+  MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockInstanceIDDriver);
+};
+
+class FakeInstanceID : public InstanceID {
+ public:
+  FakeInstanceID() : InstanceID(kAppID, /*gcm_driver = */ nullptr) {}
+  ~FakeInstanceID() override = default;
+
+  void GetID(const GetIDCallback& callback) override { NOTIMPLEMENTED(); }
+
+  void GetCreationTime(const GetCreationTimeCallback& callback) override {
+    NOTIMPLEMENTED();
+  }
+
+  void GetToken(const std::string& authorized_entity,
+                const std::string& scope,
+                const std::map<std::string, std::string>& options,
+                bool is_lazy,
+                GetTokenCallback callback) override {
+    std::move(callback).Run(kFCMToken, result_);
+  }
+
+  void ValidateToken(const std::string& authorized_entity,
+                     const std::string& scope,
+                     const std::string& token,
+                     const ValidateTokenCallback& callback) override {
+    NOTIMPLEMENTED();
+  }
+
+  void DeleteTokenImpl(const std::string& authorized_entity,
+                       const std::string& scope,
+                       DeleteTokenCallback callback) override {
+    NOTIMPLEMENTED();
+  }
+
+  void DeleteIDImpl(DeleteIDCallback callback) override { NOTIMPLEMENTED(); }
+
+  void SetFCMResult(InstanceID::Result result) { result_ = result; }
+
+ private:
+  InstanceID::Result result_;
+};
+
+class FakeEncryptionGCMDriver : public FakeGCMDriver {
+ public:
+  FakeEncryptionGCMDriver() {}
+  ~FakeEncryptionGCMDriver() override {}
+
+  void GetEncryptionInfo(const std::string& app_id,
+                         const GetEncryptionInfoCallback& callback) override {
+    std::move(callback).Run(kDevicep256dh, kDeviceAuthSecret);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeEncryptionGCMDriver);
+};
+
+class SharingDeviceRegistrationTest : public testing::Test {
+ public:
+  SharingDeviceRegistrationTest()
+      : sync_prefs_(&prefs_),
+        vapid_key_manager_(&sync_prefs_),
+        sharing_device_registration_(&sync_prefs_,
+                                     &mock_instance_id_driver_,
+                                     &vapid_key_manager_,
+                                     &fake_encryption_gcm_driver_,
+                                     &fake_local_device_info_provider_) {
+    SharingSyncPreference::RegisterProfilePrefs(prefs_.registry());
+  }
+
+  void SetUp() {
+    ON_CALL(mock_instance_id_driver_, GetInstanceID(_))
+        .WillByDefault(testing::Return(&fake_instance_id_));
+  }
+
+  void RegisterDeviceSync() {
+    base::RunLoop run_loop;
+    sharing_device_registration_.RegisterDevice(
+        base::BindLambdaForTesting([&](SharingDeviceRegistration::Result r) {
+          result_ = r;
+          devices_ = sync_prefs_.GetSyncedDevices();
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+  }
+
+  void SetInstanceIDFCMResult(InstanceID::Result result) {
+    fake_instance_id_.SetFCMResult(result);
+  }
+
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  sync_preferences::TestingPrefServiceSyncable prefs_;
+  FakeEncryptionGCMDriver fake_encryption_gcm_driver_;
+  NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
+  FakeLocalDeviceInfoProvider fake_local_device_info_provider_;
+  FakeInstanceID fake_instance_id_;
+
+  SharingSyncPreference sync_prefs_;
+  VapidKeyManager vapid_key_manager_;
+  SharingDeviceRegistration sharing_device_registration_;
+
+  // callback results
+  std::map<std::string, SharingSyncPreference::Device> devices_;
+  SharingDeviceRegistration::Result result_;
+};
+
+}  // namespace
+
+TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_Success) {
+  SetInstanceIDFCMResult(InstanceID::Result::SUCCESS);
+
+  RegisterDeviceSync();
+
+  EXPECT_EQ(SharingDeviceRegistration::Result::SUCCESS, result_);
+  std::string guid =
+      fake_local_device_info_provider_.GetLocalDeviceInfo()->guid();
+  auto it = devices_.find(guid);
+
+  ASSERT_NE(devices_.end(), it);
+  SharingSyncPreference::Device device(std::move(it->second));
+  EXPECT_EQ(kDeviceAuthSecret, device.auth_secret);
+  EXPECT_EQ(kDevicep256dh, device.p256dh);
+  EXPECT_EQ(kFCMToken, device.fcm_token);
+  EXPECT_EQ(static_cast<int>(SharingDeviceCapability::kNone),
+            device.capabilities);
+}
+
+TEST_F(SharingDeviceRegistrationTest, RegisterDeviceTest_Fail) {
+  SetInstanceIDFCMResult(InstanceID::Result::NETWORK_ERROR);
+
+  RegisterDeviceSync();
+
+  EXPECT_EQ(SharingDeviceRegistration::Result::FAILURE, result_);
+  std::string guid =
+      fake_local_device_info_provider_.GetLocalDeviceInfo()->guid();
+  auto it = devices_.find(guid);
+  EXPECT_EQ(devices_.end(), it);
+}
diff --git a/chrome/browser/sharing/sharing_fcm_handler.cc b/chrome/browser/sharing/sharing_fcm_handler.cc
index 65f9b2f4..f8e8010 100644
--- a/chrome/browser/sharing/sharing_fcm_handler.cc
+++ b/chrome/browser/sharing/sharing_fcm_handler.cc
@@ -4,15 +4,12 @@
 
 #include "chrome/browser/sharing/sharing_fcm_handler.h"
 
+#include "chrome/browser/sharing/fcm_constants.h"
 #include "chrome/browser/sharing/sharing_fcm_sender.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
 #include "chrome/browser/sharing/sharing_service_factory.h"
 #include "components/gcm_driver/gcm_driver.h"
 
-namespace {
-const char kSharingFCMAppID[] = "com.google.chrome.sharing.fcm";
-}  // namespace
-
 SharingFCMHandler::SharingFCMHandler(gcm::GCMDriver* gcm_driver,
                                      SharingFCMSender* sharing_fcm_sender)
     : gcm_driver_(gcm_driver),
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc
index 1a7ed4a..dfc65d32 100644
--- a/chrome/browser/sharing/sharing_service.cc
+++ b/chrome/browser/sharing/sharing_service.cc
@@ -8,10 +8,16 @@
 #include <map>
 #include <unordered_set>
 
+#include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/time/time.h"
+#include "chrome/browser/sharing/features.h"
 #include "chrome/browser/sharing/sharing_device_info.h"
+#include "chrome/browser/sharing/sharing_device_registration.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
 #include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "components/sync/driver/sync_service.h"
 #include "components/sync_device_info/device_info.h"
 #include "components/sync_device_info/device_info_tracker.h"
 
@@ -22,14 +28,30 @@
 
 SharingService::SharingService(
     std::unique_ptr<SharingSyncPreference> sync_prefs,
-    syncer::DeviceInfoTracker* device_info_tracker)
+    std::unique_ptr<SharingDeviceRegistration> sharing_device_registration,
+    std::unique_ptr<VapidKeyManager> vapid_key_manager,
+    syncer::DeviceInfoTracker* device_info_tracker,
+    syncer::SyncService* sync_service)
     : sync_prefs_(std::move(sync_prefs)),
-      device_info_tracker_(device_info_tracker) {
+      sharing_device_registration_(std::move(sharing_device_registration)),
+      vapid_key_manager_(std::move(vapid_key_manager)),
+      device_info_tracker_(device_info_tracker),
+      sync_service_(sync_service),
+      weak_ptr_factory_(this) {
   DCHECK(sync_prefs_);
+  DCHECK(sharing_device_registration_);
+  DCHECK(vapid_key_manager_);
   DCHECK(device_info_tracker_);
+  DCHECK(sync_service_);
+
+  if (!sync_service_->HasObserver(this))
+    sync_service_->AddObserver(this);
 }
 
-SharingService::~SharingService() = default;
+SharingService::~SharingService() {
+  if (sync_service_ && sync_service_->HasObserver(this))
+    sync_service_->RemoveObserver(this);
+}
 
 std::vector<SharingDeviceInfo> SharingService::GetDeviceCandidates(
     int required_capabilities) const {
@@ -88,3 +110,33 @@
 void SharingService::RegisterHandler(
     chrome_browser_sharing::SharingMessage::PayloadCase payload_type,
     SharingMessageHandler* handler) {}
+
+void SharingService::OnSyncShutdown(syncer::SyncService* sync) {
+  if (sync_service_ && sync_service_->HasObserver(this))
+    sync_service_->RemoveObserver(this);
+  sync_service_ = nullptr;
+}
+
+void SharingService::OnStateChanged(syncer::SyncService* sync) {
+  if (IsEnabled()) {
+    sharing_device_registration_->RegisterDevice(base::BindOnce(
+        &SharingService::OnDeviceRegistered, weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void SharingService::OnDeviceRegistered(
+    SharingDeviceRegistration::Result result) {
+  // TODO(himanshujaju) : Add retry logic and logging
+}
+
+bool SharingService::IsEnabled() const {
+  bool sync_enabled_and_active =
+      sync_service_ &&
+      sync_service_->GetTransportState() ==
+          syncer::SyncService::TransportState::ACTIVE &&
+      sync_service_->GetActiveDataTypes().Has(syncer::PREFERENCES);
+  bool device_registration_enabled =
+      base::FeatureList::IsEnabled(kSharingDeviceRegistration);
+
+  return sync_enabled_and_active && device_registration_enabled;
+}
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h
index 4002fd6..dbe05d67 100644
--- a/chrome/browser/sharing/sharing_service.h
+++ b/chrome/browser/sharing/sharing_service.h
@@ -9,23 +9,32 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/sharing/proto/sharing_message.pb.h"
+#include "chrome/browser/sharing/sharing_device_registration.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/driver/sync_service_observer.h"
 
 namespace syncer {
 class DeviceInfoTracker;
+class SyncService;
 }  // namespace syncer
 
 class SharingDeviceInfo;
 class SharingMessageHandler;
 class SharingSyncPreference;
+class VapidKeyManager;
 
 // Class to manage lifecycle of sharing feature, and provide APIs to send
 // sharing messages to other devices.
-class SharingService : public KeyedService {
+class SharingService : public KeyedService, syncer::SyncServiceObserver {
  public:
-  SharingService(std::unique_ptr<SharingSyncPreference> sync_prefs,
-                 syncer::DeviceInfoTracker* device_info_tracker);
+  SharingService(
+      std::unique_ptr<SharingSyncPreference> sync_prefs,
+      std::unique_ptr<SharingDeviceRegistration> sharing_device_registration,
+      std::unique_ptr<VapidKeyManager> vapid_key_manager,
+      syncer::DeviceInfoTracker* device_info_tracker,
+      syncer::SyncService* sync_service);
   ~SharingService() override;
 
   // Returns a list of DeviceInfo that is available to receive messages.
@@ -45,8 +54,22 @@
       SharingMessageHandler* handler);
 
  private:
+  // Overrides for syncer::SyncServiceObserver.
+  void OnSyncShutdown(syncer::SyncService* sync) override;
+  void OnStateChanged(syncer::SyncService* sync) override;
+
+  void OnDeviceRegistered(SharingDeviceRegistration::Result result);
+
+  // Returns true if cross-device Sharing features enabled, false otherwise.
+  bool IsEnabled() const;
+
   std::unique_ptr<SharingSyncPreference> sync_prefs_;
+  std::unique_ptr<SharingDeviceRegistration> sharing_device_registration_;
+  std::unique_ptr<VapidKeyManager> vapid_key_manager_;
   syncer::DeviceInfoTracker* device_info_tracker_;
+  syncer::SyncService* sync_service_;
+
+  base::WeakPtrFactory<SharingService> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SharingService);
 };
diff --git a/chrome/browser/sharing/sharing_service_factory.cc b/chrome/browser/sharing/sharing_service_factory.cc
index 7b294a2..9dc7c105 100644
--- a/chrome/browser/sharing/sharing_service_factory.cc
+++ b/chrome/browser/sharing/sharing_service_factory.cc
@@ -7,13 +7,23 @@
 #include <memory>
 
 #include "base/memory/singleton.h"
+#include "chrome/browser/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sharing/sharing_device_registration.h"
 #include "chrome/browser/sharing/sharing_service.h"
 #include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/gcm_profile_service.h"
+#include "components/gcm_driver/instance_id/instance_id_profile_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/sync/driver/sync_service.h"
 #include "components/sync_device_info/device_info_sync_service.h"
+#include "components/sync_device_info/local_device_info_provider.h"
 #include "content/public/browser/browser_context.h"
 
 namespace {
@@ -36,7 +46,10 @@
     : BrowserContextKeyedServiceFactory(
           kServiceName,
           BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(gcm::GCMProfileServiceFactory::GetInstance());
+  DependsOn(instance_id::InstanceIDProfileServiceFactory::GetInstance());
   DependsOn(DeviceInfoSyncServiceFactory::GetInstance());
+  DependsOn(ProfileSyncServiceFactory::GetInstance());
 }
 
 SharingServiceFactory::~SharingServiceFactory() = default;
@@ -44,15 +57,36 @@
 KeyedService* SharingServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
+  syncer::SyncService* sync_service =
+      ProfileSyncServiceFactory::GetForProfile(profile);
 
+  if (!sync_service)
+    return nullptr;
+
+  gcm::GCMProfileService* gcm_profile_service =
+      gcm::GCMProfileServiceFactory::GetForProfile(profile);
+  instance_id::InstanceIDProfileService* instance_id_service =
+      instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile);
   syncer::DeviceInfoTracker* device_info_tracker =
       DeviceInfoSyncServiceFactory::GetForProfile(profile)
           ->GetDeviceInfoTracker();
+  syncer::LocalDeviceInfoProvider* local_device_info_provider =
+      DeviceInfoSyncServiceFactory::GetForProfile(profile)
+          ->GetLocalDeviceInfoProvider();
 
   std::unique_ptr<SharingSyncPreference> sync_prefs =
       std::make_unique<SharingSyncPreference>(profile->GetPrefs());
+  std::unique_ptr<VapidKeyManager> vapid_key_manager =
+      std::make_unique<VapidKeyManager>(sync_prefs.get());
+  std::unique_ptr<SharingDeviceRegistration> sharing_device_registration =
+      std::make_unique<SharingDeviceRegistration>(
+          sync_prefs.get(), instance_id_service->driver(),
+          vapid_key_manager.get(), gcm_profile_service->driver(),
+          local_device_info_provider);
 
-  return new SharingService(std::move(sync_prefs), device_info_tracker);
+  return new SharingService(
+      std::move(sync_prefs), std::move(sharing_device_registration),
+      std::move(vapid_key_manager), device_info_tracker, sync_service);
 }
 
 content::BrowserContext* SharingServiceFactory::GetBrowserContextToUse(
@@ -60,8 +94,10 @@
   return chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
+// Due to the dependency on SyncService, this cannot be instantiated before
+// the profile is fully initialized.
 bool SharingServiceFactory::ServiceIsCreatedWithBrowserContext() const {
-  return true;
+  return false;
 }
 
 bool SharingServiceFactory::ServiceIsNULLWhileTesting() const {
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc
index 3e41aa2..78f18aa 100644
--- a/chrome/browser/sharing/sharing_service_unittest.cc
+++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -10,26 +10,52 @@
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/scoped_task_environment.h"
+#include "chrome/browser/sharing/fake_local_device_info_provider.h"
 #include "chrome/browser/sharing/sharing_device_info.h"
+#include "chrome/browser/sharing/sharing_device_registration.h"
 #include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/sharing/vapid_key_manager.h"
+#include "components/gcm_driver/fake_gcm_driver.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
+#include "components/sync/driver/fake_sync_service.h"
 #include "components/sync_device_info/device_info.h"
 #include "components/sync_device_info/fake_device_info_tracker.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::test::ScopedTaskEnvironment;
+using namespace instance_id;
+using namespace testing;
 
 namespace {
 
 constexpr int kNoCapabilities =
     static_cast<int>(SharingDeviceCapability::kNone);
 
+class MockInstanceIDDriver : public InstanceIDDriver {
+ public:
+  MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {}
+  ~MockInstanceIDDriver() override = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockInstanceIDDriver);
+};
+
 class SharingServiceTest : public testing::Test {
  public:
   SharingServiceTest() {
     sync_prefs_ = new SharingSyncPreference(&prefs_);
+    vapid_key_manager_ = new VapidKeyManager(sync_prefs_);
+    sharing_device_registration_ = new SharingDeviceRegistration(
+        sync_prefs_, &mock_instance_id_driver_, vapid_key_manager_,
+        &fake_gcm_driver_, &fake_local_device_info_provider_);
+
     sharing_service_ = std::make_unique<SharingService>(
-        base::WrapUnique(sync_prefs_), &device_info_tracker_);
+        base::WrapUnique(sync_prefs_),
+        base::WrapUnique(sharing_device_registration_),
+        base::WrapUnique(vapid_key_manager_), &device_info_tracker_,
+        &fake_sync_service_);
     SharingSyncPreference::RegisterProfilePrefs(prefs_.registry());
   }
 
@@ -53,8 +79,16 @@
       ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME};
 
   syncer::FakeDeviceInfoTracker device_info_tracker_;
-  SharingSyncPreference* sync_prefs_ = nullptr;
-  std::unique_ptr<SharingService> sharing_service_;
+  gcm::FakeGCMDriver fake_gcm_driver_;
+  FakeLocalDeviceInfoProvider fake_local_device_info_provider_;
+  syncer::FakeSyncService fake_sync_service_;
+
+  NiceMock<MockInstanceIDDriver> mock_instance_id_driver_;
+
+  SharingSyncPreference* sync_prefs_;
+  VapidKeyManager* vapid_key_manager_;
+  SharingDeviceRegistration* sharing_device_registration_;
+  std::unique_ptr<SharingService> sharing_service_ = nullptr;
 
  private:
   sync_preferences::TestingPrefServiceSyncable prefs_;
@@ -150,3 +184,5 @@
   ASSERT_EQ(1u, candidates.size());
   EXPECT_EQ(id2, candidates[0].guid());
 }
+
+// TODO(himanshujaju) Add tests for RegisterDevice
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 481aabc..3f84cc3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3049,6 +3049,9 @@
     "../browser/sessions/chrome_serialized_navigation_driver_unittest.cc",
     "../browser/sessions/restore_on_startup_policy_handler_unittest.cc",
     "../browser/sessions/session_common_utils_unittest.cc",
+    "../browser/sharing/fake_local_device_info_provider.cc",
+    "../browser/sharing/fake_local_device_info_provider.h",
+    "../browser/sharing/sharing_device_registration_unittest.cc",
     "../browser/sharing/sharing_fcm_handler_unittest.cc",
     "../browser/sharing/sharing_service_unittest.cc",
     "../browser/sharing/sharing_sync_preference_unittest.cc",