// Copyright 2019 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 "weblayer/browser/profile_impl.h" #include #include #include #include #include #include "base/bind.h" #include "base/memory/raw_ptr.h" #include "base/no_destructor.h" #include "base/observer_list.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/prefs/pref_service.h" #include "components/profile_metrics/browser_profile_type.h" #include "components/web_cache/browser/web_cache_manager.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/device_service.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/page_navigator.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "services/network/public/mojom/network_context.mojom.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "weblayer/browser/browser_context_impl.h" #include "weblayer/browser/browser_impl.h" #include "weblayer/browser/browser_list.h" #include "weblayer/browser/browsing_data_remover_delegate.h" #include "weblayer/browser/cookie_manager_impl.h" #include "weblayer/browser/favicon/favicon_service_impl.h" #include "weblayer/browser/favicon/favicon_service_impl_factory.h" #include "weblayer/browser/no_state_prefetch/prerender_controller_impl.h" #include "weblayer/browser/persistence/browser_persister_file_utils.h" #include "weblayer/browser/tab_impl.h" #if defined(OS_ANDROID) #include "base/android/callback_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" #include "components/safe_browsing/core/common/safe_browsing_prefs.h" #include "components/unified_consent/pref_names.h" #include "ui/gfx/android/java_bitmap.h" #include "weblayer/browser/android/metrics/weblayer_metrics_service_client.h" #include "weblayer/browser/browser_process.h" #include "weblayer/browser/java/jni/ProfileImpl_jni.h" #include "weblayer/browser/safe_browsing/safe_browsing_service.h" #endif #if defined(OS_POSIX) #include "base/base_paths_posix.h" #endif #if defined(OS_ANDROID) using base::android::AttachCurrentThread; #endif namespace weblayer { namespace { bool g_first_profile_created = false; // TaskRunner used by MarkProfileAsDeleted and NukeProfilesMarkedForDeletion to // esnure that Nuke happens before any Mark in this process. base::SequencedTaskRunner* GetBackgroundDiskOperationTaskRunner() { static const base::NoDestructor> task_runner(base::ThreadPool::CreateSingleThreadTaskRunner( {base::MayBlock(), base::TaskPriority::BEST_EFFORT})); return task_runner.get()->get(); } std::set& GetProfiles() { static base::NoDestructor> s_all_profiles; return *s_all_profiles; } base::ObserverList::Unchecked& GetObservers() { static base::NoDestructor< base::ObserverList::Unchecked> s_observers; return *s_observers; } #if defined(OS_ANDROID) void PassFilePathsToJavaCallback( const base::android::ScopedJavaGlobalRef& callback, const std::vector& file_paths) { base::android::RunObjectCallbackAndroid( callback, base::android::ToJavaArrayOfStrings( base::android::AttachCurrentThread(), file_paths)); } void OnGotBrowserPersistenceIds( const base::android::ScopedJavaGlobalRef& callback, base::flat_set ids) { std::vector as_vector; for (const std::string& id : ids) as_vector.push_back(id); base::android::RunObjectCallbackAndroid( callback, base::android::ToJavaArrayOfStrings(AttachCurrentThread(), as_vector)); } void OnDidRemoveBrowserPersistenceStorage( const base::android::ScopedJavaGlobalRef& callback, bool result) { base::android::RunBooleanCallbackAndroid(callback, result); } void OnDidGetCachedFaviconForPageUrl( const base::android::ScopedJavaGlobalRef& callback, gfx::Image image) { SkBitmap favicon = image.AsImageSkia().GetRepresentation(1.0f).GetBitmap(); base::android::RunObjectCallbackAndroid( callback, favicon.empty() ? nullptr : gfx::ConvertToJavaBitmap(favicon)); } #endif // OS_ANDROID } // namespace class ProfileImpl::DataClearer : public content::BrowsingDataRemover::Observer { public: DataClearer(content::BrowserContext* browser_context, base::OnceCallback callback) : remover_(browser_context->GetBrowsingDataRemover()), callback_(std::move(callback)) { remover_->AddObserver(this); } void ClearData(ProfileImpl* profile, uint64_t mask, base::Time from_time, base::Time to_time) { uint64_t origin_types = content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB | content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB; remover_->RemoveAndReply(from_time, to_time, mask, origin_types, this); } // content::BrowsingDataRemover::Observer: void OnBrowsingDataRemoverDone(uint64_t failed_data_types) override { // Remove the observer now as after this returns the BrowserContext may // be destroyed, which owns |remover_|. remover_->RemoveObserver(this); std::move(callback_).Run(); delete this; } private: // DataClearer deletes itself when removal is done. ~DataClearer() override = default; raw_ptr remover_; base::OnceCallback callback_; }; // static base::FilePath ProfileImpl::GetCachePath(content::BrowserContext* context) { DCHECK(context); ProfileImpl* profile = FromBrowserContext(context); return profile->info_.cache_path; } ProfileImpl::ProfileImpl(const std::string& name, bool is_incognito) : download_directory_(BrowserContextImpl::GetDefaultDownloadDirectory()) { { base::ScopedAllowBlocking allow_blocking; info_ = CreateProfileInfo(name, is_incognito); } GetProfiles().insert(this); profile_metrics::SetBrowserProfileType( GetBrowserContext(), is_incognito ? profile_metrics::BrowserProfileType::kIncognito : profile_metrics::BrowserProfileType::kRegular); for (auto& observer : GetObservers()) observer.ProfileCreated(this); if (!g_first_profile_created) { g_first_profile_created = true; GetBackgroundDiskOperationTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&NukeProfilesMarkedForDeletion)); } // Ensure WebCacheManager is created so that it starts observing // OnRenderProcessHostCreated events. web_cache::WebCacheManager::GetInstance(); #if defined(OS_ANDROID) WebLayerMetricsServiceClient::GetInstance()->UpdateUkm(false); #endif } ProfileImpl::~ProfileImpl() { // Destroy any scheduled WebContents. These implicitly refer to the // BrowserContext and must be destroyed before the BrowserContext. web_contents_to_delete_.clear(); if (browser_context_) { BrowserContextDependencyManager::GetInstance() ->DestroyBrowserContextServices(browser_context_.get()); browser_context_->ShutdownStoragePartitions(); } GetProfiles().erase(this); for (auto& observer : GetObservers()) observer.ProfileDestroyed(this); } ProfileImpl* ProfileImpl::FromBrowserContext( content::BrowserContext* browser_context) { return static_cast(browser_context)->profile_impl(); } std::set ProfileImpl::GetAllProfiles() { return GetProfiles(); } void ProfileImpl::AddProfileObserver(ProfileObserver* observer) { GetObservers().AddObserver(observer); } void ProfileImpl::RemoveProfileObserver(ProfileObserver* observer) { GetObservers().RemoveObserver(observer); } void ProfileImpl::DeleteWebContentsSoon( std::unique_ptr web_contents) { if (web_contents_to_delete_.empty()) { base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&ProfileImpl::DeleteScheduleWebContents, weak_ptr_factory_.GetWeakPtr())); } web_contents_to_delete_.push_back(std::move(web_contents)); } BrowserContextImpl* ProfileImpl::GetBrowserContext() { if (browser_context_) return browser_context_.get(); browser_context_ = std::make_unique(this, info_.data_path); locale_change_subscription_ = i18n::RegisterLocaleChangeCallback(base::BindRepeating( &ProfileImpl::OnLocaleChanged, base::Unretained(this))); return browser_context_.get(); } void ProfileImpl::DownloadsInitialized() { #if defined(OS_ANDROID) return Java_ProfileImpl_downloadsInitialized( base::android::AttachCurrentThread(), java_profile_); #endif } void ProfileImpl::MarkAsDeleted() { GetBackgroundDiskOperationTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&MarkProfileAsDeleted, info_)); } void ProfileImpl::ClearBrowsingData( const std::vector& data_types, base::Time from_time, base::Time to_time, base::OnceClosure callback) { auto* clearer = new DataClearer(GetBrowserContext(), std::move(callback)); // DataClearer will delete itself in OnBrowsingDataRemoverDone(). // If Profile is destroyed during clearing, it would lead to destroying // browser_context_ and then BrowsingDataRemover, which in turn would call // OnBrowsingDataRemoverDone(), even though the clearing hasn't been finished. uint64_t remove_mask = 0; // This follows what Chrome does: see browsing_data_bridge.cc. for (auto data_type : data_types) { switch (data_type) { case BrowsingDataType::COOKIES_AND_SITE_DATA: remove_mask |= content::BrowsingDataRemover::DATA_TYPE_COOKIES; remove_mask |= content::BrowsingDataRemover::DATA_TYPE_DOM_STORAGE; remove_mask |= content::BrowsingDataRemover::DATA_TYPE_MEDIA_LICENSES; remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_ISOLATED_ORIGINS; remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_FAVICONS; remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_AD_INTERVENTIONS; remove_mask |= content::BrowsingDataRemover::DATA_TYPE_TRUST_TOKENS; remove_mask |= content::BrowsingDataRemover::DATA_TYPE_CONVERSIONS; break; case BrowsingDataType::CACHE: remove_mask |= content::BrowsingDataRemover::DATA_TYPE_CACHE; ClearRendererCache(); break; case BrowsingDataType::SITE_SETTINGS: remove_mask |= BrowsingDataRemoverDelegate::DATA_TYPE_SITE_SETTINGS; break; default: NOTREACHED(); } } clearer->ClearData(this, remove_mask, from_time, to_time); } void ProfileImpl::SetDownloadDirectory(const base::FilePath& directory) { download_directory_ = directory; } void ProfileImpl::SetDownloadDelegate(DownloadDelegate* delegate) { download_delegate_ = delegate; } void ProfileImpl::SetGoogleAccountAccessTokenFetchDelegate( GoogleAccountAccessTokenFetchDelegate* delegate) { access_token_fetch_delegate_ = delegate; } CookieManager* ProfileImpl::GetCookieManager() { if (!cookie_manager_) cookie_manager_ = std::make_unique(GetBrowserContext()); return cookie_manager_.get(); } PrerenderController* ProfileImpl::GetPrerenderController() { if (!prerender_controller_) prerender_controller_ = std::make_unique(GetBrowserContext()); return prerender_controller_.get(); } void ProfileImpl::GetBrowserPersistenceIds( base::OnceCallback)> callback) { DCHECK(!browser_context_->IsOffTheRecord()); base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::BindOnce(&GetBrowserPersistenceIdsOnBackgroundThread, GetBrowserPersisterDataBaseDir()), std::move(callback)); } void ProfileImpl::RemoveBrowserPersistenceStorage( base::OnceCallback done_callback, base::flat_set ids) { DCHECK(!browser_context_->IsOffTheRecord()); RemoveBrowserPersistenceStorageImpl(this, std::move(done_callback), std::move(ids)); } // static void ProfileImpl::NukeDataAfterRemovingData( std::unique_ptr profile, base::OnceClosure done_callback) { // Need PostTask to avoid reentrancy for deleting |browser_context_|. content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&ProfileImpl::DoNukeData, std::move(profile), std::move(done_callback))); } // static void ProfileImpl::DoNukeData(std::unique_ptr profile, base::OnceClosure done_callback) { ProfileInfo info = profile->info_; profile.reset(); GetBackgroundDiskOperationTaskRunner()->PostTaskAndReply( FROM_HERE, base::BindOnce(&TryNukeProfileFromDisk, info), std::move(done_callback)); } void ProfileImpl::ClearRendererCache() { for (content::RenderProcessHost::iterator iter = content::RenderProcessHost::AllHostsIterator(); !iter.IsAtEnd(); iter.Advance()) { content::RenderProcessHost* render_process_host = iter.GetCurrentValue(); if (render_process_host->GetBrowserContext() == GetBrowserContext() && render_process_host->IsInitializedAndNotDead()) { web_cache::WebCacheManager::GetInstance()->ClearCacheForProcess( render_process_host->GetID()); } } } void ProfileImpl::OnLocaleChanged() { GetBrowserContext()->ForEachStoragePartition(base::BindRepeating( [](const std::string& accept_language, content::StoragePartition* storage_partition) { storage_partition->GetNetworkContext()->SetAcceptLanguage( accept_language); }, i18n::GetAcceptLangs())); } // static std::unique_ptr Profile::Create(const std::string& name, bool is_incognito) { return std::make_unique(name, is_incognito); } // static std::unique_ptr Profile::DestroyAndDeleteDataFromDisk( std::unique_ptr profile, base::OnceClosure done_callback) { std::unique_ptr impl( static_cast(profile.release())); return ProfileImpl::DestroyAndDeleteDataFromDisk(std::move(impl), std::move(done_callback)); } // static std::unique_ptr ProfileImpl::DestroyAndDeleteDataFromDisk( std::unique_ptr profile, base::OnceClosure done_callback) { if (profile->GetNumberOfBrowsers() > 0) return profile; ProfileInfo profile_info = profile->info_; GetBackgroundDiskOperationTaskRunner()->PostTaskAndReply( FROM_HERE, base::BindOnce(&MarkProfileAsDeleted, profile_info), base::BindOnce(&ProfileImpl::OnProfileMarked, std::move(profile), std::move(done_callback))); return nullptr; } // static void ProfileImpl::OnProfileMarked(std::unique_ptr profile, base::OnceClosure done_callback) { // Try to finish all writes and remove all data before nuking the profile. profile->GetBrowserContext()->pref_service()->CommitPendingWrite(); ProfileImpl* raw_profile = profile.get(); auto* clearer = new DataClearer( raw_profile->GetBrowserContext(), base::BindOnce(&ProfileImpl::NukeDataAfterRemovingData, std::move(profile), std::move(done_callback))); uint64_t remove_all_mask = 0xffffffffffffffffull; clearer->ClearData(raw_profile, remove_all_mask, base::Time::Min(), base::Time::Max()); } #if defined(OS_ANDROID) ProfileImpl::ProfileImpl( JNIEnv* env, const base::android::JavaParamRef& name, const base::android::JavaParamRef& java_profile, bool is_incognito) : ProfileImpl(ConvertJavaStringToUTF8(env, name), is_incognito) { java_profile_ = java_profile; } static jlong JNI_ProfileImpl_CreateProfile( JNIEnv* env, const base::android::JavaParamRef& name, const base::android::JavaParamRef& java_profile, jboolean is_incognito) { return reinterpret_cast( new ProfileImpl(env, name, java_profile, is_incognito)); } static void JNI_ProfileImpl_DeleteProfile(JNIEnv* env, jlong profile) { delete reinterpret_cast(profile); } static void JNI_ProfileImpl_EnumerateAllProfileNames( JNIEnv* env, const base::android::JavaParamRef& callback) { base::ThreadPool::PostTaskAndReplyWithResult( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::BindOnce(&ListProfileNames), base::BindOnce(&PassFilePathsToJavaCallback, base::android::ScopedJavaGlobalRef(callback))); } jint ProfileImpl::GetNumBrowserImpl(JNIEnv* env) { return GetNumberOfBrowsers(); } jlong ProfileImpl::GetBrowserContext(JNIEnv* env) { return reinterpret_cast(GetBrowserContext()); } void ProfileImpl::DestroyAndDeleteDataFromDisk( JNIEnv* env, const base::android::JavaRef& j_completion_callback) { std::unique_ptr ptr(this); std::unique_ptr result = ProfileImpl::DestroyAndDeleteDataFromDisk( std::move(ptr), base::BindOnce(&base::android::RunRunnableAndroid, base::android::ScopedJavaGlobalRef( j_completion_callback))); CHECK(!result); } void ProfileImpl::ClearBrowsingData( JNIEnv* env, const base::android::JavaParamRef& j_data_types, const jlong j_from_time_millis, const jlong j_to_time_millis, const base::android::JavaRef& j_callback) { std::vector data_type_ints; base::android::JavaIntArrayToIntVector(env, j_data_types, &data_type_ints); std::vector data_types; data_types.reserve(data_type_ints.size()); for (int type : data_type_ints) data_types.push_back(static_cast(type)); ClearBrowsingData( data_types, base::Time::FromJavaTime(static_cast(j_from_time_millis)), base::Time::FromJavaTime(static_cast(j_to_time_millis)), base::BindOnce(base::android::RunRunnableAndroid, base::android::ScopedJavaGlobalRef(j_callback))); } void ProfileImpl::SetDownloadDirectory( JNIEnv* env, const base::android::JavaParamRef& directory) { base::FilePath directory_path( base::android::ConvertJavaStringToUTF8(directory)); SetDownloadDirectory(directory_path); } jlong ProfileImpl::GetCookieManager(JNIEnv* env) { return reinterpret_cast(GetCookieManager()); } jlong ProfileImpl::GetPrerenderController(JNIEnv* env) { return reinterpret_cast(GetPrerenderController()); } void ProfileImpl::EnsureBrowserContextInitialized(JNIEnv* env) { GetBrowserContext()->GetDownloadManager(); } void ProfileImpl::SetBooleanSetting(JNIEnv* env, jint j_type, jboolean j_value) { SetBooleanSetting(static_cast(j_type), j_value); } jboolean ProfileImpl::GetBooleanSetting(JNIEnv* env, jint j_type) { return GetBooleanSetting(static_cast(j_type)); } void ProfileImpl::GetBrowserPersistenceIds( JNIEnv* env, const base::android::JavaRef& j_callback) { GetBrowserPersistenceIds( base::BindOnce(&OnGotBrowserPersistenceIds, base::android::ScopedJavaGlobalRef(j_callback))); } void ProfileImpl::RemoveBrowserPersistenceStorage( JNIEnv* env, const base::android::JavaRef& j_ids, const base::android::JavaRef& j_callback) { std::vector ids; base::android::AppendJavaStringArrayToStringVector(env, j_ids, &ids); RemoveBrowserPersistenceStorage( base::BindOnce(&OnDidRemoveBrowserPersistenceStorage, base::android::ScopedJavaGlobalRef(j_callback)), base::flat_set(ids.begin(), ids.end())); } void ProfileImpl::PrepareForPossibleCrossOriginNavigation(JNIEnv* env) { PrepareForPossibleCrossOriginNavigation(); } void ProfileImpl::GetCachedFaviconForPageUrl( JNIEnv* env, const base::android::JavaRef& j_page_url, const base::android::JavaRef& j_callback) { GetCachedFaviconForPageUrl( GURL(base::android::ConvertJavaStringToUTF8(j_page_url)), base::BindOnce(&OnDidGetCachedFaviconForPageUrl, base::android::ScopedJavaGlobalRef(j_callback))); } #endif // OS_ANDROID base::FilePath ProfileImpl::GetBrowserPersisterDataBaseDir() const { return ComputeBrowserPersisterDataBaseDir(info_); } content::WebContents* ProfileImpl::OpenUrl( const content::OpenURLParams& params) { #if !defined(OS_ANDROID) return nullptr; #else // We expect only NEW_FOREGROUND_TAB. The NEW_POPUP disposition is only used // for payment handler windows, but WebLayer (and Android Chrome) do not // support that. See ContentBrowserClient::ShowPaymentHandlerWindow(). DCHECK_EQ(params.disposition, WindowOpenDisposition::NEW_FOREGROUND_TAB); JNIEnv* env = base::android::AttachCurrentThread(); BrowserImpl* browser = reinterpret_cast( Java_ProfileImpl_getBrowserForNewTab(env, java_profile_)); if (!browser) return nullptr; std::unique_ptr new_tab_contents = content::WebContents::Create( content::WebContents::CreateParams(GetBrowserContext())); base::WeakPtr new_tab_contents_weak_ptr( new_tab_contents->GetWeakPtr()); Tab* tab = browser->CreateTab(std::move(new_tab_contents)); if (!new_tab_contents_weak_ptr) return nullptr; Java_ProfileImpl_onTabAdded(env, java_profile_, static_cast(tab)->GetJavaTab()); new_tab_contents_weak_ptr->GetController().LoadURLWithParams( content::NavigationController::LoadURLParams(params)); return new_tab_contents_weak_ptr.get(); #endif // defined(OS_ANDROID) } void ProfileImpl::SetBooleanSetting(SettingType type, bool value) { auto* pref_service = GetBrowserContext()->pref_service(); switch (type) { case SettingType::BASIC_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) safe_browsing::SetSafeBrowsingState( pref_service, value ? safe_browsing::SafeBrowsingState::STANDARD_PROTECTION : safe_browsing::SafeBrowsingState::NO_SAFE_BROWSING, /*is_esb_enabled_in_sync=*/false); #endif break; case SettingType::UKM_ENABLED: { #if defined(OS_ANDROID) bool old_value = pref_service->GetBoolean(prefs::kUkmEnabled); #endif pref_service->SetBoolean(prefs::kUkmEnabled, value); #if defined(OS_ANDROID) // Trigger a purge if the current state no longer allows UKM. bool must_purge = old_value && !value; WebLayerMetricsServiceClient::GetInstance()->UpdateUkm(must_purge); #endif break; } case SettingType::EXTENDED_REPORTING_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) pref_service->SetBoolean(::prefs::kSafeBrowsingScoutReportingEnabled, value); #endif break; case SettingType::REAL_TIME_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) pref_service->SetBoolean( unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, value); #endif break; case SettingType::NETWORK_PREDICTION_ENABLED: pref_service->SetBoolean(prefs::kNoStatePrefetchEnabled, value); } } bool ProfileImpl::GetBooleanSetting(SettingType type) { auto* pref_service = GetBrowserContext()->pref_service(); switch (type) { case SettingType::BASIC_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) return safe_browsing::IsSafeBrowsingEnabled(*pref_service); #else return false; #endif case SettingType::UKM_ENABLED: return pref_service->GetBoolean(prefs::kUkmEnabled); case SettingType::EXTENDED_REPORTING_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) return pref_service->GetBoolean( ::prefs::kSafeBrowsingScoutReportingEnabled); #else return false; #endif case SettingType::REAL_TIME_SAFE_BROWSING_ENABLED: #if defined(OS_ANDROID) return pref_service->GetBoolean( unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled); #else return false; #endif case SettingType::NETWORK_PREDICTION_ENABLED: return pref_service->GetBoolean(prefs::kNoStatePrefetchEnabled); } NOTREACHED(); } void ProfileImpl::GetCachedFaviconForPageUrl( const GURL& page_url, base::OnceCallback callback) { auto* service = FaviconServiceImplFactory::GetForBrowserContext(GetBrowserContext()); if (!service) { std::move(callback).Run({}); return; } service->GetFaviconForPageUrl(page_url, std::move(callback), &cancelable_task_tracker_); } void ProfileImpl::PrepareForPossibleCrossOriginNavigation() { content::RenderProcessHost::WarmupSpareRenderProcessHost(GetBrowserContext()); } int ProfileImpl::GetNumberOfBrowsers() { const auto& browsers = BrowserList::GetInstance()->browsers(); return std::count_if(browsers.begin(), browsers.end(), [this](BrowserImpl* b) { return b->profile() == this; }); } void ProfileImpl::DeleteScheduleWebContents() { web_contents_to_delete_.clear(); } } // namespace weblayer