• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/metrics/demographics/demographic_metrics_provider.h"
6 
7 #include "base/feature_list.h"
8 #include "base/metrics/histogram_functions.h"
9 #include "build/chromeos_buildflags.h"
10 #include "components/sync/driver/sync_service_utils.h"
11 #include "third_party/abseil-cpp/absl/types/optional.h"
12 #include "third_party/metrics_proto/ukm/report.pb.h"
13 
14 namespace metrics {
15 
16 namespace {
17 
CanUploadDemographicsToGoogle(syncer::SyncService * sync_service)18 bool CanUploadDemographicsToGoogle(syncer::SyncService* sync_service) {
19   DCHECK(sync_service);
20 
21   // PRIORITY_PREFERENCES is the sync datatype used to propagate demographics
22   // information to the client. In its absence, demographics info is unavailable
23   // thus cannot be uploaded.
24   switch (GetUploadToGoogleState(sync_service, syncer::PRIORITY_PREFERENCES)) {
25     case syncer::UploadState::NOT_ACTIVE:
26       return false;
27     case syncer::UploadState::INITIALIZING:
28       // Note that INITIALIZING is considered good enough, because sync is known
29       // to be enabled, and transient errors don't really matter here.
30     case syncer::UploadState::ACTIVE:
31       return true;
32   }
33 }
34 
35 }  // namespace
36 
37 // static
38 BASE_FEATURE(kDemographicMetricsReporting,
39              "DemographicMetricsReporting",
40              base::FEATURE_ENABLED_BY_DEFAULT);
41 
DemographicMetricsProvider(std::unique_ptr<ProfileClient> profile_client,MetricsLogUploader::MetricServiceType metrics_service_type)42 DemographicMetricsProvider::DemographicMetricsProvider(
43     std::unique_ptr<ProfileClient> profile_client,
44     MetricsLogUploader::MetricServiceType metrics_service_type)
45     : profile_client_(std::move(profile_client)),
46       metrics_service_type_(metrics_service_type) {
47   DCHECK(profile_client_);
48 }
49 
~DemographicMetricsProvider()50 DemographicMetricsProvider::~DemographicMetricsProvider() {}
51 
52 absl::optional<UserDemographics>
ProvideSyncedUserNoisedBirthYearAndGender()53 DemographicMetricsProvider::ProvideSyncedUserNoisedBirthYearAndGender() {
54   // Skip if feature disabled.
55   if (!base::FeatureList::IsEnabled(kDemographicMetricsReporting))
56     return absl::nullopt;
57 
58 #if !BUILDFLAG(IS_CHROMEOS_ASH)
59   // Skip if not exactly one Profile on disk. Having more than one Profile that
60   // is using the browser can make demographics less relevant. This approach
61   // cannot determine if there is more than 1 distinct user using the Profile.
62 
63   // ChromeOS almost always has more than one profile on disk, so this check
64   // doesn't work. We have a profile selection strategy for ChromeOS, so skip
65   // this check for ChromeOS.
66   // TODO(crbug/1145655): LaCros will behave similarly to desktop Chrome and
67   // reduce the number of profiles on disk to one, so remove these #if guards
68   // after LaCros release.
69   if (profile_client_->GetNumberOfProfilesOnDisk() != 1) {
70     LogUserDemographicsStatusInHistogram(
71         UserDemographicsStatus::kMoreThanOneProfile);
72     return absl::nullopt;
73   }
74 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
75 
76   syncer::SyncService* sync_service = profile_client_->GetSyncService();
77   // Skip if no sync service.
78   if (!sync_service) {
79     LogUserDemographicsStatusInHistogram(
80         UserDemographicsStatus::kNoSyncService);
81     return absl::nullopt;
82   }
83 
84   if (!CanUploadDemographicsToGoogle(sync_service)) {
85     LogUserDemographicsStatusInHistogram(
86         UserDemographicsStatus::kSyncNotEnabled);
87     return absl::nullopt;
88   }
89 
90   UserDemographicsResult demographics_result =
91       GetUserNoisedBirthYearAndGenderFromPrefs(
92           profile_client_->GetNetworkTime(), profile_client_->GetLocalState(),
93           profile_client_->GetProfilePrefs());
94   LogUserDemographicsStatusInHistogram(demographics_result.status());
95 
96   if (demographics_result.IsSuccess())
97     return demographics_result.value();
98 
99   return absl::nullopt;
100 }
101 
ProvideCurrentSessionData(ChromeUserMetricsExtension * uma_proto)102 void DemographicMetricsProvider::ProvideCurrentSessionData(
103     ChromeUserMetricsExtension* uma_proto) {
104   ProvideSyncedUserNoisedBirthYearAndGender(uma_proto);
105 }
106 
107 void DemographicMetricsProvider::
ProvideSyncedUserNoisedBirthYearAndGenderToReport(ukm::Report * report)108     ProvideSyncedUserNoisedBirthYearAndGenderToReport(ukm::Report* report) {
109   ProvideSyncedUserNoisedBirthYearAndGender(report);
110 }
111 
LogUserDemographicsStatusInHistogram(UserDemographicsStatus status)112 void DemographicMetricsProvider::LogUserDemographicsStatusInHistogram(
113     UserDemographicsStatus status) {
114   switch (metrics_service_type_) {
115     case MetricsLogUploader::MetricServiceType::UMA:
116       base::UmaHistogramEnumeration("UMA.UserDemographics.Status", status);
117       // If the user demographics data was retrieved successfully, then the user
118       // must be between the ages of |kUserDemographicsMinAgeInYears|+1=21 and
119       // |kUserDemographicsMaxAgeInYears|=85, so the user is not a minor.
120       base::UmaHistogramBoolean("UMA.UserDemographics.IsNoisedAgeOver21Under85",
121                                 status == UserDemographicsStatus::kSuccess);
122       return;
123     case MetricsLogUploader::MetricServiceType::UKM:
124       base::UmaHistogramEnumeration("UKM.UserDemographics.Status", status);
125       return;
126   }
127   NOTREACHED();
128 }
129 
130 }  // namespace metrics
131