blob: 24cba6c448ab9c38663098edde6bd7452bd19c35 [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/bind.h"
#include "base/files/file_path.h"
#include "base/guid.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/common/chrome_features.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/live_caption/pref_names.h"
#include "components/media_router/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/variations/variations.mojom.h"
#include "components/variations/variations_client.h"
#include "components/variations/variations_ids_provider.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/shared_cors_origin_access_list.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 BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_switches.h"
#include "base/command_line.h"
#endif
#if defined(OS_ANDROID)
#include "base/android/jni_string.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/android/jni_headers/OTRProfileID_jni.h"
#endif
#if !defined(OS_ANDROID)
#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 BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/lacros/lacros_chrome_service_impl.h"
#endif
#if DCHECK_IS_ON()
#include <set>
#include "base/check_op.h"
#include "base/lazy_instance.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()
namespace {
const char kDevToolsOTRProfileIDPrefix[] = "Devtools::BrowserContext";
const char kMediaRouterOTRProfileIDPrefix[] = "MediaRouter::Presentation";
const char kTestOTRProfileIDPrefix[] = "Test::OTR";
} // namespace
Profile::OTRProfileID::OTRProfileID(const std::string& profile_id)
: profile_id_(profile_id) {}
bool Profile::OTRProfileID::AllowsBrowserWindows() const {
// Non-Primary OTR profiles are not supposed to create Browser windows.
// DevTools::BrowserContext and MediaRouter::Presentation are an
// exception to this ban.
return *this == PrimaryID() ||
base::StartsWith(profile_id_, kDevToolsOTRProfileIDPrefix,
base::CompareCase::SENSITIVE) ||
base::StartsWith(profile_id_, kMediaRouterOTRProfileIDPrefix,
base::CompareCase::SENSITIVE);
}
// static
const Profile::OTRProfileID Profile::OTRProfileID::PrimaryID() {
// OTRProfileID value should be same as
// |OTRProfileID.java#sPrimaryOTRProfileID| variable.
return OTRProfileID("profile::primary_otr");
}
// static
Profile::OTRProfileID Profile::OTRProfileID::CreateUnique(
const std::string& profile_id_prefix) {
return OTRProfileID(base::StringPrintf(
"%s-%s", profile_id_prefix.c_str(),
base::GUID::GenerateRandomV4().AsLowercaseString().c_str()));
}
// static
Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForDevTools() {
return CreateUnique(kDevToolsOTRProfileIDPrefix);
}
// static
Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForMediaRouter() {
return CreateUnique(kMediaRouterOTRProfileIDPrefix);
}
// static
Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForTesting() {
return CreateUnique(kTestOTRProfileIDPrefix);
}
const std::string& Profile::OTRProfileID::ToString() const {
return profile_id_;
}
std::ostream& operator<<(std::ostream& out,
const Profile::OTRProfileID& profile_id) {
out << profile_id.ToString();
return out;
}
#if defined(OS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
Profile::OTRProfileID::ConvertToJavaOTRProfileID(JNIEnv* env) const {
return Java_OTRProfileID_Constructor(
env, base::android::ConvertUTF8ToJavaString(env, profile_id_));
}
// static
Profile::OTRProfileID Profile::OTRProfileID::ConvertFromJavaOTRProfileID(
JNIEnv* env,
const base::android::JavaRef<jobject>& j_otr_profile_id) {
return OTRProfileID(base::android::ConvertJavaStringToUTF8(
env, Java_OTRProfileID_getProfileID(env, j_otr_profile_id)));
}
// static
base::android::ScopedJavaLocalRef<jobject>
JNI_OTRProfileID_CreateUniqueOTRProfileID(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_profile_id_prefix) {
Profile::OTRProfileID profile_id = Profile::OTRProfileID::CreateUnique(
base::android::ConvertJavaStringToUTF8(env, j_profile_id_prefix));
return profile_id.ConvertToJavaOTRProfileID(env);
}
// static
base::android::ScopedJavaLocalRef<jobject> JNI_OTRProfileID_GetPrimaryID(
JNIEnv* env) {
return Profile::OTRProfileID::PrimaryID().ConvertToJavaOTRProfileID(env);
}
// static
Profile::OTRProfileID Profile::OTRProfileID::Deserialize(
const std::string& value) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_value =
base::android::ConvertUTF8ToJavaString(env, value);
base::android::ScopedJavaLocalRef<jobject> j_otr_profile_id =
Java_OTRProfileID_deserializeWithoutVerify(env, j_value);
return ConvertFromJavaOTRProfileID(env, j_otr_profile_id);
}
std::string Profile::OTRProfileID::Serialize() const {
JNIEnv* env = base::android::AttachCurrentThread();
return base::android::ConvertJavaStringToUTF8(
env, Java_OTRProfileID_serialize(env, ConvertToJavaOTRProfileID(env)));
}
#endif // defined(OS_ANDROID)
Profile::Profile()
: resource_context_(std::make_unique<content::ResourceContext>()) {
#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 (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO)) {
content::GetIOThreadTaskRunner({})->DeleteSoon(
FROM_HERE, std::move(resource_context_));
}
#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);
}
base::FilePath Profile::GetBaseName() const {
return GetPath().BaseName();
}
std::string Profile::GetDebugName() const {
std::string name = GetBaseName().MaybeAsASCII();
return name.empty() ? "UnknownProfile" : name;
}
TestingProfile* Profile::AsTestingProfile() {
return nullptr;
}
#if !defined(OS_ANDROID)
ChromeZoomLevelPrefs* Profile::GetZoomLevelPrefs() {
return nullptr;
}
#endif // !defined(OS_ANDROID)
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->RegisterStringPref(prefs::kSessionExitType, std::string());
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::kPreinstalledApps, "install");
registry->RegisterBooleanPref(prefs::kSpeechRecognitionFilterProfanities,
true);
registry->RegisterIntegerPref(prefs::kProfileIconVersion, 0);
registry->RegisterBooleanPref(prefs::kAllowDinosaurEasterEgg, true);
#if BUILDFLAG(IS_CHROMEOS_ASH)
// 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_OS_PRIORITY_PREF);
registry->RegisterStringPref(prefs::kApplicationLocaleBackup, std::string());
registry->RegisterStringPref(prefs::kApplicationLocaleAccepted,
std::string());
#endif
data_reduction_proxy::RegisterSyncableProfilePrefs(registry);
#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
// 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
#if !defined(OS_ANDROID)
registry->RegisterBooleanPref(
media_router::prefs::kMediaRouterCloudServicesPrefSet, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
media_router::prefs::kMediaRouterEnableCloudServices, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterBooleanPref(
media_router::prefs::kMediaRouterMediaRemotingEnabled, true);
registry->RegisterListPref(
media_router::prefs::kMediaRouterTabMirroringSources);
#endif
registry->RegisterDictionaryPref(prefs::kWebShareVisitedTargets);
registry->RegisterDictionaryPref(
prefs::kProtocolHandlerPerOriginAllowedProtocols);
registry->RegisterListPref(prefs::kAutoLaunchProtocolsFromOrigins);
// Instead of registering new prefs here, please create a static method and
// invoke it from RegisterProfilePrefs() in
// chrome/browser/prefs/browser_prefs.cc.
}
bool Profile::IsRegularProfile() const {
return profile_metrics::GetBrowserProfileType(this) ==
profile_metrics::BrowserProfileType::kRegular;
}
bool Profile::IsIncognitoProfile() const {
return profile_metrics::GetBrowserProfileType(this) ==
profile_metrics::BrowserProfileType::kIncognito;
}
// static
bool Profile::IsEphemeralGuestProfileEnabled() {
return false;
}
bool Profile::IsGuestSession() const {
#if BUILDFLAG(IS_CHROMEOS_ASH)
static bool is_guest_session =
base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kGuestSession);
return is_guest_session;
#else
#if BUILDFLAG(IS_CHROMEOS_LACROS)
DCHECK(chromeos::LacrosChromeServiceImpl::Get());
if (chromeos::LacrosChromeServiceImpl::Get()->init_params()->session_type ==
crosapi::mojom::SessionType::kGuestSession) {
return true;
}
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
return profile_metrics::GetBrowserProfileType(this) ==
profile_metrics::BrowserProfileType::kGuest;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
PrefService* Profile::GetReadOnlyOffTheRecordPrefs() {
return nullptr;
}
bool Profile::IsEphemeralGuestProfile() const {
return false;
}
bool Profile::IsSystemProfile() const {
return profile_metrics::GetBrowserProfileType(this) ==
profile_metrics::BrowserProfileType::kSystem;
}
bool Profile::IsPrimaryOTRProfile() const {
return IsOffTheRecord() && GetOTRProfileID() == OTRProfileID::PrimaryID();
}
bool Profile::CanUseDiskWhenOffTheRecord() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Guest mode on ChromeOS uses an in-memory file system to store the profile
// in, so despite this being an off the record profile, it is still okay to
// store data on disk.
return IsGuestSession();
#else
return false;
#endif
}
bool Profile::ShouldRestoreOldSessionCookies() const {
return false;
}
bool Profile::ShouldPersistSessionCookies() const {
return false;
}
void Profile::MaybeSendDestroyedNotification() {
TRACE_EVENT1("shutdown", "Profile::MaybeSendDestroyedNotification", "profile",
this);
if (!sent_destroyed_notification_) {
sent_destroyed_notification_ = true;
NotifyWillBeDestroyed();
for (auto& observer : observers_)
observer.OnProfileWillBeDestroyed(this);
}
}
// 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->IsSameOrParent(b))
return false;
return a->GetOriginalProfile() < b->GetOriginalProfile();
}
#if !defined(OS_ANDROID)
double Profile::GetDefaultZoomLevelForProfile() {
return GetDefaultStoragePartition()->GetHostZoomMap()->GetDefaultZoomLevel();
}
#endif // !defined(OS_ANDROID)
void Profile::Wipe() {
GetBrowsingDataRemover()->Remove(
base::Time(), base::Time::Max(),
chrome_browsing_data_remover::WIPE_PROFILE,
chrome_browsing_data_remover::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);
}
Profile* Profile::GetPrimaryOTRProfile(bool create_if_needed) {
return GetOffTheRecordProfile(OTRProfileID::PrimaryID(), create_if_needed);
}
bool Profile::HasPrimaryOTRProfile() {
return HasOffTheRecordProfile(OTRProfileID::PrimaryID());
}
class Profile::ChromeVariationsClient : public variations::VariationsClient {
public:
explicit ChromeVariationsClient(Profile* profile) : profile_(profile) {}
~ChromeVariationsClient() override = default;
bool IsOffTheRecord() const override { return profile_->IsOffTheRecord(); }
variations::mojom::VariationsHeadersPtr GetVariationsHeaders()
const override {
return variations::VariationsIdsProvider::GetInstance()
->GetClientDataHeaders(profile_->IsSignedIn());
}
private:
Profile* profile_;
};
variations::VariationsClient* Profile::GetVariationsClient() {
if (!chrome_variations_client_)
chrome_variations_client_ = std::make_unique<ChromeVariationsClient>(this);
return chrome_variations_client_.get();
}
content::ResourceContext* Profile::GetResourceContext() {
return resource_context_.get();
}