| 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);
|
| -}
|
|
|