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