Index: chrome/browser/extensions/extension_process_manager.cc |
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc |
deleted file mode 100644 |
index 937d09e80461f53394e99f8cf8c027c5e252ef06..0000000000000000000000000000000000000000 |
--- a/chrome/browser/extensions/extension_process_manager.cc |
+++ /dev/null |
@@ -1,853 +0,0 @@ |
-// 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/extensions/extension_process_manager.h" |
- |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/lazy_instance.h" |
-#include "base/logging.h" |
-#include "base/message_loop/message_loop.h" |
-#include "base/metrics/histogram.h" |
-#include "base/stl_util.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/time/time.h" |
-#include "chrome/browser/chrome_notification_types.h" |
-#include "chrome/browser/extensions/api/runtime/runtime_api.h" |
-#include "chrome/browser/extensions/extension_host.h" |
-#include "chrome/browser/extensions/extension_service.h" |
-#include "chrome/browser/extensions/extension_system.h" |
-#include "chrome/browser/extensions/extension_util.h" |
-#include "chrome/common/extensions/extension.h" |
-#include "chrome/common/extensions/extension_messages.h" |
-#include "content/public/browser/browser_context.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/devtools_agent_host.h" |
-#include "content/public/browser/devtools_manager.h" |
-#include "content/public/browser/notification_service.h" |
-#include "content/public/browser/render_process_host.h" |
-#include "content/public/browser/render_view_host.h" |
-#include "content/public/browser/site_instance.h" |
-#include "content/public/browser/web_contents.h" |
-#include "content/public/browser/web_contents_delegate.h" |
-#include "content/public/browser/web_contents_observer.h" |
-#include "content/public/browser/web_contents_user_data.h" |
-#include "content/public/common/renderer_preferences.h" |
-#include "extensions/browser/extensions_browser_client.h" |
-#include "extensions/browser/view_type_utils.h" |
-#include "extensions/common/manifest_handlers/background_info.h" |
-#include "extensions/common/manifest_handlers/incognito_info.h" |
-#include "extensions/common/switches.h" |
- |
-#if defined(OS_MACOSX) |
-#include "chrome/browser/extensions/extension_host_mac.h" |
-#endif |
- |
-using content::BrowserContext; |
-using content::RenderViewHost; |
-using content::SiteInstance; |
-using content::WebContents; |
-using extensions::BackgroundInfo; |
-using extensions::BackgroundManifestHandler; |
-using extensions::Extension; |
-using extensions::ExtensionHost; |
-using extensions::ExtensionsBrowserClient; |
-using extensions::ExtensionSystem; |
- |
-class RenderViewHostDestructionObserver; |
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(RenderViewHostDestructionObserver); |
- |
-namespace { |
- |
-std::string GetExtensionID(RenderViewHost* render_view_host) { |
- // This works for both apps and extensions because the site has been |
- // normalized to the extension URL for apps. |
- if (!render_view_host->GetSiteInstance()) |
- return std::string(); |
- |
- return render_view_host->GetSiteInstance()->GetSiteURL().host(); |
-} |
- |
-void OnRenderViewHostUnregistered(BrowserContext* context, |
- RenderViewHost* render_view_host) { |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, |
- content::Source<BrowserContext>(context), |
- content::Details<RenderViewHost>(render_view_host)); |
-} |
- |
-// Incognito profiles use this process manager. It is mostly a shim that decides |
-// whether to fall back on the original profile's ExtensionProcessManager based |
-// on whether a given extension uses "split" or "spanning" incognito behavior. |
-class IncognitoExtensionProcessManager : public ExtensionProcessManager { |
- public: |
- IncognitoExtensionProcessManager(BrowserContext* incognito_context, |
- BrowserContext* original_context); |
- virtual ~IncognitoExtensionProcessManager(); |
- virtual ExtensionHost* CreateBackgroundHost(const Extension* extension, |
- const GURL& url) OVERRIDE; |
- virtual SiteInstance* GetSiteInstanceForURL(const GURL& url) OVERRIDE; |
- |
- private: |
- // Returns true if the extension is allowed to run in incognito mode. |
- bool IsIncognitoEnabled(const Extension* extension); |
- |
- ExtensionProcessManager* original_manager_; |
- |
- DISALLOW_COPY_AND_ASSIGN(IncognitoExtensionProcessManager); |
-}; |
- |
-static void CreateBackgroundHostForExtensionLoad( |
- ExtensionProcessManager* manager, const Extension* extension) { |
- DVLOG(1) << "CreateBackgroundHostForExtensionLoad"; |
- if (BackgroundInfo::HasPersistentBackgroundPage(extension)) |
- manager->CreateBackgroundHost(extension, |
- BackgroundInfo::GetBackgroundURL(extension)); |
-} |
- |
-} // namespace |
- |
-class RenderViewHostDestructionObserver |
- : public content::WebContentsObserver, |
- public content::WebContentsUserData<RenderViewHostDestructionObserver> { |
- public: |
- virtual ~RenderViewHostDestructionObserver() {} |
- |
- private: |
- explicit RenderViewHostDestructionObserver(WebContents* web_contents) |
- : WebContentsObserver(web_contents) { |
- BrowserContext* context = web_contents->GetBrowserContext(); |
- process_manager_ = |
- ExtensionSystem::GetForBrowserContext(context)->process_manager(); |
- } |
- |
- friend class content::WebContentsUserData<RenderViewHostDestructionObserver>; |
- |
- // content::WebContentsObserver overrides. |
- virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE { |
- process_manager_->UnregisterRenderViewHost(render_view_host); |
- } |
- |
- ExtensionProcessManager* process_manager_; |
- |
- DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver); |
-}; |
- |
-struct ExtensionProcessManager::BackgroundPageData { |
- // The count of things keeping the lazy background page alive. |
- int lazy_keepalive_count; |
- |
- // This is used with the ShouldSuspend message, to ensure that the extension |
- // remained idle between sending the message and receiving the ack. |
- int close_sequence_id; |
- |
- // True if the page responded to the ShouldSuspend message and is currently |
- // dispatching the suspend event. During this time any events that arrive will |
- // cancel the suspend process and an onSuspendCanceled event will be |
- // dispatched to the page. |
- bool is_closing; |
- |
- // Keeps track of when this page was last suspended. Used for perf metrics. |
- linked_ptr<base::ElapsedTimer> since_suspended; |
- |
- BackgroundPageData() |
- : lazy_keepalive_count(0), close_sequence_id(0), is_closing(false) {} |
-}; |
- |
-// |
-// ExtensionProcessManager |
-// |
- |
-// static |
-ExtensionProcessManager* ExtensionProcessManager::Create( |
- BrowserContext* context) { |
- if (context->IsOffTheRecord()) { |
- BrowserContext* original_context = |
- ExtensionsBrowserClient::Get()->GetOriginalContext(context); |
- return new IncognitoExtensionProcessManager(context, original_context); |
- } |
- return new ExtensionProcessManager(context, context); |
-} |
- |
-ExtensionProcessManager::ExtensionProcessManager( |
- BrowserContext* context, |
- BrowserContext* original_context) |
- : site_instance_(SiteInstance::Create(context)), |
- defer_background_host_creation_(false), |
- startup_background_hosts_created_(false), |
- devtools_callback_(base::Bind( |
- &ExtensionProcessManager::OnDevToolsStateChanged, |
- base::Unretained(this))), |
- weak_ptr_factory_(this) { |
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
- content::Source<BrowserContext>(original_context)); |
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
- content::Source<BrowserContext>(original_context)); |
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
- content::Source<BrowserContext>(original_context)); |
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
- content::Source<BrowserContext>(context)); |
- registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
- content::Source<BrowserContext>(context)); |
- registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, |
- content::NotificationService::AllSources()); |
- registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED, |
- content::NotificationService::AllSources()); |
- registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
- content::Source<BrowserContext>(original_context)); |
- registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
- content::Source<BrowserContext>(context)); |
- if (context->IsOffTheRecord()) { |
- registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
- content::Source<BrowserContext>(original_context)); |
- } |
- |
- event_page_idle_time_ = base::TimeDelta::FromSeconds(10); |
- unsigned idle_time_sec = 0; |
- if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
- extensions::switches::kEventPageIdleTime), &idle_time_sec)) { |
- event_page_idle_time_ = base::TimeDelta::FromSeconds(idle_time_sec); |
- } |
- event_page_suspending_time_ = base::TimeDelta::FromSeconds(5); |
- unsigned suspending_time_sec = 0; |
- if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
- extensions::switches::kEventPageSuspendingTime), |
- &suspending_time_sec)) { |
- event_page_suspending_time_ = |
- base::TimeDelta::FromSeconds(suspending_time_sec); |
- } |
- |
- content::DevToolsManager::GetInstance()->AddAgentStateCallback( |
- devtools_callback_); |
-} |
- |
-ExtensionProcessManager::~ExtensionProcessManager() { |
- CloseBackgroundHosts(); |
- DCHECK(background_hosts_.empty()); |
- content::DevToolsManager::GetInstance()->RemoveAgentStateCallback( |
- devtools_callback_); |
-} |
- |
-const ExtensionProcessManager::ViewSet |
-ExtensionProcessManager::GetAllViews() const { |
- ViewSet result; |
- for (ExtensionRenderViews::const_iterator iter = |
- all_extension_views_.begin(); |
- iter != all_extension_views_.end(); ++iter) { |
- result.insert(iter->first); |
- } |
- return result; |
-} |
- |
-ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( |
- const Extension* extension, const GURL& url) { |
- DVLOG(1) << "CreateBackgroundHost " << url.spec(); |
- // Hosted apps are taken care of from BackgroundContentsService. Ignore them |
- // here. |
- if (extension->is_hosted_app()) |
- return NULL; |
- |
- // Don't create multiple background hosts for an extension. |
- if (ExtensionHost* host = GetBackgroundHostForExtension(extension->id())) |
- return host; // TODO(kalman): return NULL here? It might break things... |
- |
- ExtensionHost* host = |
-#if defined(OS_MACOSX) |
- new extensions::ExtensionHostMac( |
- extension, GetSiteInstanceForURL(url), url, |
- extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
-#else |
- new ExtensionHost(extension, GetSiteInstanceForURL(url), url, |
- extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
-#endif |
- |
- host->CreateRenderViewSoon(); |
- OnBackgroundHostCreated(host); |
- return host; |
-} |
- |
-ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( |
- const std::string& extension_id) { |
- for (ExtensionHostSet::iterator iter = background_hosts_.begin(); |
- iter != background_hosts_.end(); ++iter) { |
- ExtensionHost* host = *iter; |
- if (host->extension_id() == extension_id) |
- return host; |
- } |
- return NULL; |
-} |
- |
-std::set<RenderViewHost*> |
- ExtensionProcessManager::GetRenderViewHostsForExtension( |
- const std::string& extension_id) { |
- std::set<RenderViewHost*> result; |
- |
- SiteInstance* site_instance = GetSiteInstanceForURL( |
- Extension::GetBaseURLFromExtensionId(extension_id)); |
- if (!site_instance) |
- return result; |
- |
- // Gather up all the views for that site. |
- for (ExtensionRenderViews::iterator view = all_extension_views_.begin(); |
- view != all_extension_views_.end(); ++view) { |
- if (view->first->GetSiteInstance() == site_instance) |
- result.insert(view->first); |
- } |
- |
- return result; |
-} |
- |
-const Extension* ExtensionProcessManager::GetExtensionForRenderViewHost( |
- RenderViewHost* render_view_host) { |
- if (!render_view_host->GetSiteInstance()) |
- return NULL; |
- |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- if (!service) |
- return NULL; |
- |
- return service->extensions()->GetByID(GetExtensionID(render_view_host)); |
-} |
- |
-void ExtensionProcessManager::UnregisterRenderViewHost( |
- RenderViewHost* render_view_host) { |
- ExtensionRenderViews::iterator view = |
- all_extension_views_.find(render_view_host); |
- if (view == all_extension_views_.end()) |
- return; |
- |
- OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host); |
- extensions::ViewType view_type = view->second; |
- all_extension_views_.erase(view); |
- |
- // Keepalive count, balanced in RegisterRenderViewHost. |
- if (view_type != extensions::VIEW_TYPE_INVALID && |
- view_type != extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
- const Extension* extension = GetExtensionForRenderViewHost( |
- render_view_host); |
- if (extension) |
- DecrementLazyKeepaliveCount(extension); |
- } |
-} |
- |
-void ExtensionProcessManager::RegisterRenderViewHost( |
- RenderViewHost* render_view_host) { |
- const Extension* extension = GetExtensionForRenderViewHost( |
- render_view_host); |
- if (!extension) |
- return; |
- |
- WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host); |
- all_extension_views_[render_view_host] = |
- extensions::GetViewType(web_contents); |
- |
- // Keep the lazy background page alive as long as any non-background-page |
- // extension views are visible. Keepalive count balanced in |
- // UnregisterRenderViewHost. |
- IncrementLazyKeepaliveCountForView(render_view_host); |
-} |
- |
-SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { |
- return site_instance_->GetRelatedSiteInstance(url); |
-} |
- |
-bool ExtensionProcessManager::IsBackgroundHostClosing( |
- const std::string& extension_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- return (host && background_page_data_[extension_id].is_closing); |
-} |
- |
-int ExtensionProcessManager::GetLazyKeepaliveCount(const Extension* extension) { |
- if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
- return 0; |
- |
- return background_page_data_[extension->id()].lazy_keepalive_count; |
-} |
- |
-int ExtensionProcessManager::IncrementLazyKeepaliveCount( |
- const Extension* extension) { |
- if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
- return 0; |
- |
- int& count = background_page_data_[extension->id()].lazy_keepalive_count; |
- if (++count == 1) |
- OnLazyBackgroundPageActive(extension->id()); |
- |
- return count; |
-} |
- |
-int ExtensionProcessManager::DecrementLazyKeepaliveCount( |
- const Extension* extension) { |
- if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
- return 0; |
- |
- int& count = background_page_data_[extension->id()].lazy_keepalive_count; |
- DCHECK_GT(count, 0); |
- |
- // If we reach a zero keepalive count when the lazy background page is about |
- // to be closed, incrementing close_sequence_id will cancel the close |
- // sequence and cause the background page to linger. So check is_closing |
- // before initiating another close sequence. |
- if (--count == 0 && !background_page_data_[extension->id()].is_closing) { |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&ExtensionProcessManager::OnLazyBackgroundPageIdle, |
- weak_ptr_factory_.GetWeakPtr(), extension->id(), |
- ++background_page_data_[extension->id()].close_sequence_id), |
- event_page_idle_time_); |
- } |
- |
- return count; |
-} |
- |
-void ExtensionProcessManager::IncrementLazyKeepaliveCountForView( |
- RenderViewHost* render_view_host) { |
- WebContents* web_contents = |
- WebContents::FromRenderViewHost(render_view_host); |
- extensions::ViewType view_type = extensions::GetViewType(web_contents); |
- if (view_type != extensions::VIEW_TYPE_INVALID && |
- view_type != extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
- const Extension* extension = GetExtensionForRenderViewHost( |
- render_view_host); |
- if (extension) |
- IncrementLazyKeepaliveCount(extension); |
- } |
-} |
- |
-void ExtensionProcessManager::OnLazyBackgroundPageIdle( |
- const std::string& extension_id, int sequence_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- if (host && !background_page_data_[extension_id].is_closing && |
- sequence_id == background_page_data_[extension_id].close_sequence_id) { |
- // Tell the renderer we are about to close. This is a simple ping that the |
- // renderer will respond to. The purpose is to control sequencing: if the |
- // extension remains idle until the renderer responds with an ACK, then we |
- // know that the extension process is ready to shut down. If our |
- // close_sequence_id has already changed, then we would ignore the |
- // ShouldSuspendAck, so we don't send the ping. |
- host->render_view_host()->Send(new ExtensionMsg_ShouldSuspend( |
- extension_id, sequence_id)); |
- } |
-} |
- |
-void ExtensionProcessManager::OnLazyBackgroundPageActive( |
- const std::string& extension_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- if (host && !background_page_data_[extension_id].is_closing) { |
- // Cancel the current close sequence by changing the close_sequence_id, |
- // which causes us to ignore the next ShouldSuspendAck. |
- ++background_page_data_[extension_id].close_sequence_id; |
- } |
-} |
- |
-void ExtensionProcessManager::OnShouldSuspendAck( |
- const std::string& extension_id, int sequence_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- if (host && |
- sequence_id == background_page_data_[extension_id].close_sequence_id) { |
- host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id)); |
- } |
-} |
- |
-void ExtensionProcessManager::OnSuspendAck(const std::string& extension_id) { |
- background_page_data_[extension_id].is_closing = true; |
- int sequence_id = background_page_data_[extension_id].close_sequence_id; |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&ExtensionProcessManager::CloseLazyBackgroundPageNow, |
- weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id), |
- event_page_suspending_time_); |
-} |
- |
-void ExtensionProcessManager::CloseLazyBackgroundPageNow( |
- const std::string& extension_id, int sequence_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- if (host && |
- sequence_id == background_page_data_[extension_id].close_sequence_id) { |
- ExtensionHost* host = GetBackgroundHostForExtension(extension_id); |
- if (host) |
- CloseBackgroundHost(host); |
- } |
-} |
- |
-void ExtensionProcessManager::OnNetworkRequestStarted( |
- RenderViewHost* render_view_host) { |
- ExtensionHost* host = GetBackgroundHostForExtension( |
- GetExtensionID(render_view_host)); |
- if (host && host->render_view_host() == render_view_host) |
- IncrementLazyKeepaliveCount(host->extension()); |
-} |
- |
-void ExtensionProcessManager::OnNetworkRequestDone( |
- RenderViewHost* render_view_host) { |
- ExtensionHost* host = GetBackgroundHostForExtension( |
- GetExtensionID(render_view_host)); |
- if (host && host->render_view_host() == render_view_host) |
- DecrementLazyKeepaliveCount(host->extension()); |
-} |
- |
-void ExtensionProcessManager::CancelSuspend(const Extension* extension) { |
- bool& is_closing = background_page_data_[extension->id()].is_closing; |
- ExtensionHost* host = GetBackgroundHostForExtension(extension->id()); |
- if (host && is_closing) { |
- is_closing = false; |
- host->render_view_host()->Send( |
- new ExtensionMsg_CancelSuspend(extension->id())); |
- // This increment / decrement is to simulate an instantaneous event. This |
- // has the effect of invalidating close_sequence_id, preventing any in |
- // progress closes from completing and starting a new close process if |
- // necessary. |
- IncrementLazyKeepaliveCount(extension); |
- DecrementLazyKeepaliveCount(extension); |
- } |
-} |
- |
-void ExtensionProcessManager::DeferBackgroundHostCreation(bool defer) { |
- bool previous = defer_background_host_creation_; |
- defer_background_host_creation_ = defer; |
- |
- // If we were deferred, and we switch to non-deferred, then create the |
- // background hosts. |
- if (previous && !defer_background_host_creation_) |
- CreateBackgroundHostsForProfileStartup(); |
-} |
- |
-void ExtensionProcessManager::OnBrowserWindowReady() { |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- // On Chrome OS, a login screen is implemented as a browser. |
- // This browser has no extension service. In this case, |
- // service will be NULL. |
- if (!service || !service->is_ready()) |
- return; |
- |
- CreateBackgroundHostsForProfileStartup(); |
-} |
- |
-content::BrowserContext* ExtensionProcessManager::GetBrowserContext() const { |
- return site_instance_->GetBrowserContext(); |
-} |
- |
-void ExtensionProcessManager::Observe( |
- int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- switch (type) { |
- case chrome::NOTIFICATION_EXTENSIONS_READY: |
- case chrome::NOTIFICATION_PROFILE_CREATED: { |
- CreateBackgroundHostsForProfileStartup(); |
- break; |
- } |
- |
- case chrome::NOTIFICATION_EXTENSION_LOADED: { |
- BrowserContext* context = content::Source<BrowserContext>(source).ptr(); |
- ExtensionService* service = |
- ExtensionSystem::GetForBrowserContext(context)->extension_service(); |
- if (service->is_ready()) { |
- const Extension* extension = |
- content::Details<const Extension>(details).ptr(); |
- CreateBackgroundHostForExtensionLoad(this, extension); |
- } |
- break; |
- } |
- |
- case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
- const Extension* extension = |
- content::Details<extensions::UnloadedExtensionInfo>( |
- details)->extension; |
- for (ExtensionHostSet::iterator iter = background_hosts_.begin(); |
- iter != background_hosts_.end(); ++iter) { |
- ExtensionHost* host = *iter; |
- if (host->extension_id() == extension->id()) { |
- CloseBackgroundHost(host); |
- break; |
- } |
- } |
- UnregisterExtension(extension->id()); |
- break; |
- } |
- |
- case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { |
- ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); |
- if (background_hosts_.erase(host)) { |
- ClearBackgroundPageData(host->extension()->id()); |
- background_page_data_[host->extension()->id()].since_suspended.reset( |
- new base::ElapsedTimer()); |
- } |
- break; |
- } |
- |
- case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: { |
- ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); |
- if (host->extension_host_type() == |
- extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
- CloseBackgroundHost(host); |
- } |
- break; |
- } |
- |
- case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: { |
- // We get this notification both for new WebContents and when one |
- // has its RenderViewHost replaced (e.g. when a user does a cross-site |
- // navigation away from an extension URL). For the replaced case, we must |
- // unregister the old RVH so it doesn't count as an active view that would |
- // keep the event page alive. |
- WebContents* contents = content::Source<WebContents>(source).ptr(); |
- if (contents->GetBrowserContext() != GetBrowserContext()) |
- break; |
- |
- typedef std::pair<RenderViewHost*, RenderViewHost*> RVHPair; |
- RVHPair* switched_details = content::Details<RVHPair>(details).ptr(); |
- if (switched_details->first) |
- UnregisterRenderViewHost(switched_details->first); |
- |
- // The above will unregister a RVH when it gets swapped out with a new |
- // one. However we need to watch the WebContents to know when a RVH is |
- // deleted because the WebContents has gone away. |
- RenderViewHostDestructionObserver::CreateForWebContents(contents); |
- RegisterRenderViewHost(switched_details->second); |
- break; |
- } |
- |
- case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: { |
- WebContents* contents = content::Source<WebContents>(source).ptr(); |
- if (contents->GetBrowserContext() != GetBrowserContext()) |
- break; |
- const Extension* extension = GetExtensionForRenderViewHost( |
- contents->GetRenderViewHost()); |
- if (!extension) |
- return; |
- |
- // RegisterRenderViewHost is called too early (before the process is |
- // available), so we need to wait until now to notify. |
- content::NotificationService::current()->Notify( |
- chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, |
- content::Source<BrowserContext>(GetBrowserContext()), |
- content::Details<RenderViewHost>(contents->GetRenderViewHost())); |
- break; |
- } |
- |
- case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
- // Close background hosts when the last browser is closed so that they |
- // have time to shutdown various objects on different threads. Our |
- // destructor is called too late in the shutdown sequence. |
- CloseBackgroundHosts(); |
- break; |
- } |
- |
- default: |
- NOTREACHED(); |
- } |
-} |
- |
-void ExtensionProcessManager::OnDevToolsStateChanged( |
- content::DevToolsAgentHost* agent_host, bool attached) { |
- RenderViewHost* rvh = agent_host->GetRenderViewHost(); |
- // Ignore unrelated notifications. |
- if (!rvh || |
- rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != |
- GetBrowserContext()) |
- return; |
- if (extensions::GetViewType(WebContents::FromRenderViewHost(rvh)) != |
- extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) |
- return; |
- const Extension* extension = GetExtensionForRenderViewHost(rvh); |
- if (!extension) |
- return; |
- if (attached) { |
- // Keep the lazy background page alive while it's being inspected. |
- CancelSuspend(extension); |
- IncrementLazyKeepaliveCount(extension); |
- } else { |
- DecrementLazyKeepaliveCount(extension); |
- } |
-} |
- |
-void ExtensionProcessManager::CreateBackgroundHostsForProfileStartup() { |
- if (startup_background_hosts_created_) |
- return; |
- |
- // Don't load background hosts now if the loading should be deferred. |
- // Instead they will be loaded when a browser window for this profile |
- // (or an incognito profile from this profile) is ready, or when |
- // DeferBackgroundHostCreation is called with false. |
- if (DeferLoadingBackgroundHosts()) |
- return; |
- |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- DCHECK(service); |
- for (ExtensionSet::const_iterator extension = service->extensions()->begin(); |
- extension != service->extensions()->end(); ++extension) { |
- CreateBackgroundHostForExtensionLoad(this, extension->get()); |
- |
- extensions::RuntimeEventRouter::DispatchOnStartupEvent( |
- GetBrowserContext(), (*extension)->id()); |
- } |
- startup_background_hosts_created_ = true; |
- |
- // Background pages should only be loaded once. To prevent any further loads |
- // occurring, we remove the notification listeners. |
- BrowserContext* original_context = |
- ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext()); |
- if (registrar_.IsRegistered( |
- this, |
- chrome::NOTIFICATION_PROFILE_CREATED, |
- content::Source<BrowserContext>(original_context))) { |
- registrar_.Remove(this, |
- chrome::NOTIFICATION_PROFILE_CREATED, |
- content::Source<BrowserContext>(original_context)); |
- } |
- if (registrar_.IsRegistered( |
- this, |
- chrome::NOTIFICATION_EXTENSIONS_READY, |
- content::Source<BrowserContext>(original_context))) { |
- registrar_.Remove(this, |
- chrome::NOTIFICATION_EXTENSIONS_READY, |
- content::Source<BrowserContext>(original_context)); |
- } |
-} |
- |
-void ExtensionProcessManager::OnBackgroundHostCreated(ExtensionHost* host) { |
- DCHECK_EQ(GetBrowserContext(), host->browser_context()); |
- background_hosts_.insert(host); |
- |
- if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) { |
- linked_ptr<base::ElapsedTimer> since_suspended( |
- background_page_data_[host->extension()->id()]. |
- since_suspended.release()); |
- if (since_suspended.get()) { |
- UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime", |
- since_suspended->Elapsed()); |
- } |
- } |
-} |
- |
-void ExtensionProcessManager::CloseBackgroundHost(ExtensionHost* host) { |
- CHECK(host->extension_host_type() == |
- extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
- delete host; |
- // |host| should deregister itself from our structures. |
- CHECK(background_hosts_.find(host) == background_hosts_.end()); |
-} |
- |
-void ExtensionProcessManager::CloseBackgroundHosts() { |
- for (ExtensionHostSet::iterator iter = background_hosts_.begin(); |
- iter != background_hosts_.end(); ) { |
- ExtensionHostSet::iterator current = iter++; |
- delete *current; |
- } |
-} |
- |
-void ExtensionProcessManager::UnregisterExtension( |
- const std::string& extension_id) { |
- // The lazy_keepalive_count may be greater than zero at this point because |
- // RenderViewHosts are still alive. During extension reloading, they will |
- // decrement the lazy_keepalive_count to negative for the new extension |
- // instance when they are destroyed. Since we are erasing the background page |
- // data for the unloaded extension, unregister the RenderViewHosts too. |
- BrowserContext* context = GetBrowserContext(); |
- for (ExtensionRenderViews::iterator it = all_extension_views_.begin(); |
- it != all_extension_views_.end(); ) { |
- if (GetExtensionID(it->first) == extension_id) { |
- OnRenderViewHostUnregistered(context, it->first); |
- all_extension_views_.erase(it++); |
- } else { |
- ++it; |
- } |
- } |
- |
- background_page_data_.erase(extension_id); |
-} |
- |
-void ExtensionProcessManager::ClearBackgroundPageData( |
- const std::string& extension_id) { |
- background_page_data_.erase(extension_id); |
- |
- // Re-register all RenderViews for this extension. We do this to restore |
- // the lazy_keepalive_count (if any) to properly reflect the number of open |
- // views. |
- for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin(); |
- it != all_extension_views_.end(); ++it) { |
- if (GetExtensionID(it->first) == extension_id) |
- IncrementLazyKeepaliveCountForView(it->first); |
- } |
-} |
- |
-bool ExtensionProcessManager::DeferLoadingBackgroundHosts() const { |
- // Don't load background hosts now if the loading should be deferred. |
- if (defer_background_host_creation_) |
- return true; |
- |
- // The extensions embedder may have special rules about background hosts. |
- return ExtensionsBrowserClient::Get()->DeferLoadingBackgroundHosts( |
- GetBrowserContext()); |
-} |
- |
-// |
-// IncognitoExtensionProcessManager |
-// |
- |
-IncognitoExtensionProcessManager::IncognitoExtensionProcessManager( |
- BrowserContext* incognito_context, |
- BrowserContext* original_context) |
- : ExtensionProcessManager(incognito_context, original_context), |
- original_manager_(extensions::ExtensionSystem::GetForBrowserContext( |
- original_context)->process_manager()) { |
- DCHECK(incognito_context->IsOffTheRecord()); |
- |
- // The original profile will have its own ExtensionProcessManager to |
- // load the background pages of the spanning extensions. This process |
- // manager need only worry about the split mode extensions, which is handled |
- // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler. |
- registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
- content::Source<BrowserContext>(original_context)); |
- registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED, |
- content::Source<BrowserContext>(original_context)); |
-} |
- |
-IncognitoExtensionProcessManager::~IncognitoExtensionProcessManager() { |
- // TODO(yoz): This cleanup code belongs in the MenuManager. |
- // Remove "incognito" "split" mode context menu items. |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- if (service) |
- service->menu_manager()->RemoveAllIncognitoContextItems(); |
-} |
- |
-ExtensionHost* IncognitoExtensionProcessManager::CreateBackgroundHost( |
- const Extension* extension, const GURL& url) { |
- if (extensions::IncognitoInfo::IsSplitMode(extension)) { |
- if (IsIncognitoEnabled(extension)) |
- return ExtensionProcessManager::CreateBackgroundHost(extension, url); |
- } else { |
- // Do nothing. If an extension is spanning, then its original-profile |
- // background page is shared with incognito, so we don't create another. |
- } |
- return NULL; |
-} |
- |
-SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL( |
- const GURL& url) { |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- if (service) { |
- const Extension* extension = |
- service->extensions()->GetExtensionOrAppByURL(url); |
- if (extension && |
- !extensions::IncognitoInfo::IsSplitMode(extension)) { |
- return original_manager_->GetSiteInstanceForURL(url); |
- } |
- } |
- return ExtensionProcessManager::GetSiteInstanceForURL(url); |
-} |
- |
-bool IncognitoExtensionProcessManager::IsIncognitoEnabled( |
- const Extension* extension) { |
- // Keep in sync with duplicate in extension_info_map.cc. |
- ExtensionService* service = ExtensionSystem::GetForBrowserContext( |
- GetBrowserContext())->extension_service(); |
- return extension_util::IsIncognitoEnabled(extension->id(), service); |
-} |