// Copyright (c) 2015 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 "libcef/browser/browser_context.h" #include "libcef/browser/content_browser_client.h" #include "libcef/browser/extensions/extension_system.h" #include "libcef/browser/thread_util.h" #include "libcef/common/extensions/extensions_util.h" #include "base/logging.h" #include "chrome/browser/plugins/chrome_plugin_service_filter.h" #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "extensions/browser/process_manager.h" CefBrowserContext::CefBrowserContext(bool is_proxy) : is_proxy_(is_proxy), extension_system_(NULL) {} CefBrowserContext::~CefBrowserContext() { // Should be cleared in Shutdown(). DCHECK(!resource_context_.get()); } void CefBrowserContext::Initialize() { content::BrowserContext::Initialize(this, GetPath()); resource_context_.reset( new CefResourceContext(IsOffTheRecord(), GetHandler())); // This must be called before creating any services to avoid hitting // DependencyManager::AssertContextWasntDestroyed when creating/destroying // multiple browser contexts (due to pointer address reuse). BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices( this); const bool extensions_enabled = extensions::ExtensionsEnabled(); if (extensions_enabled) { // Create the custom ExtensionSystem first because other KeyedServices // depend on it. // The same CefExtensionSystem instance is shared by CefBrowserContextImpl // and CefBrowserContextProxy objects. extension_system_ = static_cast( extensions::ExtensionSystem::Get(this)); if (is_proxy_) { DCHECK(extension_system_->initialized()); } else { extension_system_->InitForRegularProfile(true); } resource_context_->set_extensions_info_map(extension_system_->info_map()); // Make sure the ProcessManager is created so that it receives extension // load notifications. This is necessary for the proper initialization of // background/event pages. extensions::ProcessManager::Get(this); } } void CefBrowserContext::PostInitialize() { // Spell checking support and possibly other subsystems retrieve the // PrefService associated with a BrowserContext via UserPrefs::Get(). PrefService* pref_service = GetPrefs(); DCHECK(pref_service); user_prefs::UserPrefs::Set(this, pref_service); const bool extensions_enabled = extensions::ExtensionsEnabled(); if (extensions_enabled && !is_proxy_) extension_system_->Init(); ChromePluginServiceFilter::GetInstance()->RegisterResourceContext( this, resource_context_.get()); } void CefBrowserContext::Shutdown() { CEF_REQUIRE_UIT(); // Send notifications to clean up objects associated with this Profile. MaybeSendDestroyedNotification(); ChromePluginServiceFilter::GetInstance()->UnregisterResourceContext( resource_context_.get()); // Remove any BrowserContextKeyedServiceFactory associations. This must be // called before the ProxyService owned by CefBrowserContextImpl is destroyed. BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices( this); if (!is_proxy_) { // Shuts down the storage partitions associated with this browser context. // This must be called before the browser context is actually destroyed // and before a clean-up task for its corresponding IO thread residents // (e.g. ResourceContext) is posted, so that the classes that hung on // StoragePartition can have time to do necessary cleanups on IO thread. ShutdownStoragePartitions(); } if (resource_context_.get()) { // Destruction of the ResourceContext will trigger destruction of all // associated URLRequests. content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE, resource_context_.release()); } } content::ResourceContext* CefBrowserContext::GetResourceContext() { return resource_context_.get(); } net::URLRequestContextGetter* CefBrowserContext::GetRequestContext() { CEF_REQUIRE_UIT(); return GetDefaultStoragePartition(this)->GetURLRequestContext(); } net::URLRequestContextGetter* CefBrowserContext::CreateMediaRequestContext() { return GetRequestContext(); } net::URLRequestContextGetter* CefBrowserContext::CreateMediaRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory) { return nullptr; } ChromeZoomLevelPrefs* CefBrowserContext::GetZoomLevelPrefs() { return static_cast( GetStoragePartition(this, NULL)->GetZoomLevelDelegate()); } void CefBrowserContext::OnRenderFrameDeleted(int render_process_id, int render_frame_id, bool is_main_frame, bool is_guest_view) { CEF_REQUIRE_UIT(); if (resource_context_ && is_main_frame) { DCHECK_GE(render_process_id, 0); // Using base::Unretained() is safe because both this callback and possible // deletion of |resource_context_| will execute on the IO thread, and this // callback will be executed first. CEF_POST_TASK(CEF_IOT, base::Bind(&CefResourceContext::ClearPluginLoadDecision, base::Unretained(resource_context_.get()), render_process_id)); } } void CefBrowserContext::OnPurgePluginListCache() { CEF_REQUIRE_UIT(); if (resource_context_) { // Using base::Unretained() is safe because both this callback and possible // deletion of |resource_context_| will execute on the IO thread, and this // callback will be executed first. CEF_POST_TASK(CEF_IOT, base::Bind(&CefResourceContext::ClearPluginLoadDecision, base::Unretained(resource_context_.get()), -1)); } }