1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_ 6*6777b538SAndroid Build Coastguard Worker #define COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h" 9*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h" 10*6777b538SAndroid Build Coastguard Worker #include "third_party/metrics_proto/user_demographics.pb.h" 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Worker class PrefService; 13*6777b538SAndroid Build Coastguard Worker class PrefRegistrySimple; 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker namespace metrics { 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker // Default value for user gender when no value has been set. 18*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsGenderDefaultValue = -1; 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Worker // Default value for user gender enum when no value has been set. 21*6777b538SAndroid Build Coastguard Worker constexpr UserDemographicsProto_Gender kUserDemographicGenderDefaultEnumValue = 22*6777b538SAndroid Build Coastguard Worker UserDemographicsProto_Gender_Gender_MIN; 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker // Default value for user birth year when no value has been set. 25*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsBirthYearDefaultValue = -1; 26*6777b538SAndroid Build Coastguard Worker 27*6777b538SAndroid Build Coastguard Worker // Default value for birth year offset when no value has been set. Set to a 28*6777b538SAndroid Build Coastguard Worker // really high value that |kUserDemographicsBirthYearNoiseOffsetRange| will 29*6777b538SAndroid Build Coastguard Worker // never go over. 30*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsBirthYearNoiseOffsetDefaultValue = 100; 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker // Boundary of the +/- range in years within witch to randomly pick an offset to 33*6777b538SAndroid Build Coastguard Worker // add to the user birth year. This adds noise to the birth year to not allow 34*6777b538SAndroid Build Coastguard Worker // someone to accurately know a user's age. Possible offsets range from -2 to 2. 35*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsBirthYearNoiseOffsetRange = 2; 36*6777b538SAndroid Build Coastguard Worker 37*6777b538SAndroid Build Coastguard Worker // Minimal user age in years to provide demographics for. 38*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsMinAgeInYears = 20; 39*6777b538SAndroid Build Coastguard Worker 40*6777b538SAndroid Build Coastguard Worker // Max user age to provide demopgrahics for. 41*6777b538SAndroid Build Coastguard Worker constexpr int kUserDemographicsMaxAgeInYears = 85; 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker // Root dictionary pref to store the user's birth year and gender that are 44*6777b538SAndroid Build Coastguard Worker // provided by the sync server. This is a read-only syncable priority pref on 45*6777b538SAndroid Build Coastguard Worker // all platforms except ChromeOS Ash, where it is a syncable OS-level priority 46*6777b538SAndroid Build Coastguard Worker // pref. 47*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_CHROMEOS_ASH) 48*6777b538SAndroid Build Coastguard Worker inline constexpr char kSyncDemographicsPrefName[] = "sync.demographics"; 49*6777b538SAndroid Build Coastguard Worker #else 50*6777b538SAndroid Build Coastguard Worker inline constexpr char kSyncOsDemographicsPrefName[] = "sync.os_demographics"; 51*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): Make this non-syncable (on Ash only) after full rollout 52*6777b538SAndroid Build Coastguard Worker // of the syncable os priority pref; then delete it locally from Ash devices. 53*6777b538SAndroid Build Coastguard Worker inline constexpr char kSyncDemographicsPrefName[] = "sync.demographics"; 54*6777b538SAndroid Build Coastguard Worker #endif 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker // Stores a "secret" offset that is used to randomize the birth year for metrics 57*6777b538SAndroid Build Coastguard Worker // reporting. This value should not be logged to UMA directly; instead, it 58*6777b538SAndroid Build Coastguard Worker // should be summed with the kSyncDemographicsBirthYear. This value is generated 59*6777b538SAndroid Build Coastguard Worker // locally on the client the first time a user begins to merge birth year data 60*6777b538SAndroid Build Coastguard Worker // into their UMA reports. 61*6777b538SAndroid Build Coastguard Worker inline constexpr char kUserDemographicsBirthYearOffsetPrefName[] = 62*6777b538SAndroid Build Coastguard Worker "demographics_birth_year_offset"; 63*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): Delete after 2023/09 64*6777b538SAndroid Build Coastguard Worker inline constexpr char kDeprecatedDemographicsBirthYearOffsetPrefName[] = 65*6777b538SAndroid Build Coastguard Worker "sync.demographics_birth_year_offset"; 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Worker // These are not prefs, they are paths inside of kSyncDemographics. 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker // This pref value is subordinate to the kSyncDemographics dictionary pref and 70*6777b538SAndroid Build Coastguard Worker // is synced to the client. It stores the self-reported birth year of the 71*6777b538SAndroid Build Coastguard Worker // syncing user. as provided by the sync server. This value should not be logged 72*6777b538SAndroid Build Coastguard Worker // to UMA directly; instead, it should be summed with the 73*6777b538SAndroid Build Coastguard Worker // kSyncDemographicsBirthYearNoiseOffset. 74*6777b538SAndroid Build Coastguard Worker inline constexpr char kSyncDemographicsBirthYearPath[] = "birth_year"; 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker // This pref value is subordinate to the kSyncDemographics dictionary pref and 77*6777b538SAndroid Build Coastguard Worker // is synced to the client. It stores the self-reported gender of the syncing 78*6777b538SAndroid Build Coastguard Worker // user, as provided by the sync server. The gender is encoded using the Gender 79*6777b538SAndroid Build Coastguard Worker // enum defined in UserDemographicsProto 80*6777b538SAndroid Build Coastguard Worker // (see third_party/metrics_proto/user_demographics.proto). 81*6777b538SAndroid Build Coastguard Worker inline constexpr char kSyncDemographicsGenderPath[] = "gender"; 82*6777b538SAndroid Build Coastguard Worker 83*6777b538SAndroid Build Coastguard Worker // Container of user demographics. 84*6777b538SAndroid Build Coastguard Worker struct UserDemographics { 85*6777b538SAndroid Build Coastguard Worker int birth_year = 0; 86*6777b538SAndroid Build Coastguard Worker UserDemographicsProto_Gender gender = UserDemographicsProto::Gender_MIN; 87*6777b538SAndroid Build Coastguard Worker }; 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker // Represents the status of providing user demographics (noised birth year and 90*6777b538SAndroid Build Coastguard Worker // gender) that are logged to UMA. Entries of the enum should not be renumbered 91*6777b538SAndroid Build Coastguard Worker // and numeric values should never be reused. Please keep in sync with 92*6777b538SAndroid Build Coastguard Worker // "UserDemographicsStatus" in src/tools/metrics/histograms/enums.xml. There 93*6777b538SAndroid Build Coastguard Worker // should only be one entry representing demographic data that is ineligible to 94*6777b538SAndroid Build Coastguard Worker // be provided. A finer grained division of kIneligibleDemographicsData (e.g., 95*6777b538SAndroid Build Coastguard Worker // INVALID_BIRTH_YEAR) might help inferring categories of demographics that 96*6777b538SAndroid Build Coastguard Worker // should not be exposed to protect privacy. 97*6777b538SAndroid Build Coastguard Worker enum class UserDemographicsStatus { 98*6777b538SAndroid Build Coastguard Worker // Could get the user's noised birth year and gender. 99*6777b538SAndroid Build Coastguard Worker kSuccess = 0, 100*6777b538SAndroid Build Coastguard Worker // Sync is not enabled. 101*6777b538SAndroid Build Coastguard Worker kSyncNotEnabled = 1, 102*6777b538SAndroid Build Coastguard Worker // User's birth year and gender are ineligible to be provided either because 103*6777b538SAndroid Build Coastguard Worker // some of them don't exist (missing data) or some of them are not eligible to 104*6777b538SAndroid Build Coastguard Worker // be provided. 105*6777b538SAndroid Build Coastguard Worker kIneligibleDemographicsData = 2, 106*6777b538SAndroid Build Coastguard Worker // Could not get the time needed to compute the user's age. 107*6777b538SAndroid Build Coastguard Worker kCannotGetTime = 3, 108*6777b538SAndroid Build Coastguard Worker // There is more than one Profile for the Chrome browser. This entry is used 109*6777b538SAndroid Build Coastguard Worker // by the DemographicMetricsProvider client. 110*6777b538SAndroid Build Coastguard Worker kMoreThanOneProfile = 4, 111*6777b538SAndroid Build Coastguard Worker // There is no sync service available for the loaded Profile. This entry is 112*6777b538SAndroid Build Coastguard Worker // used by the DemographicMetricsProvider client. 113*6777b538SAndroid Build Coastguard Worker kNoSyncService = 5, 114*6777b538SAndroid Build Coastguard Worker // Upper boundary of the enum that is needed for the histogram. 115*6777b538SAndroid Build Coastguard Worker kMaxValue = kNoSyncService 116*6777b538SAndroid Build Coastguard Worker }; 117*6777b538SAndroid Build Coastguard Worker 118*6777b538SAndroid Build Coastguard Worker // Container and handler for data related to the retrieval of user demographics. 119*6777b538SAndroid Build Coastguard Worker // Holds either valid demographics data or an error code. 120*6777b538SAndroid Build Coastguard Worker class UserDemographicsResult { 121*6777b538SAndroid Build Coastguard Worker public: 122*6777b538SAndroid Build Coastguard Worker // Builds a UserDemographicsResult that contains user demographics and has a 123*6777b538SAndroid Build Coastguard Worker // UserDemographicsStatus::kSuccess status. 124*6777b538SAndroid Build Coastguard Worker static UserDemographicsResult ForValue(UserDemographics value); 125*6777b538SAndroid Build Coastguard Worker 126*6777b538SAndroid Build Coastguard Worker // Builds a UserDemographicsResult that does not have user demographics (only 127*6777b538SAndroid Build Coastguard Worker // default values) and has a status other than 128*6777b538SAndroid Build Coastguard Worker // UserDemographicsStatus::kSuccess. 129*6777b538SAndroid Build Coastguard Worker static UserDemographicsResult ForStatus(UserDemographicsStatus status); 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker // Determines whether demographics could be successfully retrieved. 132*6777b538SAndroid Build Coastguard Worker bool IsSuccess() const; 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker // Gets the status of the result. 135*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus status() const; 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker // Gets the value of the result which will contain data when status() is 138*6777b538SAndroid Build Coastguard Worker // UserDemographicsStatus::kSuccess. 139*6777b538SAndroid Build Coastguard Worker const UserDemographics& value() const; 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker private: 142*6777b538SAndroid Build Coastguard Worker UserDemographicsResult(UserDemographics value, UserDemographicsStatus status); 143*6777b538SAndroid Build Coastguard Worker 144*6777b538SAndroid Build Coastguard Worker UserDemographics value_; 145*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus status_ = UserDemographicsStatus::kMaxValue; 146*6777b538SAndroid Build Coastguard Worker }; 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker // Registers the local state preferences that are needed to persist demographics 149*6777b538SAndroid Build Coastguard Worker // information exposed via GetUserNoisedBirthYearAndGenderFromPrefs(). 150*6777b538SAndroid Build Coastguard Worker void RegisterDemographicsLocalStatePrefs(PrefRegistrySimple* registry); 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker // Registers the profile preferences that are needed to persist demographics 153*6777b538SAndroid Build Coastguard Worker // information exposed via GetUserNoisedBirthYearAndGenderFromPrefs(). 154*6777b538SAndroid Build Coastguard Worker void RegisterDemographicsProfilePrefs(PrefRegistrySimple* registry); 155*6777b538SAndroid Build Coastguard Worker 156*6777b538SAndroid Build Coastguard Worker // Clears the profile's demographics-related preferences containing user data. 157*6777b538SAndroid Build Coastguard Worker // This excludes the internal birth year offset. 158*6777b538SAndroid Build Coastguard Worker void ClearDemographicsPrefs(PrefService* profile_prefs); 159*6777b538SAndroid Build Coastguard Worker 160*6777b538SAndroid Build Coastguard Worker // Gets the synced user’s birth year and gender from |profile_prefs|, and noise 161*6777b538SAndroid Build Coastguard Worker // from |local_state|. See docs for metrics::DemographicMetricsProvider in 162*6777b538SAndroid Build Coastguard Worker // components/metrics/demographic_metrics_provider.h for more details. Returns 163*6777b538SAndroid Build Coastguard Worker // an error status with an empty value when the user's birth year or gender 164*6777b538SAndroid Build Coastguard Worker // cannot be provided. You need to provide an accurate |now| time that 165*6777b538SAndroid Build Coastguard Worker // represents the current time. 166*6777b538SAndroid Build Coastguard Worker UserDemographicsResult GetUserNoisedBirthYearAndGenderFromPrefs( 167*6777b538SAndroid Build Coastguard Worker base::Time now, 168*6777b538SAndroid Build Coastguard Worker PrefService* local_state, 169*6777b538SAndroid Build Coastguard Worker PrefService* profile_prefs); 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker } // namespace metrics 172*6777b538SAndroid Build Coastguard Worker 173*6777b538SAndroid Build Coastguard Worker #endif // COMPONENTS_METRICS_DEMOGRAPHICS_USER_DEMOGRAPHICS_H_ 174