summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_process_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/extension_process_manager.cc')
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc853
1 files changed, 0 insertions, 853 deletions
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
deleted file mode 100644
index b11eecf..0000000
--- 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/background_info.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/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);
-}