1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 "chrome/browser/profiles/profile.h"
6
7 #include <string>
8
9 #include "base/path_service.h"
10 #include "base/strings/string_util.h"
11 #include "build/build_config.h"
12 #include "build/chromeos_buildflags.h"
13 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/net/profile_network_context_service.h"
16 #include "chrome/browser/net/profile_network_context_service_factory.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/profiles/profile_observer.h"
19 #include "chrome/browser/signin/identity_manager_factory.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chrome/common/buildflags.h"
22 #include "chrome/common/chrome_features.h"
23 #include "chrome/common/pref_names.h"
24 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
25 #include "components/keyed_service/content/browser_context_dependency_manager.h"
26 #include "components/language/core/browser/pref_names.h"
27 #include "components/media_router/common/pref_names.h"
28 #include "components/pref_registry/pref_registry_syncable.h"
29 #include "components/prefs/pref_service.h"
30 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
31 #include "components/signin/public/identity_manager/identity_manager.h"
32 #include "components/sync/base/sync_prefs.h"
33 #include "components/sync/driver/sync_driver_switches.h"
34 #include "components/sync/driver/sync_service.h"
35 #include "components/variations/proto/study.pb.h"
36 #include "components/variations/variations.mojom.h"
37 #include "components/variations/variations_client.h"
38 #include "components/variations/variations_ids_provider.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/browser/storage_partition.h"
42 #include "content/public/browser/web_contents.h"
43 #include "content/public/browser/web_ui.h"
44 #include "extensions/buildflags/buildflags.h"
45
46 #if defined(OS_CHROMEOS)
47 #include "base/command_line.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chromeos/constants/chromeos_switches.h"
50 #endif
51
52 #if defined(OS_ANDROID)
53 #include "base/android/jni_string.h"
54 #include "base/strings/utf_string_conversions.h"
55 #include "chrome/browser/profiles/android/jni_headers/OTRProfileID_jni.h"
56 #endif
57
58 #if !defined(OS_ANDROID)
59 #include "chrome/browser/first_run/first_run.h"
60 #include "content/public/browser/host_zoom_map.h"
61 #endif
62
63 #if BUILDFLAG(ENABLE_EXTENSIONS)
64 #include "extensions/browser/extension_pref_store.h"
65 #include "extensions/browser/extension_pref_value_map_factory.h"
66 #include "extensions/browser/pref_names.h"
67 #endif
68
69 #if BUILDFLAG(IS_LACROS)
70 #include "chromeos/lacros/lacros_chrome_service_impl.h"
71 #endif
72
73 #if DCHECK_IS_ON()
74
75 #include <set>
76 #include "base/check_op.h"
77 #include "base/lazy_instance.h"
78 #include "base/synchronization/lock.h"
79
80 namespace {
81
82 base::LazyInstance<base::Lock>::Leaky g_profile_instances_lock =
83 LAZY_INSTANCE_INITIALIZER;
84 base::LazyInstance<std::set<content::BrowserContext*>>::Leaky
85 g_profile_instances = LAZY_INSTANCE_INITIALIZER;
86
87 } // namespace
88
89 #endif // DCHECK_IS_ON()
90
91 namespace {
92
93 class ChromeVariationsClient : public variations::VariationsClient {
94 public:
ChromeVariationsClient(content::BrowserContext * browser_context)95 explicit ChromeVariationsClient(content::BrowserContext* browser_context)
96 : browser_context_(browser_context) {}
97
98 ~ChromeVariationsClient() override = default;
99
IsOffTheRecord() const100 bool IsOffTheRecord() const override {
101 return browser_context_->IsOffTheRecord();
102 }
103
GetVariationsHeaders() const104 variations::mojom::VariationsHeadersPtr GetVariationsHeaders()
105 const override {
106 return variations::VariationsIdsProvider::GetInstance()
107 ->GetClientDataHeaders(IsSignedIn());
108 }
109
110 private:
IsSignedIn() const111 bool IsSignedIn() const {
112 Profile* profile = Profile::FromBrowserContext(browser_context_);
113 signin::IdentityManager* identity_manager =
114 IdentityManagerFactory::GetForProfile(profile);
115 return identity_manager && identity_manager->HasPrimaryAccount();
116 }
117
118 content::BrowserContext* browser_context_;
119 };
120
121 const char kDevToolsOTRProfileIDPrefix[] = "Devtools::BrowserContext";
122 const char kMediaRouterOTRProfileIDPrefix[] = "MediaRouter::Presentation";
123
124 } // namespace
125
OTRProfileID(const std::string & profile_id)126 Profile::OTRProfileID::OTRProfileID(const std::string& profile_id)
127 : profile_id_(profile_id) {}
128
AllowsBrowserWindows() const129 bool Profile::OTRProfileID::AllowsBrowserWindows() const {
130 // Non-Primary OTR profiles are not supposed to create Browser windows.
131 // DevTools::BrowserContext and MediaRouter::Presentation are an
132 // exception to this ban.
133 return *this == PrimaryID() ||
134 base::StartsWith(profile_id_, kDevToolsOTRProfileIDPrefix,
135 base::CompareCase::SENSITIVE) ||
136 base::StartsWith(profile_id_, kMediaRouterOTRProfileIDPrefix,
137 base::CompareCase::SENSITIVE);
138 }
139
140 // static
PrimaryID()141 const Profile::OTRProfileID Profile::OTRProfileID::PrimaryID() {
142 return OTRProfileID("profile::primary_otr");
143 }
144
145 // static
146 int Profile::OTRProfileID::first_unused_index_ = 0;
147
148 // static
CreateUnique(const std::string & profile_id_prefix)149 Profile::OTRProfileID Profile::OTRProfileID::CreateUnique(
150 const std::string& profile_id_prefix) {
151 return OTRProfileID(base::StringPrintf("%s-%i", profile_id_prefix.c_str(),
152 first_unused_index_++));
153 }
154
155 // static
CreateUniqueForDevTools()156 Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForDevTools() {
157 return CreateUnique(kDevToolsOTRProfileIDPrefix);
158 }
159
160 // static
CreateUniqueForMediaRouter()161 Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForMediaRouter() {
162 return CreateUnique(kMediaRouterOTRProfileIDPrefix);
163 }
164
ToString() const165 const std::string& Profile::OTRProfileID::ToString() const {
166 return profile_id_;
167 }
168
operator <<(std::ostream & out,const Profile::OTRProfileID & profile_id)169 std::ostream& operator<<(std::ostream& out,
170 const Profile::OTRProfileID& profile_id) {
171 out << profile_id.ToString();
172 return out;
173 }
174
175 #if defined(OS_ANDROID)
176 base::android::ScopedJavaLocalRef<jobject>
ConvertToJavaOTRProfileID(JNIEnv * env) const177 Profile::OTRProfileID::ConvertToJavaOTRProfileID(JNIEnv* env) const {
178 return Java_OTRProfileID_Constructor(
179 env, base::android::ConvertUTF16ToJavaString(
180 env, base::ASCIIToUTF16(profile_id_)));
181 }
182
183 // static
ConvertFromJavaOTRProfileID(JNIEnv * env,const base::android::JavaRef<jobject> & j_otr_profile_id)184 Profile::OTRProfileID Profile::OTRProfileID::ConvertFromJavaOTRProfileID(
185 JNIEnv* env,
186 const base::android::JavaRef<jobject>& j_otr_profile_id) {
187 return OTRProfileID(
188 base::UTF16ToASCII(base::android::ConvertJavaStringToUTF16(
189 env, Java_OTRProfileID_getProfileID(env, j_otr_profile_id))));
190 }
191
192 // static
193 base::android::ScopedJavaLocalRef<jobject>
JNI_OTRProfileID_CreateUniqueOTRProfileID(JNIEnv * env,const base::android::JavaParamRef<jstring> & j_profile_id_prefix)194 JNI_OTRProfileID_CreateUniqueOTRProfileID(
195 JNIEnv* env,
196 const base::android::JavaParamRef<jstring>& j_profile_id_prefix) {
197 Profile::OTRProfileID profile_id =
198 Profile::OTRProfileID::CreateUnique(base::UTF16ToASCII(
199 base::android::ConvertJavaStringToUTF16(env, j_profile_id_prefix)));
200 return profile_id.ConvertToJavaOTRProfileID(env);
201 }
202 #endif
203
Profile()204 Profile::Profile() {
205 #if DCHECK_IS_ON()
206 base::AutoLock lock(g_profile_instances_lock.Get());
207 g_profile_instances.Get().insert(this);
208 #endif // DCHECK_IS_ON()
209
210 BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this);
211 }
212
~Profile()213 Profile::~Profile() {
214 #if DCHECK_IS_ON()
215 base::AutoLock lock(g_profile_instances_lock.Get());
216 g_profile_instances.Get().erase(this);
217 #endif // DCHECK_IS_ON()
218 }
219
220 // static
FromBrowserContext(content::BrowserContext * browser_context)221 Profile* Profile::FromBrowserContext(content::BrowserContext* browser_context) {
222 if (!browser_context)
223 return nullptr;
224
225 // For code running in a chrome/ environment, it is safe to cast to Profile*
226 // because Profile is the only implementation of BrowserContext used. In
227 // testing, however, there are several BrowserContext subclasses that are not
228 // Profile subclasses, and we can catch them. http://crbug.com/725276
229 #if DCHECK_IS_ON()
230 base::AutoLock lock(g_profile_instances_lock.Get());
231 if (!g_profile_instances.Get().count(browser_context)) {
232 DCHECK(false)
233 << "Non-Profile BrowserContext passed to Profile::FromBrowserContext! "
234 "If you have a test linked in chrome/ you need a chrome/ based test "
235 "class such as TestingProfile in chrome/test/base/testing_profile.h "
236 "or you need to subclass your test class from Profile, not from "
237 "BrowserContext.";
238 }
239 #endif // DCHECK_IS_ON()
240 return static_cast<Profile*>(browser_context);
241 }
242
243 // static
FromWebUI(content::WebUI * web_ui)244 Profile* Profile::FromWebUI(content::WebUI* web_ui) {
245 return FromBrowserContext(web_ui->GetWebContents()->GetBrowserContext());
246 }
247
AddObserver(ProfileObserver * observer)248 void Profile::AddObserver(ProfileObserver* observer) {
249 observers_.AddObserver(observer);
250 }
251
RemoveObserver(ProfileObserver * observer)252 void Profile::RemoveObserver(ProfileObserver* observer) {
253 observers_.RemoveObserver(observer);
254 }
255
AsTestingProfile()256 TestingProfile* Profile::AsTestingProfile() {
257 return nullptr;
258 }
259
260 #if !defined(OS_ANDROID)
GetZoomLevelPrefs()261 ChromeZoomLevelPrefs* Profile::GetZoomLevelPrefs() {
262 return nullptr;
263 }
264 #endif // !defined(OS_ANDROID)
265
GetReadOnlyOffTheRecordPrefs()266 PrefService* Profile::GetReadOnlyOffTheRecordPrefs() {
267 return GetOffTheRecordPrefs();
268 }
269
~Delegate()270 Profile::Delegate::~Delegate() {
271 }
272
273 // static
274 const char Profile::kProfileKey[] = "__PROFILE__";
275
276 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)277 void Profile::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
278 registry->RegisterBooleanPref(
279 prefs::kSearchSuggestEnabled,
280 true,
281 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
282 #if defined(OS_ANDROID)
283 registry->RegisterStringPref(
284 prefs::kContextualSearchEnabled,
285 std::string(),
286 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
287 #endif // defined(OS_ANDROID)
288 registry->RegisterBooleanPref(prefs::kSessionExitedCleanly, true);
289 registry->RegisterStringPref(prefs::kSessionExitType, std::string());
290 registry->RegisterInt64Pref(prefs::kSiteEngagementLastUpdateTime, 0,
291 PrefRegistry::LOSSY_PREF);
292 registry->RegisterBooleanPref(prefs::kSSLErrorOverrideAllowed, true);
293 registry->RegisterBooleanPref(prefs::kDisableExtensions, false);
294 #if BUILDFLAG(ENABLE_EXTENSIONS)
295 registry->RegisterBooleanPref(extensions::pref_names::kAlertsInitialized,
296 false);
297 #endif
298 base::FilePath home;
299 base::PathService::Get(base::DIR_HOME, &home);
300 registry->RegisterStringPref(prefs::kSelectFileLastDirectory,
301 home.MaybeAsASCII());
302 registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextSize,
303 std::string());
304 registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextFont,
305 std::string());
306 registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextColor,
307 std::string());
308 registry->RegisterIntegerPref(prefs::kAccessibilityCaptionsTextOpacity, 100);
309 registry->RegisterIntegerPref(prefs::kAccessibilityCaptionsBackgroundOpacity,
310 100);
311 registry->RegisterStringPref(prefs::kAccessibilityCaptionsBackgroundColor,
312 std::string());
313 registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextShadow,
314 std::string());
315 #if !defined(OS_ANDROID)
316 registry->RegisterDictionaryPref(prefs::kPartitionDefaultZoomLevel);
317 registry->RegisterDictionaryPref(prefs::kPartitionPerHostZoomLevels);
318 #endif // !defined(OS_ANDROID)
319 registry->RegisterStringPref(prefs::kDefaultApps, "install");
320 registry->RegisterBooleanPref(prefs::kSpeechRecognitionFilterProfanities,
321 true);
322 registry->RegisterIntegerPref(prefs::kProfileIconVersion, 0);
323 registry->RegisterBooleanPref(prefs::kAllowDinosaurEasterEgg, true);
324 #if defined(OS_CHROMEOS)
325 // TODO(dilmah): For OS_CHROMEOS we maintain kApplicationLocale in both
326 // local state and user's profile. For other platforms we maintain
327 // kApplicationLocale only in local state.
328 // In the future we may want to maintain kApplicationLocale
329 // in user's profile for other platforms as well.
330 registry->RegisterStringPref(
331 language::prefs::kApplicationLocale, std::string(),
332 user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PRIORITY_PREF);
333 registry->RegisterStringPref(prefs::kApplicationLocaleBackup, std::string());
334 registry->RegisterStringPref(prefs::kApplicationLocaleAccepted,
335 std::string());
336 #endif
337
338 data_reduction_proxy::RegisterSyncableProfilePrefs(registry);
339
340 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
341 // Preferences related to the avatar bubble and user manager tutorials.
342 registry->RegisterIntegerPref(prefs::kProfileAvatarTutorialShown, 0);
343 #endif
344
345 #if defined(OS_ANDROID)
346 registry->RegisterBooleanPref(prefs::kClickedUpdateMenuItem, false);
347 registry->RegisterStringPref(prefs::kLatestVersionWhenClickedUpdateMenuItem,
348 std::string());
349 #endif
350
351 #if !defined(OS_ANDROID)
352 registry->RegisterBooleanPref(
353 media_router::prefs::kMediaRouterCloudServicesPrefSet, false,
354 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
355 registry->RegisterBooleanPref(
356 media_router::prefs::kMediaRouterEnableCloudServices, false,
357 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
358 registry->RegisterBooleanPref(
359 media_router::prefs::kMediaRouterMediaRemotingEnabled, true);
360 registry->RegisterListPref(
361 media_router::prefs::kMediaRouterTabMirroringSources);
362 #endif
363
364 registry->RegisterDictionaryPref(prefs::kWebShareVisitedTargets);
365 registry->RegisterDictionaryPref(
366 prefs::kProtocolHandlerPerOriginAllowedProtocols);
367
368 registry->RegisterListPref(prefs::kAutoLaunchProtocolsFromOrigins);
369
370 // Instead of registering new prefs here, please create a static method and
371 // invoke it from RegisterProfilePrefs() in
372 // chrome/browser/prefs/browser_prefs.cc.
373 }
374
GetDebugName() const375 std::string Profile::GetDebugName() const {
376 std::string name = GetPath().BaseName().MaybeAsASCII();
377 return name.empty() ? "UnknownProfile" : name;
378 }
379
IsRegularProfile() const380 bool Profile::IsRegularProfile() const {
381 return !IsOffTheRecord();
382 }
383
IsIncognitoProfile() const384 bool Profile::IsIncognitoProfile() const {
385 return IsPrimaryOTRProfile() && !IsGuestSession() && !IsSystemProfile();
386 }
387
388 // static
IsEphemeralGuestProfileEnabled()389 bool Profile::IsEphemeralGuestProfileEnabled() {
390 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_BSD) || \
391 defined(OS_MAC)
392 return base::FeatureList::IsEnabled(
393 features::kEnableEphemeralGuestProfilesOnDesktop);
394 #else
395 return false;
396 #endif
397 }
398
IsGuestSession() const399 bool Profile::IsGuestSession() const {
400 #if defined(OS_CHROMEOS)
401 static bool is_guest_session =
402 base::CommandLine::ForCurrentProcess()->HasSwitch(
403 chromeos::switches::kGuestSession);
404 return is_guest_session;
405 #else
406 #if BUILDFLAG(IS_LACROS)
407 DCHECK(chromeos::LacrosChromeServiceImpl::Get());
408 if (chromeos::LacrosChromeServiceImpl::Get()->init_params()->session_type !=
409 crosapi::mojom::SessionType::kUnknown) {
410 return chromeos::LacrosChromeServiceImpl::Get()
411 ->init_params()
412 ->session_type == crosapi::mojom::SessionType::kGuestSession;
413 }
414 #endif // BUILDFLAG(IS_LACROS)
415 return is_guest_profile_ && !IsEphemeralGuestProfileEnabled();
416 #endif // defined(OS_CHROMEOS)
417 }
418
IsEphemeralGuestProfile() const419 bool Profile::IsEphemeralGuestProfile() const {
420 return is_guest_profile_ && IsEphemeralGuestProfileEnabled();
421 }
422
IsSystemProfile() const423 bool Profile::IsSystemProfile() const {
424 return is_system_profile_;
425 }
426
IsPrimaryOTRProfile() const427 bool Profile::IsPrimaryOTRProfile() const {
428 return IsOffTheRecord() && GetOTRProfileID() == OTRProfileID::PrimaryID();
429 }
430
CanUseDiskWhenOffTheRecord()431 bool Profile::CanUseDiskWhenOffTheRecord() {
432 #if defined(OS_CHROMEOS)
433 // Guest mode on ChromeOS uses an in-memory file system to store the profile
434 // in, so despite this being an off the record profile, it is still okay to
435 // store data on disk.
436 return IsGuestSession();
437 #else
438 return false;
439 #endif
440 }
441
ShouldRestoreOldSessionCookies() const442 bool Profile::ShouldRestoreOldSessionCookies() const {
443 return false;
444 }
445
ShouldPersistSessionCookies() const446 bool Profile::ShouldPersistSessionCookies() const {
447 return false;
448 }
449
ConfigureNetworkContextParams(bool in_memory,const base::FilePath & relative_partition_path,network::mojom::NetworkContextParams * network_context_params,network::mojom::CertVerifierCreationParams * cert_verifier_creation_params)450 void Profile::ConfigureNetworkContextParams(
451 bool in_memory,
452 const base::FilePath& relative_partition_path,
453 network::mojom::NetworkContextParams* network_context_params,
454 network::mojom::CertVerifierCreationParams* cert_verifier_creation_params) {
455 ProfileNetworkContextServiceFactory::GetForContext(this)
456 ->ConfigureNetworkContextParams(in_memory, relative_partition_path,
457 network_context_params,
458 cert_verifier_creation_params);
459 }
460
IsNewProfile() const461 bool Profile::IsNewProfile() const {
462 #if !defined(OS_ANDROID)
463 // The profile is new if the preference files has just been created, except on
464 // first run, because the installer may create a preference file. See
465 // https://crbug.com/728402
466 if (first_run::IsChromeFirstRun())
467 return true;
468 #endif
469
470 return GetOriginalProfile()->GetPrefs()->GetInitializationStatus() ==
471 PrefService::INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
472 }
473
MaybeSendDestroyedNotification()474 void Profile::MaybeSendDestroyedNotification() {
475 TRACE_EVENT1("shutdown", "Profile::MaybeSendDestroyedNotification", "profile",
476 this);
477
478 if (!sent_destroyed_notification_) {
479 sent_destroyed_notification_ = true;
480
481 NotifyWillBeDestroyed(this);
482
483 for (auto& observer : observers_)
484 observer.OnProfileWillBeDestroyed(this);
485
486 content::NotificationService::current()->Notify(
487 chrome::NOTIFICATION_PROFILE_DESTROYED,
488 content::Source<Profile>(this),
489 content::NotificationService::NoDetails());
490 }
491 }
492
493 // static
CreateExtensionPrefStore(Profile * profile,bool incognito_pref_store)494 PrefStore* Profile::CreateExtensionPrefStore(Profile* profile,
495 bool incognito_pref_store) {
496 #if BUILDFLAG(ENABLE_EXTENSIONS)
497 return new ExtensionPrefStore(
498 ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
499 incognito_pref_store);
500 #else
501 return nullptr;
502 #endif
503 }
504
operator ()(Profile * a,Profile * b) const505 bool ProfileCompare::operator()(Profile* a, Profile* b) const {
506 DCHECK(a && b);
507 if (a->IsSameOrParent(b))
508 return false;
509 return a->GetOriginalProfile() < b->GetOriginalProfile();
510 }
511
512 #if !defined(OS_ANDROID)
GetDefaultZoomLevelForProfile()513 double Profile::GetDefaultZoomLevelForProfile() {
514 return GetDefaultStoragePartition(this)
515 ->GetHostZoomMap()
516 ->GetDefaultZoomLevel();
517 }
518 #endif // !defined(OS_ANDROID)
519
Wipe()520 void Profile::Wipe() {
521 content::BrowserContext::GetBrowsingDataRemover(this)->Remove(
522 base::Time(), base::Time::Max(),
523 ChromeBrowsingDataRemoverDelegate::WIPE_PROFILE,
524 ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES);
525 }
526
NotifyOffTheRecordProfileCreated(Profile * off_the_record)527 void Profile::NotifyOffTheRecordProfileCreated(Profile* off_the_record) {
528 DCHECK_EQ(off_the_record->GetOriginalProfile(), this);
529 DCHECK(off_the_record->IsOffTheRecord());
530 for (auto& observer : observers_)
531 observer.OnOffTheRecordProfileCreated(off_the_record);
532 }
533
GetPrimaryOTRProfile()534 Profile* Profile::GetPrimaryOTRProfile() {
535 return GetOffTheRecordProfile(OTRProfileID::PrimaryID());
536 }
537
HasPrimaryOTRProfile()538 bool Profile::HasPrimaryOTRProfile() {
539 return HasOffTheRecordProfile(OTRProfileID::PrimaryID());
540 }
541
GetVariationsClient()542 variations::VariationsClient* Profile::GetVariationsClient() {
543 if (!chrome_variations_client_)
544 chrome_variations_client_ = std::make_unique<ChromeVariationsClient>(this);
545 return chrome_variations_client_.get();
546 }
547