Retrieve UMA consent for a given device.

This method is needed before updating the new "full_hardware_class"
field to our DeviceInfoSpecifics proto. We must check whether the user
has given UMA consent before sending hardware class information apart of
the Chrome Sync ping.

Currently, the UMA consent can be retireved once the browser process
begins by calling IsMetricsAndCrashReportingEnabled() in
ChromeMetricsServiceAccessor class.

Bug: 1188978
Change-Id: I154de47c2acf1c6d5e2e44e13291a55f31bd8436
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2816348
Commit-Queue: Hirthanan Subenderan <[email protected]>
Auto-Submit: Hirthanan Subenderan <[email protected]>
Reviewed-by: Rushan Suleymanov <[email protected]>
Reviewed-by: Weilun Shi <[email protected]>
Reviewed-by: Olivier Robin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#873452}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d57a3e977..c56475a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1731,6 +1731,8 @@
     "sync/bookmark_sync_service_factory.h",
     "sync/chrome_sync_client.cc",
     "sync/chrome_sync_client.h",
+    "sync/device_info_sync_client_impl.cc",
+    "sync/device_info_sync_client_impl.h",
     "sync/device_info_sync_service_factory.cc",
     "sync/device_info_sync_service_factory.h",
     "sync/glue/extensions_activity_monitor.cc",
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.h b/chrome/browser/metrics/chrome_metrics_service_accessor.h
index 01a2da83..727651f 100644
--- a/chrome/browser/metrics/chrome_metrics_service_accessor.h
+++ b/chrome/browser/metrics/chrome_metrics_service_accessor.h
@@ -79,6 +79,10 @@
 class FeedServiceDelegateImpl;
 }  // namespace feed
 
+namespace browser_sync {
+class DeviceInfoSyncClientImpl;
+}  // namespace browser_sync
+
 // This class limits and documents access to metrics service helper methods.
 // Since these methods are private, each user has to be explicitly declared
 // as a 'friend' below.
@@ -128,6 +132,7 @@
   friend class OptimizationGuideKeyedService;
   friend class WebUITabStripFieldTrial;
   friend class feed::FeedServiceDelegateImpl;
+  friend class browser_sync::DeviceInfoSyncClientImpl;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   friend class ChromeCameraAppUIDelegate;
diff --git a/chrome/browser/sync/device_info_sync_client_impl.cc b/chrome/browser/sync/device_info_sync_client_impl.cc
new file mode 100644
index 0000000..1649ab6
--- /dev/null
+++ b/chrome/browser/sync/device_info_sync_client_impl.cc
@@ -0,0 +1,109 @@
+// Copyright 2021 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/sync/device_info_sync_client_impl.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sharing/sharing_sync_preference.h"
+#include "chrome/browser/signin/chrome_device_id_helper.h"
+#include "chrome/browser/sync/sync_invalidations_service_factory.h"
+#include "components/send_tab_to_self/features.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/invalidations/sync_invalidations_service.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/browser/webauthn/android/cable_module_android.h"
+#endif
+
+namespace browser_sync {
+
+DeviceInfoSyncClientImpl::DeviceInfoSyncClientImpl(Profile* profile)
+    : profile_(profile) {}
+
+DeviceInfoSyncClientImpl::~DeviceInfoSyncClientImpl() = default;
+
+// syncer::DeviceInfoSyncClient:
+std::string DeviceInfoSyncClientImpl::GetSigninScopedDeviceId() const {
+// Since the local sync backend is currently only supported on Windows, Mac and
+// Linux don't even check the pref on other os-es.
+// TODO(crbug.com/1052397): Reassess whether the next block needs to be included
+// in lacros-chrome once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+  syncer::SyncPrefs prefs(profile_->GetPrefs());
+  if (prefs.IsLocalSyncEnabled()) {
+    return "local_device";
+  }
+#endif  // defined(OS_WIN) || defined(OS_MAC) || (defined(OS_LINUX) ||
+        // BUILDFLAG(IS_CHROMEOS_LACROS))
+
+  return GetSigninScopedDeviceIdForProfile(profile_);
+}
+
+// syncer::DeviceInfoSyncClient:
+bool DeviceInfoSyncClientImpl::GetSendTabToSelfReceivingEnabled() const {
+  return send_tab_to_self::IsReceivingEnabledByUserOnThisDevice(
+      profile_->GetPrefs());
+}
+
+// syncer::DeviceInfoSyncClient:
+base::Optional<syncer::DeviceInfo::SharingInfo>
+DeviceInfoSyncClientImpl::GetLocalSharingInfo() const {
+  return SharingSyncPreference::GetLocalSharingInfoForSync(
+      profile_->GetPrefs());
+}
+
+// syncer::DeviceInfoSyncClient:
+base::Optional<std::string> DeviceInfoSyncClientImpl::GetFCMRegistrationToken()
+    const {
+  syncer::SyncInvalidationsService* service =
+      SyncInvalidationsServiceFactory::GetForProfile(profile_);
+  if (service) {
+    return service->GetFCMRegistrationToken();
+  }
+  // If the service is not enabled, then the registration token must be empty,
+  // not unknown (base::nullopt). This is needed to reset previous token if
+  // the invalidations have been turned off.
+  return std::string();
+}
+
+// syncer::DeviceInfoSyncClient:
+base::Optional<syncer::ModelTypeSet>
+DeviceInfoSyncClientImpl::GetInterestedDataTypes() const {
+  syncer::SyncInvalidationsService* service =
+      SyncInvalidationsServiceFactory::GetForProfile(profile_);
+  if (service) {
+    return service->GetInterestedDataTypes();
+  }
+  // If the service is not enabled, then the list of types must be empty, not
+  // unknown (base::nullopt). This is needed to reset previous types if the
+  // invalidations have been turned off.
+  return syncer::ModelTypeSet();
+}
+
+base::Optional<syncer::DeviceInfo::PhoneAsASecurityKeyInfo>
+DeviceInfoSyncClientImpl::GetPhoneAsASecurityKeyInfo() const {
+#if defined(OS_ANDROID)
+  return webauthn::authenticator::GetSyncDataIfRegistered();
+#else
+  return base::nullopt;
+#endif
+}
+
+bool DeviceInfoSyncClientImpl::IsUmaEnabledOnCrOSDevice() const {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
+#else
+  return false;
+#endif
+}
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/device_info_sync_client_impl.h b/chrome/browser/sync/device_info_sync_client_impl.h
new file mode 100644
index 0000000..bb06147
--- /dev/null
+++ b/chrome/browser/sync/device_info_sync_client_impl.h
@@ -0,0 +1,54 @@
+// Copyright 2021 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_SYNC_DEVICE_INFO_SYNC_CLIENT_IMPL_H_
+#define CHROME_BROWSER_SYNC_DEVICE_INFO_SYNC_CLIENT_IMPL_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+
+#include "components/sync_device_info/device_info_sync_client.h"
+
+class Profile;
+
+namespace browser_sync {
+
+class DeviceInfoSyncClientImpl : public syncer::DeviceInfoSyncClient {
+ public:
+  explicit DeviceInfoSyncClientImpl(Profile* profile);
+
+  ~DeviceInfoSyncClientImpl() override;
+
+  // syncer::DeviceInfoSyncClient:
+  std::string GetSigninScopedDeviceId() const override;
+
+  // syncer::DeviceInfoSyncClient:
+  bool GetSendTabToSelfReceivingEnabled() const override;
+
+  // syncer::DeviceInfoSyncClient:
+  base::Optional<syncer::DeviceInfo::SharingInfo> GetLocalSharingInfo()
+      const override;
+
+  // syncer::DeviceInfoSyncClient:
+  base::Optional<std::string> GetFCMRegistrationToken() const override;
+
+  // syncer::DeviceInfoSyncClient:
+  base::Optional<syncer::ModelTypeSet> GetInterestedDataTypes() const override;
+
+  // syncer::DeviceInfoSyncClient:
+  base::Optional<syncer::DeviceInfo::PhoneAsASecurityKeyInfo>
+  GetPhoneAsASecurityKeyInfo() const override;
+
+  // syncer::DeviceInfoSyncClient:
+  bool IsUmaEnabledOnCrOSDevice() const override;
+
+ private:
+  Profile* const profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceInfoSyncClientImpl);
+};
+
+}  // namespace browser_sync
+
+#endif  // CHROME_BROWSER_SYNC_DEVICE_INFO_SYNC_CLIENT_IMPL_H_
diff --git a/chrome/browser/sync/device_info_sync_service_factory.cc b/chrome/browser/sync/device_info_sync_service_factory.cc
index 687b18a..5ceb414 100644
--- a/chrome/browser/sync/device_info_sync_service_factory.cc
+++ b/chrome/browser/sync/device_info_sync_service_factory.cc
@@ -17,104 +17,17 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/sharing/sharing_sync_preference.h"
-#include "chrome/browser/signin/chrome_device_id_helper.h"
+#include "chrome/browser/sync/device_info_sync_client_impl.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
 #include "chrome/common/channel_info.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/send_tab_to_self/features.h"
-#include "components/sync/base/sync_prefs.h"
 #include "components/sync/invalidations/sync_invalidations_service.h"
 #include "components/sync/model/model_type_store_service.h"
 #include "components/sync_device_info/device_info_prefs.h"
-#include "components/sync_device_info/device_info_sync_client.h"
 #include "components/sync_device_info/device_info_sync_service_impl.h"
 #include "components/sync_device_info/local_device_info_provider_impl.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/webauthn/android/cable_module_android.h"
-#endif
-
-namespace {
-
-class DeviceInfoSyncClient : public syncer::DeviceInfoSyncClient {
- public:
-  explicit DeviceInfoSyncClient(Profile* profile) : profile_(profile) {}
-  ~DeviceInfoSyncClient() override = default;
-
-  // syncer::DeviceInfoSyncClient:
-  std::string GetSigninScopedDeviceId() const override {
-// Since the local sync backend is currently only supported on Windows, Mac and
-// Linux don't even check the pref on other os-es.
-// TODO(crbug.com/1052397): Reassess whether the next block needs to be included
-// in lacros-chrome once build flag switch of lacros-chrome is
-// complete.
-#if defined(OS_WIN) || defined(OS_MAC) || \
-    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
-    syncer::SyncPrefs prefs(profile_->GetPrefs());
-    if (prefs.IsLocalSyncEnabled()) {
-      return "local_device";
-    }
-#endif  // defined(OS_WIN) || defined(OS_MAC) || (defined(OS_LINUX) ||
-        // BUILDFLAG(IS_CHROMEOS_LACROS))
-
-    return GetSigninScopedDeviceIdForProfile(profile_);
-  }
-
-  // syncer::DeviceInfoSyncClient:
-  bool GetSendTabToSelfReceivingEnabled() const override {
-    return send_tab_to_self::IsReceivingEnabledByUserOnThisDevice(
-        profile_->GetPrefs());
-  }
-
-  // syncer::DeviceInfoSyncClient:
-  base::Optional<syncer::DeviceInfo::SharingInfo> GetLocalSharingInfo()
-      const override {
-    return SharingSyncPreference::GetLocalSharingInfoForSync(
-        profile_->GetPrefs());
-  }
-
-  // syncer::DeviceInfoSyncClient:
-  base::Optional<std::string> GetFCMRegistrationToken() const override {
-    syncer::SyncInvalidationsService* service =
-        SyncInvalidationsServiceFactory::GetForProfile(profile_);
-    if (service) {
-      return service->GetFCMRegistrationToken();
-    }
-    // If the service is not enabled, then the registration token must be empty,
-    // not unknown (base::nullopt). This is needed to reset previous token if
-    // the invalidations have been turned off.
-    return std::string();
-  }
-
-  // syncer::DeviceInfoSyncClient:
-  base::Optional<syncer::ModelTypeSet> GetInterestedDataTypes() const override {
-    syncer::SyncInvalidationsService* service =
-        SyncInvalidationsServiceFactory::GetForProfile(profile_);
-    if (service) {
-      return service->GetInterestedDataTypes();
-    }
-    // If the service is not enabled, then the list of types must be empty, not
-    // unknown (base::nullopt). This is needed to reset previous types if the
-    // invalidations have been turned off.
-    return syncer::ModelTypeSet();
-  }
-
-  base::Optional<syncer::DeviceInfo::PhoneAsASecurityKeyInfo>
-  GetPhoneAsASecurityKeyInfo() const override {
-#if defined(OS_ANDROID)
-    return webauthn::authenticator::GetSyncDataIfRegistered();
-#else
-    return base::nullopt;
-#endif
-  }
-
- private:
-  Profile* const profile_;
-};
-
-}  // namespace
 
 // static
 syncer::DeviceInfoSyncService* DeviceInfoSyncServiceFactory::GetForProfile(
@@ -164,7 +77,7 @@
   Profile* profile = Profile::FromBrowserContext(context);
 
   auto device_info_sync_client =
-      std::make_unique<DeviceInfoSyncClient>(profile);
+      std::make_unique<browser_sync::DeviceInfoSyncClientImpl>(profile);
   auto local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
           chrome::GetChannel(),
diff --git a/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc b/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc
index 22753a8..4ab0f6c 100644
--- a/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_device_info_sync_test.cc
@@ -8,6 +8,7 @@
 #include "base/test/bind.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/sync/test/integration/device_info_helper.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -27,6 +28,7 @@
 
 namespace {
 
+using testing::Contains;
 using testing::ElementsAre;
 using testing::IsSupersetOf;
 using testing::UnorderedElementsAre;
@@ -35,6 +37,14 @@
   return arg.specifics().device_info().cache_guid() == expected_cache_guid;
 }
 
+MATCHER(HasFullHardwareClass, "") {
+  return !arg.specifics().device_info().full_hardware_class().empty();
+}
+
+MATCHER(IsFullHardwareClassEmpty, "") {
+  return arg.specifics().device_info().full_hardware_class().empty();
+}
+
 std::string CacheGuidForSuffix(int suffix) {
   return base::StringPrintf("cache guid %d", suffix);
 }
@@ -96,6 +106,47 @@
   DISALLOW_COPY_AND_ASSIGN(SingleClientDeviceInfoSyncTest);
 };
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+IN_PROC_BROWSER_TEST_F(SingleClientDeviceInfoSyncTest,
+                       UmaEnabledSetFullHardwareClass) {
+  bool uma_enabled = true;
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+      &uma_enabled);
+  ASSERT_TRUE(SetupSync());
+
+  EXPECT_THAT(fake_server_->GetSyncEntitiesByModelType(syncer::DEVICE_INFO),
+              Contains(HasFullHardwareClass()));
+
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(SingleClientDeviceInfoSyncTest,
+                       UmaDisabledFullHardwareClassEmpty) {
+  bool uma_enabled = false;
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+      &uma_enabled);
+  ASSERT_TRUE(SetupSync());
+
+  EXPECT_THAT(fake_server_->GetSyncEntitiesByModelType(syncer::DEVICE_INFO),
+              Contains(IsFullHardwareClassEmpty()));
+
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
+}
+#else
+IN_PROC_BROWSER_TEST_F(SingleClientDeviceInfoSyncTest,
+                       UmaEnabledFullHardwareClassOnNonChromeOS) {
+  bool uma_enabled = true;
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
+      &uma_enabled);
+  ASSERT_TRUE(SetupSync());
+
+  EXPECT_THAT(fake_server_->GetSyncEntitiesByModelType(syncer::DEVICE_INFO),
+              Contains(IsFullHardwareClassEmpty()));
+
+  ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(nullptr);
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 IN_PROC_BROWSER_TEST_F(SingleClientDeviceInfoSyncTest, CommitLocalDevice) {
   ASSERT_TRUE(SetupSync());