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 #include "components/metrics/demographics/user_demographics.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <optional>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
13*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
14*6777b538SAndroid Build Coastguard Worker #include "components/pref_registry/pref_registry_syncable.h"
15*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_service.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace metrics {
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_CHROMEOS_ASH)
20*6777b538SAndroid Build Coastguard Worker constexpr auto kSyncDemographicsPrefFlags =
21*6777b538SAndroid Build Coastguard Worker user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF;
22*6777b538SAndroid Build Coastguard Worker #else
23*6777b538SAndroid Build Coastguard Worker constexpr auto kSyncOsDemographicsPrefFlags =
24*6777b538SAndroid Build Coastguard Worker user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PRIORITY_PREF;
25*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): Make this non-syncable (on Ash only) after full rollout
26*6777b538SAndroid Build Coastguard Worker // of the syncable os priority pref; then delete it locally from Ash devices.
27*6777b538SAndroid Build Coastguard Worker constexpr auto kSyncDemographicsPrefFlags =
28*6777b538SAndroid Build Coastguard Worker user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF;
29*6777b538SAndroid Build Coastguard Worker #endif
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker constexpr auto kUserDemographicsBirthYearOffsetPrefFlags =
32*6777b538SAndroid Build Coastguard Worker PrefRegistry::NO_REGISTRATION_FLAGS;
33*6777b538SAndroid Build Coastguard Worker constexpr auto kDeprecatedDemographicsBirthYearOffsetPrefFlags =
34*6777b538SAndroid Build Coastguard Worker PrefRegistry::NO_REGISTRATION_FLAGS;
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker namespace {
37*6777b538SAndroid Build Coastguard Worker
GetDemographicsDict(PrefService * profile_prefs)38*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& GetDemographicsDict(PrefService* profile_prefs) {
39*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
40*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): On Ash only, clear sync demographics pref once
41*6777b538SAndroid Build Coastguard Worker // os-level syncable pref is fully rolled out and Ash drops support for
42*6777b538SAndroid Build Coastguard Worker // non-os-level syncable prefs.
43*6777b538SAndroid Build Coastguard Worker if (profile_prefs->HasPrefPath(kSyncOsDemographicsPrefName)) {
44*6777b538SAndroid Build Coastguard Worker return profile_prefs->GetDict(kSyncOsDemographicsPrefName);
45*6777b538SAndroid Build Coastguard Worker }
46*6777b538SAndroid Build Coastguard Worker #endif
47*6777b538SAndroid Build Coastguard Worker return profile_prefs->GetDict(kSyncDemographicsPrefName);
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker
MigrateBirthYearOffset(PrefService * to_local_state,PrefService * from_profile_prefs)50*6777b538SAndroid Build Coastguard Worker void MigrateBirthYearOffset(PrefService* to_local_state,
51*6777b538SAndroid Build Coastguard Worker PrefService* from_profile_prefs) {
52*6777b538SAndroid Build Coastguard Worker const int profile_offset = from_profile_prefs->GetInteger(
53*6777b538SAndroid Build Coastguard Worker kDeprecatedDemographicsBirthYearOffsetPrefName);
54*6777b538SAndroid Build Coastguard Worker if (profile_offset == kUserDemographicsBirthYearNoiseOffsetDefaultValue)
55*6777b538SAndroid Build Coastguard Worker return;
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): clear/remove deprecated pref after 2023/09
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker const int local_offset =
60*6777b538SAndroid Build Coastguard Worker to_local_state->GetInteger(kUserDemographicsBirthYearOffsetPrefName);
61*6777b538SAndroid Build Coastguard Worker if (local_offset == kUserDemographicsBirthYearNoiseOffsetDefaultValue) {
62*6777b538SAndroid Build Coastguard Worker to_local_state->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
63*6777b538SAndroid Build Coastguard Worker profile_offset);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker }
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker // Returns the noise offset for the birth year. If not found in |local_state|,
68*6777b538SAndroid Build Coastguard Worker // the offset will be randomly generated within the offset range and cached in
69*6777b538SAndroid Build Coastguard Worker // |local_state|.
GetBirthYearOffset(PrefService * local_state)70*6777b538SAndroid Build Coastguard Worker int GetBirthYearOffset(PrefService* local_state) {
71*6777b538SAndroid Build Coastguard Worker int offset =
72*6777b538SAndroid Build Coastguard Worker local_state->GetInteger(kUserDemographicsBirthYearOffsetPrefName);
73*6777b538SAndroid Build Coastguard Worker if (offset == kUserDemographicsBirthYearNoiseOffsetDefaultValue) {
74*6777b538SAndroid Build Coastguard Worker // Generate a new random offset when not already cached.
75*6777b538SAndroid Build Coastguard Worker offset = base::RandInt(-kUserDemographicsBirthYearNoiseOffsetRange,
76*6777b538SAndroid Build Coastguard Worker kUserDemographicsBirthYearNoiseOffsetRange);
77*6777b538SAndroid Build Coastguard Worker local_state->SetInteger(kUserDemographicsBirthYearOffsetPrefName, offset);
78*6777b538SAndroid Build Coastguard Worker }
79*6777b538SAndroid Build Coastguard Worker return offset;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker // Determines whether the synced user has provided a birth year to Google which
83*6777b538SAndroid Build Coastguard Worker // is eligible, once aggregated and anonymized, to measure usage of Chrome
84*6777b538SAndroid Build Coastguard Worker // features by age groups. See doc of DemographicMetricsProvider in
85*6777b538SAndroid Build Coastguard Worker // demographic_metrics_provider.h for more details.
HasEligibleBirthYear(base::Time now,int user_birth_year,int offset)86*6777b538SAndroid Build Coastguard Worker bool HasEligibleBirthYear(base::Time now, int user_birth_year, int offset) {
87*6777b538SAndroid Build Coastguard Worker // Compute user age.
88*6777b538SAndroid Build Coastguard Worker base::Time::Exploded exploded_now_time;
89*6777b538SAndroid Build Coastguard Worker now.LocalExplode(&exploded_now_time);
90*6777b538SAndroid Build Coastguard Worker int user_age = exploded_now_time.year - (user_birth_year + offset);
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker // Verify if the synced user's age has a population size in the age
93*6777b538SAndroid Build Coastguard Worker // distribution of the society that is big enough to not raise the entropy of
94*6777b538SAndroid Build Coastguard Worker // the demographics too much. At a certain point, as the age increase, the
95*6777b538SAndroid Build Coastguard Worker // size of the population starts declining sharply as you can see in this
96*6777b538SAndroid Build Coastguard Worker // approximate representation of the age distribution:
97*6777b538SAndroid Build Coastguard Worker // | ________ max age
98*6777b538SAndroid Build Coastguard Worker // |______/ \_________ |
99*6777b538SAndroid Build Coastguard Worker // | |\
100*6777b538SAndroid Build Coastguard Worker // | | \
101*6777b538SAndroid Build Coastguard Worker // +--------------------------|---------
102*6777b538SAndroid Build Coastguard Worker // 0 10 20 30 40 50 60 70 80 90 100+
103*6777b538SAndroid Build Coastguard Worker if (user_age > kUserDemographicsMaxAgeInYears)
104*6777b538SAndroid Build Coastguard Worker return false;
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker // Verify if the synced user is old enough. Use > rather than >= because we
107*6777b538SAndroid Build Coastguard Worker // want to be sure that the user is at least |kUserDemographicsMinAgeInYears|
108*6777b538SAndroid Build Coastguard Worker // without disclosing their birth date, which requires to add an extra year
109*6777b538SAndroid Build Coastguard Worker // margin to the minimal age to be safe. For example, if we are in 2019-07-10
110*6777b538SAndroid Build Coastguard Worker // (now) and the user was born in 1999-08-10, the user is not yet 20 years old
111*6777b538SAndroid Build Coastguard Worker // (minimal age) but we cannot know that because we only have access to the
112*6777b538SAndroid Build Coastguard Worker // year of the dates (2019 and 1999 respectively). If we make sure that the
113*6777b538SAndroid Build Coastguard Worker // minimal age (computed at year granularity) is at least 21, we are 100% sure
114*6777b538SAndroid Build Coastguard Worker // that the user will be at least 20 years old when providing the user’s birth
115*6777b538SAndroid Build Coastguard Worker // year and gender.
116*6777b538SAndroid Build Coastguard Worker return user_age > kUserDemographicsMinAgeInYears;
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker // Gets the synced user's birth year from synced prefs, see doc of
120*6777b538SAndroid Build Coastguard Worker // DemographicMetricsProvider in demographic_metrics_provider.h for more
121*6777b538SAndroid Build Coastguard Worker // details.
GetUserBirthYear(const base::Value::Dict & demographics)122*6777b538SAndroid Build Coastguard Worker std::optional<int> GetUserBirthYear(const base::Value::Dict& demographics) {
123*6777b538SAndroid Build Coastguard Worker return demographics.FindInt(kSyncDemographicsBirthYearPath);
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker // Gets the synced user's gender from synced prefs, see doc of
127*6777b538SAndroid Build Coastguard Worker // DemographicMetricsProvider in demographic_metrics_provider.h for more
128*6777b538SAndroid Build Coastguard Worker // details.
GetUserGender(const base::Value::Dict & demographics)129*6777b538SAndroid Build Coastguard Worker std::optional<UserDemographicsProto_Gender> GetUserGender(
130*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& demographics) {
131*6777b538SAndroid Build Coastguard Worker const std::optional<int> gender_int =
132*6777b538SAndroid Build Coastguard Worker demographics.FindInt(kSyncDemographicsGenderPath);
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard Worker // Verify that the gender is unset.
135*6777b538SAndroid Build Coastguard Worker if (!gender_int)
136*6777b538SAndroid Build Coastguard Worker return std::nullopt;
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker // Verify that the gender number is a valid UserDemographicsProto_Gender
139*6777b538SAndroid Build Coastguard Worker // encoding.
140*6777b538SAndroid Build Coastguard Worker if (!UserDemographicsProto_Gender_IsValid(*gender_int))
141*6777b538SAndroid Build Coastguard Worker return std::nullopt;
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker const auto gender = UserDemographicsProto_Gender(*gender_int);
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker // Verify that the gender is in a large enough population set to preserve
146*6777b538SAndroid Build Coastguard Worker // anonymity.
147*6777b538SAndroid Build Coastguard Worker if (gender != UserDemographicsProto::GENDER_FEMALE &&
148*6777b538SAndroid Build Coastguard Worker gender != UserDemographicsProto::GENDER_MALE) {
149*6777b538SAndroid Build Coastguard Worker return std::nullopt;
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker
152*6777b538SAndroid Build Coastguard Worker return gender;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker } // namespace
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker // static
ForValue(UserDemographics value)158*6777b538SAndroid Build Coastguard Worker UserDemographicsResult UserDemographicsResult::ForValue(
159*6777b538SAndroid Build Coastguard Worker UserDemographics value) {
160*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult(std::move(value),
161*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus::kSuccess);
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker // static
ForStatus(UserDemographicsStatus status)165*6777b538SAndroid Build Coastguard Worker UserDemographicsResult UserDemographicsResult::ForStatus(
166*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus status) {
167*6777b538SAndroid Build Coastguard Worker DCHECK(status != UserDemographicsStatus::kSuccess);
168*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult(UserDemographics(), status);
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker
IsSuccess() const171*6777b538SAndroid Build Coastguard Worker bool UserDemographicsResult::IsSuccess() const {
172*6777b538SAndroid Build Coastguard Worker return status_ == UserDemographicsStatus::kSuccess;
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
status() const175*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus UserDemographicsResult::status() const {
176*6777b538SAndroid Build Coastguard Worker return status_;
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker
value() const179*6777b538SAndroid Build Coastguard Worker const UserDemographics& UserDemographicsResult::value() const {
180*6777b538SAndroid Build Coastguard Worker return value_;
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker
UserDemographicsResult(UserDemographics value,UserDemographicsStatus status)183*6777b538SAndroid Build Coastguard Worker UserDemographicsResult::UserDemographicsResult(UserDemographics value,
184*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus status)
185*6777b538SAndroid Build Coastguard Worker : value_(std::move(value)), status_(status) {}
186*6777b538SAndroid Build Coastguard Worker
RegisterDemographicsLocalStatePrefs(PrefRegistrySimple * registry)187*6777b538SAndroid Build Coastguard Worker void RegisterDemographicsLocalStatePrefs(PrefRegistrySimple* registry) {
188*6777b538SAndroid Build Coastguard Worker registry->RegisterIntegerPref(
189*6777b538SAndroid Build Coastguard Worker kUserDemographicsBirthYearOffsetPrefName,
190*6777b538SAndroid Build Coastguard Worker kUserDemographicsBirthYearNoiseOffsetDefaultValue,
191*6777b538SAndroid Build Coastguard Worker kUserDemographicsBirthYearOffsetPrefFlags);
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker
RegisterDemographicsProfilePrefs(PrefRegistrySimple * registry)194*6777b538SAndroid Build Coastguard Worker void RegisterDemographicsProfilePrefs(PrefRegistrySimple* registry) {
195*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
196*6777b538SAndroid Build Coastguard Worker registry->RegisterDictionaryPref(kSyncOsDemographicsPrefName,
197*6777b538SAndroid Build Coastguard Worker kSyncOsDemographicsPrefFlags);
198*6777b538SAndroid Build Coastguard Worker #endif
199*6777b538SAndroid Build Coastguard Worker registry->RegisterDictionaryPref(kSyncDemographicsPrefName,
200*6777b538SAndroid Build Coastguard Worker kSyncDemographicsPrefFlags);
201*6777b538SAndroid Build Coastguard Worker registry->RegisterIntegerPref(
202*6777b538SAndroid Build Coastguard Worker kDeprecatedDemographicsBirthYearOffsetPrefName,
203*6777b538SAndroid Build Coastguard Worker kUserDemographicsBirthYearNoiseOffsetDefaultValue,
204*6777b538SAndroid Build Coastguard Worker kDeprecatedDemographicsBirthYearOffsetPrefFlags);
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker
ClearDemographicsPrefs(PrefService * profile_prefs)207*6777b538SAndroid Build Coastguard Worker void ClearDemographicsPrefs(PrefService* profile_prefs) {
208*6777b538SAndroid Build Coastguard Worker // Clear the dict holding the user's birth year and gender.
209*6777b538SAndroid Build Coastguard Worker //
210*6777b538SAndroid Build Coastguard Worker // Note: We never clear kUserDemographicsBirthYearOffset from local state.
211*6777b538SAndroid Build Coastguard Worker // The device should continue to use the *same* noise value as long as the
212*6777b538SAndroid Build Coastguard Worker // device's UMA client id remains the same. If the noise value were allowed
213*6777b538SAndroid Build Coastguard Worker // to change for a given user + client id, then the min/max noisy birth year
214*6777b538SAndroid Build Coastguard Worker // values could both be reported, revealing the true value in the middle.
215*6777b538SAndroid Build Coastguard Worker profile_prefs->ClearPref(kSyncDemographicsPrefName);
216*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
217*6777b538SAndroid Build Coastguard Worker profile_prefs->ClearPref(kSyncOsDemographicsPrefName);
218*6777b538SAndroid Build Coastguard Worker #endif
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker
GetUserNoisedBirthYearAndGenderFromPrefs(base::Time now,PrefService * local_state,PrefService * profile_prefs)221*6777b538SAndroid Build Coastguard Worker UserDemographicsResult GetUserNoisedBirthYearAndGenderFromPrefs(
222*6777b538SAndroid Build Coastguard Worker base::Time now,
223*6777b538SAndroid Build Coastguard Worker PrefService* local_state,
224*6777b538SAndroid Build Coastguard Worker PrefService* profile_prefs) {
225*6777b538SAndroid Build Coastguard Worker // Verify that the now time is available. There are situations where the now
226*6777b538SAndroid Build Coastguard Worker // time cannot be provided.
227*6777b538SAndroid Build Coastguard Worker if (now.is_null()) {
228*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult::ForStatus(
229*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus::kCannotGetTime);
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker
232*6777b538SAndroid Build Coastguard Worker // Get the synced user’s noised birth year and gender from synced profile
233*6777b538SAndroid Build Coastguard Worker // prefs. Only one error status code should be used to represent the case
234*6777b538SAndroid Build Coastguard Worker // where demographics are ineligible, see doc of UserDemographicsStatus in
235*6777b538SAndroid Build Coastguard Worker // user_demographics.h for more details.
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker // Get the pref that contains the user's birth year and gender.
238*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& demographics = GetDemographicsDict(profile_prefs);
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker // Get the user's birth year.
241*6777b538SAndroid Build Coastguard Worker std::optional<int> birth_year = GetUserBirthYear(demographics);
242*6777b538SAndroid Build Coastguard Worker if (!birth_year.has_value()) {
243*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult::ForStatus(
244*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus::kIneligibleDemographicsData);
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker // Get the user's gender.
248*6777b538SAndroid Build Coastguard Worker std::optional<UserDemographicsProto_Gender> gender =
249*6777b538SAndroid Build Coastguard Worker GetUserGender(demographics);
250*6777b538SAndroid Build Coastguard Worker if (!gender.has_value()) {
251*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult::ForStatus(
252*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus::kIneligibleDemographicsData);
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker // Get the offset from local_state/profile_prefs and do one last check that
256*6777b538SAndroid Build Coastguard Worker // the birth year is eligible.
257*6777b538SAndroid Build Coastguard Worker // TODO(crbug/1367338): remove profile_prefs after 2023/09
258*6777b538SAndroid Build Coastguard Worker MigrateBirthYearOffset(local_state, profile_prefs);
259*6777b538SAndroid Build Coastguard Worker int offset = GetBirthYearOffset(local_state);
260*6777b538SAndroid Build Coastguard Worker if (!HasEligibleBirthYear(now, *birth_year, offset)) {
261*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult::ForStatus(
262*6777b538SAndroid Build Coastguard Worker UserDemographicsStatus::kIneligibleDemographicsData);
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker // Set gender and noised birth year in demographics.
266*6777b538SAndroid Build Coastguard Worker UserDemographics user_demographics;
267*6777b538SAndroid Build Coastguard Worker user_demographics.gender = *gender;
268*6777b538SAndroid Build Coastguard Worker user_demographics.birth_year = *birth_year + offset;
269*6777b538SAndroid Build Coastguard Worker
270*6777b538SAndroid Build Coastguard Worker return UserDemographicsResult::ForValue(std::move(user_demographics));
271*6777b538SAndroid Build Coastguard Worker }
272*6777b538SAndroid Build Coastguard Worker
273*6777b538SAndroid Build Coastguard Worker } // namespace metrics
274