| // Copyright 2021 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "content/browser/browser_context_impl.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/memory/ref_counted.h" | 
 | #include "base/task/sequenced_task_runner.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "build/build_config.h" | 
 | #include "content/browser/background_sync/background_sync_scheduler.h" | 
 | #include "content/browser/browsing_data/browsing_data_remover_impl.h" | 
 | #include "content/browser/download/download_manager_impl.h" | 
 | #include "content/browser/permissions/permission_controller_impl.h" | 
 | #include "content/browser/preloading/prefetch/prefetch_service.h" | 
 | #include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_cache.h" | 
 | #include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_manager.h" | 
 | #include "content/browser/speech/tts_controller_impl.h" | 
 | #include "content/browser/storage_partition_impl.h" | 
 | #include "content/browser/storage_partition_impl_map.h" | 
 | #include "content/public/browser/browser_context.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "content/public/browser/render_process_host.h" | 
 | #include "content/public/browser/shared_worker_service.h" | 
 | #include "media/capabilities/webrtc_video_stats_db_impl.h" | 
 | #include "media/learning/common/media_learning_tasks.h" | 
 | #include "media/learning/impl/learning_session_impl.h" | 
 | #include "media/mojo/services/video_decode_perf_history.h" | 
 | #include "media/mojo/services/webrtc_video_perf_history.h" | 
 |  | 
 | #if BUILDFLAG(IS_CHROMEOS_ASH) | 
 | #include "storage/browser/file_system/external_mount_points.h" | 
 | #endif | 
 |  | 
 | namespace content { | 
 |  | 
 | namespace { | 
 |  | 
 | void NotifyContextWillBeDestroyed(StoragePartition* partition) { | 
 |   static_cast<StoragePartitionImpl*>(partition) | 
 |       ->OnBrowserContextWillBeDestroyed(); | 
 | } | 
 |  | 
 | void RegisterMediaLearningTask( | 
 |     media::learning::LearningSessionImpl* learning_session, | 
 |     const media::learning::LearningTask& task) { | 
 |   // The RegisterTask method cannot be directly used in base::Bind, because it | 
 |   // provides a default argument value for the 2nd parameter | 
 |   // (`feature_provider`). | 
 |   learning_session->RegisterTask(task); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // static | 
 | BrowserContextImpl* BrowserContextImpl::From(BrowserContext* self) { | 
 |   return self->impl(); | 
 | } | 
 |  | 
 | BrowserContextImpl::BrowserContextImpl(BrowserContext* self) : self_(self) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   background_sync_scheduler_ = base::MakeRefCounted<BackgroundSyncScheduler>(); | 
 | } | 
 |  | 
 | BrowserContextImpl::~BrowserContextImpl() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   DCHECK(!storage_partition_map_) | 
 |       << "StoragePartitionMap is not shut down properly"; | 
 |  | 
 |   if (!will_be_destroyed_soon_) { | 
 |     NOTREACHED(); | 
 |   } | 
 |  | 
 |   // Verify that there are no outstanding RenderProcessHosts that reference | 
 |   // this context. Trigger a crash report if there are still references so | 
 |   // we can detect/diagnose potential UAFs. | 
 |   std::string rph_crash_key_value; | 
 |   ChildProcessSecurityPolicyImpl* policy = | 
 |       ChildProcessSecurityPolicyImpl::GetInstance(); | 
 |   for (RenderProcessHost::iterator host_iterator = | 
 |            RenderProcessHost::AllHostsIterator(); | 
 |        !host_iterator.IsAtEnd(); host_iterator.Advance()) { | 
 |     RenderProcessHost* host = host_iterator.GetCurrentValue(); | 
 |     if (host->GetBrowserContext() == self_) { | 
 |       rph_crash_key_value += | 
 |           "{ " + host->GetInfoForBrowserContextDestructionCrashReporting() + | 
 |           " }"; | 
 |     } | 
 |   } | 
 |   if (!rph_crash_key_value.empty()) { | 
 |     SCOPED_CRASH_KEY_STRING256("BrowserContext", "dangling_rph", | 
 |                                rph_crash_key_value); | 
 |     NOTREACHED() << "rph_with_bc_reference : " << rph_crash_key_value; | 
 |   } | 
 |  | 
 |   // Clean up any isolated origins and other security state associated with this | 
 |   // BrowserContext. | 
 |   policy->RemoveStateForBrowserContext(*self_); | 
 |  | 
 |   if (download_manager_) | 
 |     download_manager_->Shutdown(); | 
 |  | 
 |   TtsControllerImpl::GetInstance()->OnBrowserContextDestroyed(self_); | 
 |  | 
 |   TRACE_EVENT_NESTABLE_ASYNC_END1( | 
 |       "shutdown", "BrowserContextImpl::NotifyWillBeDestroyed() called.", this, | 
 |       "browser_context_impl", static_cast<void*>(this)); | 
 | } | 
 |  | 
 | bool BrowserContextImpl::ShutdownStarted() { | 
 |   return will_be_destroyed_soon_; | 
 | } | 
 |  | 
 | void BrowserContextImpl::NotifyWillBeDestroyed() { | 
 |   TRACE_EVENT1("shutdown", "BrowserContextImpl::NotifyWillBeDestroyed", | 
 |                "browser_context_impl", static_cast<void*>(this)); | 
 |   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( | 
 |       "shutdown", "BrowserContextImpl::NotifyWillBeDestroyed() called.", this, | 
 |       "browser_context_impl", static_cast<void*>(this)); | 
 |   // Make sure NotifyWillBeDestroyed is idempotent.  This helps facilitate the | 
 |   // pattern where NotifyWillBeDestroyed is called from *both* | 
 |   // ShellBrowserContext and its derived classes (e.g. WebTestBrowserContext). | 
 |   if (will_be_destroyed_soon_) | 
 |     return; | 
 |   will_be_destroyed_soon_ = true; | 
 |  | 
 |   self_->ForEachLoadedStoragePartition(&NotifyContextWillBeDestroyed); | 
 |  | 
 |   // Also forcibly release keep alive refcounts on RenderProcessHosts, to ensure | 
 |   // they destruct before the BrowserContext does. | 
 |   for (RenderProcessHost::iterator host_iterator = | 
 |            RenderProcessHost::AllHostsIterator(); | 
 |        !host_iterator.IsAtEnd(); host_iterator.Advance()) { | 
 |     RenderProcessHost* host = host_iterator.GetCurrentValue(); | 
 |     if (host->GetBrowserContext() == self_) { | 
 |       // This will also clean up spare RPH references. | 
 |       host->DisableRefCounts(); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | StoragePartitionImplMap* BrowserContextImpl::GetOrCreateStoragePartitionMap() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!storage_partition_map_) | 
 |     storage_partition_map_ = std::make_unique<StoragePartitionImplMap>(self_); | 
 |  | 
 |   return storage_partition_map_.get(); | 
 | } | 
 |  | 
 | BrowsingDataRemoverImpl* BrowserContextImpl::GetBrowsingDataRemover() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!browsing_data_remover_) { | 
 |     browsing_data_remover_ = std::make_unique<BrowsingDataRemoverImpl>(self_); | 
 |     browsing_data_remover_->SetEmbedderDelegate( | 
 |         self_->GetBrowsingDataRemoverDelegate()); | 
 |   } | 
 |  | 
 |   return browsing_data_remover_.get(); | 
 | } | 
 |  | 
 | media::learning::LearningSession* BrowserContextImpl::GetLearningSession() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!learning_session_) { | 
 |     learning_session_ = std::make_unique<media::learning::LearningSessionImpl>( | 
 |         base::SequencedTaskRunner::GetCurrentDefault()); | 
 |  | 
 |     // Using base::Unretained is safe below, because the callback here will not | 
 |     // be called or retained after the Register method below returns. | 
 |     media::learning::MediaLearningTasks::Register(base::BindRepeating( | 
 |         &RegisterMediaLearningTask, base::Unretained(learning_session_.get()))); | 
 |   } | 
 |  | 
 |   return learning_session_.get(); | 
 | } | 
 |  | 
 | media::VideoDecodePerfHistory* BrowserContextImpl::GetVideoDecodePerfHistory() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!video_decode_perf_history_) | 
 |     video_decode_perf_history_ = self_->CreateVideoDecodePerfHistory(); | 
 |  | 
 |   return video_decode_perf_history_.get(); | 
 | } | 
 |  | 
 | std::unique_ptr<media::WebrtcVideoPerfHistory> | 
 | BrowserContextImpl::CreateWebrtcVideoPerfHistory() { | 
 |   // TODO(https://crbug.com/1187565): Implement in memory path in | 
 |   // off_the_record_profile_impl.cc and web_engine_browser_context.cc | 
 |  | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   auto* db_provider = | 
 |       self_->GetDefaultStoragePartition()->GetProtoDatabaseProvider(); | 
 |  | 
 |   std::unique_ptr<media::WebrtcVideoStatsDB> stats_db = | 
 |       media::WebrtcVideoStatsDBImpl::Create( | 
 |           self_->GetPath().Append(FILE_PATH_LITERAL("WebrtcVideoStats")), | 
 |           db_provider); | 
 |  | 
 |   return std::make_unique<media::WebrtcVideoPerfHistory>(std::move(stats_db)); | 
 | } | 
 |  | 
 | media::WebrtcVideoPerfHistory* BrowserContextImpl::GetWebrtcVideoPerfHistory() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!webrtc_video_perf_history_) | 
 |     webrtc_video_perf_history_ = CreateWebrtcVideoPerfHistory(); | 
 |  | 
 |   return webrtc_video_perf_history_.get(); | 
 | } | 
 |  | 
 | void BrowserContextImpl::ShutdownStoragePartitions() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   // The BackgroundSyncScheduler keeps raw pointers to partitions; clear it | 
 |   // first. | 
 |   DCHECK(background_sync_scheduler_->HasOneRef()); | 
 |   background_sync_scheduler_.reset(); | 
 |  | 
 |   storage_partition_map_.reset(); | 
 | } | 
 |  | 
 | DownloadManager* BrowserContextImpl::GetDownloadManager() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   // Lazily populate `download_manager_`.  This is important to | 
 |   // 1) Avoid constructing DownloadManagerImpl when a test might have provided | 
 |   //    an alternative object via SetDownloadManagerForTesting. | 
 |   // 2) Avoiding calling into DownloadManagerImpl's constructor with a partially | 
 |   //    constructed BrowserContext. | 
 |   if (!download_manager_) { | 
 |     download_manager_ = std::make_unique<DownloadManagerImpl>(self_); | 
 |  | 
 |     // Note that GetDownloadManagerDelegate might call into GetDownloadManager, | 
 |     // leading to re-entrancy concerns.  We avoid re-entrancy by making sure | 
 |     // `download_manager_` is set earlier, above. | 
 |     download_manager_->SetDelegate(self_->GetDownloadManagerDelegate()); | 
 |   } | 
 |  | 
 |   return download_manager_.get(); | 
 | } | 
 |  | 
 | void BrowserContextImpl::SetDownloadManagerForTesting( | 
 |     std::unique_ptr<DownloadManager> download_manager) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   if (download_manager_) | 
 |     download_manager_->Shutdown(); | 
 |   download_manager_ = std::move(download_manager); | 
 | } | 
 |  | 
 | PermissionController* BrowserContextImpl::GetPermissionController() { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |  | 
 |   if (!permission_controller_) | 
 |     permission_controller_ = std::make_unique<PermissionControllerImpl>(self_); | 
 |  | 
 |   return permission_controller_.get(); | 
 | } | 
 |  | 
 | void BrowserContextImpl::SetPermissionControllerForTesting( | 
 |     std::unique_ptr<PermissionController> permission_controller) { | 
 |   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
 |   permission_controller_ = std::move(permission_controller); | 
 | } | 
 |  | 
 | storage::ExternalMountPoints* BrowserContextImpl::GetMountPoints() { | 
 |   // Ensure that these methods are called on the UI thread, except for | 
 |   // unittests where a UI thread might not have been created. | 
 |   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | 
 |          !BrowserThread::IsThreadInitialized(BrowserThread::UI)); | 
 |  | 
 | #if BUILDFLAG(IS_CHROMEOS_ASH) | 
 |   if (!external_mount_points_) | 
 |     external_mount_points_ = storage::ExternalMountPoints::CreateRefCounted(); | 
 |   return external_mount_points_.get(); | 
 | #else | 
 |   return nullptr; | 
 | #endif | 
 | } | 
 |  | 
 | PrefetchService* BrowserContextImpl::GetPrefetchService() { | 
 |   if (!prefetch_service_) { | 
 |     prefetch_service_ = std::make_unique<PrefetchService>(self_); | 
 |   } | 
 |  | 
 |   return prefetch_service_.get(); | 
 | } | 
 |  | 
 | void BrowserContextImpl::SetPrefetchServiceForTesting( | 
 |     std::unique_ptr<PrefetchService> prefetch_service) { | 
 |   prefetch_service_ = std::move(prefetch_service); | 
 | } | 
 |  | 
 | NavigationEntryScreenshotManager* | 
 | BrowserContextImpl::GetNavigationEntryScreenshotManager() { | 
 |   if (!nav_entry_screenshot_manager_ && AreBackForwardTransitionsEnabled()) { | 
 |     nav_entry_screenshot_manager_ = | 
 |         std::make_unique<NavigationEntryScreenshotManager>(); | 
 |   } | 
 |   return nav_entry_screenshot_manager_.get(); | 
 | } | 
 |  | 
 | void BrowserContextImpl::WriteIntoTrace( | 
 |     perfetto::TracedProto<TraceProto> proto) const { | 
 |   proto->set_id(UniqueId()); | 
 | } | 
 |  | 
 | }  // namespace content |