blob: 9e0d25bc3367fa5ed2a91be4b5890df122993efe [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/profiles/profile.h"
#include <string>
#include "base/path_service.h"
#include "build/build_config.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/net/profile_network_context_service_factory.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/pref_names.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/language/core/browser/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/sync_service.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "extensions/buildflags/buildflags.h"
#if defined(OS_CHROMEOS)
#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
#include "chromeos/constants/chromeos_switches.h"
#endif
#if !defined(OS_ANDROID)
#include "chrome/browser/first_run/first_run.h"
#include "content/public/browser/host_zoom_map.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/browser/extension_pref_store.h"
#include "extensions/browser/extension_pref_value_map_factory.h"
#include "extensions/browser/pref_names.h"
#endif
#if DCHECK_IS_ON()
#include <set>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"
namespace {
base::LazyInstance<base::Lock>::Leaky g_profile_instances_lock =
LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<std::set<content::BrowserContext*>>::Leaky
g_profile_instances = LAZY_INSTANCE_INITIALIZER;
} // namespace
#endif // DCHECK_IS_ON()
Profile::Profile()
: restored_last_session_(false),
sent_destroyed_notification_(false),
accessibility_pause_level_(0),
is_guest_profile_(false),
is_system_profile_(false) {
#if DCHECK_IS_ON()
base::AutoLock lock(g_profile_instances_lock.Get());
g_profile_instances.Get().insert(this);
#endif // DCHECK_IS_ON()
BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this);
}
Profile::~Profile() {
#if DCHECK_IS_ON()
base::AutoLock lock(g_profile_instances_lock.Get());
g_profile_instances.Get().erase(this);
#endif // DCHECK_IS_ON()
}
// static
Profile* Profile::FromBrowserContext(content::BrowserContext* browser_context) {
if (!browser_context)
return nullptr;
// For code running in a chrome/ environment, it is safe to cast to Profile*
// because Profile is the only implementation of BrowserContext used. In
// testing, however, there are several BrowserContext subclasses that are not
// Profile subclasses, and we can catch them. http://crbug.com/725276
#if DCHECK_IS_ON()
base::AutoLock lock(g_profile_instances_lock.Get());
if (!g_profile_instances.Get().count(browser_context)) {
DCHECK(false)
<< "Non-Profile BrowserContext passed to Profile::FromBrowserContext! "
"If you have a test linked in chrome/ you need a chrome/ based test "
"class such as TestingProfile in chrome/test/base/testing_profile.h "
"or you need to subclass your test class from Profile, not from "
"BrowserContext.";
}
#endif // DCHECK_IS_ON()
return static_cast<Profile*>(browser_context);
}
// static
Profile* Profile::FromWebUI(content::WebUI* web_ui) {
return FromBrowserContext(web_ui->GetWebContents()->GetBrowserContext());
}
void Profile::AddObserver(ProfileObserver* observer) {
observers_.AddObserver(observer);
}
void Profile::RemoveObserver(ProfileObserver* observer) {
observers_.RemoveObserver(observer);
}
TestingProfile* Profile::AsTestingProfile() {
return nullptr;
}
#if !defined(OS_ANDROID)
ChromeZoomLevelPrefs* Profile::GetZoomLevelPrefs() {
return nullptr;
}
#endif // !defined(OS_ANDROID)
PrefService* Profile::GetReadOnlyOffTheRecordPrefs() {
return GetOffTheRecordPrefs();
}
Profile::Delegate::~Delegate() {
}
// static
const char Profile::kProfileKey[] = "__PROFILE__";
// static
void Profile::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(
prefs::kSearchSuggestEnabled,
true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
#if defined(OS_ANDROID)
registry->RegisterStringPref(
prefs::kContextualSearchEnabled,
std::string(),
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
#endif // defined(OS_ANDROID)
registry->RegisterBooleanPref(prefs::kSessionExitedCleanly, true);
registry->RegisterStringPref(prefs::kSessionExitType, std::string());
registry->RegisterInt64Pref(prefs::kSiteEngagementLastUpdateTime, 0,
PrefRegistry::LOSSY_PREF);
registry->RegisterBooleanPref(prefs::kSSLErrorOverrideAllowed, true);
registry->RegisterBooleanPref(prefs::kDisableExtensions, false);
#if BUILDFLAG(ENABLE_EXTENSIONS)
registry->RegisterBooleanPref(extensions::pref_names::kAlertsInitialized,
false);
#endif
base::FilePath home;
base::PathService::Get(base::DIR_HOME, &home);
registry->RegisterStringPref(prefs::kSelectFileLastDirectory,
home.MaybeAsASCII());
registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextSize,
std::string());
registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextFont,
std::string());
registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextColor,
std::string());
registry->RegisterIntegerPref(prefs::kAccessibilityCaptionsTextOpacity, 100);
registry->RegisterIntegerPref(prefs::kAccessibilityCaptionsBackgroundOpacity,
100);
registry->RegisterStringPref(prefs::kAccessibilityCaptionsBackgroundColor,
std::string());
registry->RegisterStringPref(prefs::kAccessibilityCaptionsTextShadow,
std::string());
#if !defined(OS_ANDROID)
registry->RegisterDictionaryPref(prefs::kPartitionDefaultZoomLevel);
registry->RegisterDictionaryPref(prefs::kPartitionPerHostZoomLevels);
#endif // !defined(OS_ANDROID)
registry->RegisterStringPref(prefs::kDefaultApps, "install");
registry->RegisterBooleanPref(prefs::kSpeechRecognitionFilterProfanities,
true);
registry->RegisterIntegerPref(prefs::kProfileIconVersion, 0);
registry->RegisterBooleanPref(prefs::kAllowDinosaurEasterEgg, true);
#if defined(OS_CHROMEOS)
// TODO(dilmah): For OS_CHROMEOS we maintain kApplicationLocale in both
// local state and user's profile. For other platforms we maintain
// kApplicationLocale only in local state.
// In the future we may want to maintain kApplicationLocale
// in user's profile for other platforms as well.
registry->RegisterStringPref(
language::prefs::kApplicationLocale, std::string(),
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
registry->RegisterStringPref(prefs::kApplicationLocaleBackup, std::string());
registry->RegisterStringPref(prefs::kApplicationLocaleAccepted,
std::string());
#endif
data_reduction_proxy::RegisterSyncableProfilePrefs(registry);
#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
// Preferences related to the avatar bubble and user manager tutorials.
registry->RegisterIntegerPref(prefs::kProfileAvatarTutorialShown, 0);
#endif
#if defined(OS_ANDROID)
registry->RegisterBooleanPref(prefs::kClickedUpdateMenuItem, false);
registry->RegisterStringPref(prefs::kLatestVersionWhenClickedUpdateMenuItem,
std::string());
#endif
registry->RegisterBooleanPref(
prefs::kMediaRouterCloudServicesPrefSet,
false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kMediaRouterEnableCloudServices,
false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
prefs::kMediaRouterFirstRunFlowAcknowledged,
false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(prefs::kMediaRouterMediaRemotingEnabled, true);
registry->RegisterListPref(prefs::kMediaRouterTabMirroringSources);
registry->RegisterDictionaryPref(prefs::kWebShareVisitedTargets);
registry->RegisterDictionaryPref(prefs::kExcludedSchemes);
// Instead of registering new prefs here, please create a static method and
// invoke it from RegisterProfilePrefs() in
// chrome/browser/prefs/browser_prefs.cc.
}
std::string Profile::GetDebugName() {
std::string name = GetPath().BaseName().MaybeAsASCII();
if (name.empty()) {
name = "UnknownProfile";
}
return name;
}
bool Profile::IsRegularProfile() const {
return GetProfileType() == REGULAR_PROFILE;
}
bool Profile::IsIncognitoProfile() const {
return GetProfileType() == INCOGNITO_PROFILE;
}
bool Profile::IsGuestSession() const {
#if defined(OS_CHROMEOS)
static bool is_guest_session =
base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kGuestSession);
return is_guest_session;
#else
return is_guest_profile_;
#endif
}
bool Profile::IsSystemProfile() const {
return is_system_profile_;
}
bool Profile::ShouldRestoreOldSessionCookies() {
return false;
}
bool Profile::ShouldPersistSessionCookies() {
return false;
}
mojo::Remote<network::mojom::NetworkContext> Profile::CreateNetworkContext(
bool in_memory,
const base::FilePath& relative_partition_path) {
return ProfileNetworkContextServiceFactory::GetForContext(this)
->CreateNetworkContext(in_memory, relative_partition_path);
}
identity::mojom::IdentityService* Profile::GetIdentityService() {
return nullptr;
}
bool Profile::IsNewProfile() {
#if !defined(OS_ANDROID)
// The profile is new if the preference files has just been created, except on
// first run, because the installer may create a preference file. See
// https://crbug.com/728402
if (first_run::IsChromeFirstRun())
return true;
#endif
return GetOriginalProfile()->GetPrefs()->GetInitializationStatus() ==
PrefService::INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
}
bool Profile::IsSyncAllowed() {
if (ProfileSyncServiceFactory::HasSyncService(this)) {
syncer::SyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(this);
return !sync_service->HasDisableReason(
syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE) &&
!sync_service->HasDisableReason(
syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY);
}
// No ProfileSyncService created yet - we don't want to create one, so just
// infer the accessible state by looking at prefs/command line flags.
syncer::SyncPrefs prefs(GetPrefs());
return switches::IsSyncAllowedByFlag() && !prefs.IsManaged();
}
void Profile::MaybeSendDestroyedNotification() {
if (!sent_destroyed_notification_) {
sent_destroyed_notification_ = true;
NotifyWillBeDestroyed(this);
for (auto& observer : observers_)
observer.OnProfileWillBeDestroyed(this);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(this),
content::NotificationService::NoDetails());
}
}
// static
PrefStore* Profile::CreateExtensionPrefStore(Profile* profile,
bool incognito_pref_store) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
return new ExtensionPrefStore(
ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
incognito_pref_store);
#else
return nullptr;
#endif
}
bool ProfileCompare::operator()(Profile* a, Profile* b) const {
DCHECK(a && b);
if (a->IsSameProfile(b))
return false;
return a->GetOriginalProfile() < b->GetOriginalProfile();
}
#if !defined(OS_ANDROID)
double Profile::GetDefaultZoomLevelForProfile() {
return GetDefaultStoragePartition(this)
->GetHostZoomMap()
->GetDefaultZoomLevel();
}
#endif // !defined(OS_ANDROID)
void Profile::Wipe() {
content::BrowserContext::GetBrowsingDataRemover(this)->Remove(
base::Time(), base::Time::Max(),
ChromeBrowsingDataRemoverDelegate::WIPE_PROFILE,
ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES);
}
void Profile::NotifyOffTheRecordProfileCreated(Profile* off_the_record) {
DCHECK_EQ(off_the_record->GetOriginalProfile(), this);
DCHECK(off_the_record->IsOffTheRecord());
for (auto& observer : observers_)
observer.OnOffTheRecordProfileCreated(off_the_record);
}