summaryrefslogtreecommitdiffstats
path: root/extensions/browser
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 19:15:21 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 19:15:21 +0000
commit423f1fb38b61b9ecb94f7e64fc20e2a9969aaf95 (patch)
tree8ca74e89e9a59dada913d42ceeea17cdd8b0370d /extensions/browser
parent24ad156eab71b598312f9935e8e2e4a494567119 (diff)
downloadchromium_src-423f1fb38b61b9ecb94f7e64fc20e2a9969aaf95.zip
chromium_src-423f1fb38b61b9ecb94f7e64fc20e2a9969aaf95.tar.gz
chromium_src-423f1fb38b61b9ecb94f7e64fc20e2a9969aaf95.tar.bz2
Move ExtensionProcessManager to src/extensions, part 4
* Move c/b/extensions/extension_process_manager.h to extensions/browser/process_manager.h * Rename ExtensionsProcessManager to ProcessManager * Place it in the "extensions" namespace BUG=313481 TEST=browser_tests, unit_tests R=miket@chromium.org TBR=sky@chromium.org for mechanical header file move affecting chrome/browser/ Review URL: https://codereview.chromium.org/62713003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@233956 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions/browser')
-rw-r--r--extensions/browser/DEPS4
-rw-r--r--extensions/browser/lazy_background_task_queue.cc6
-rw-r--r--extensions/browser/lazy_background_task_queue_unittest.cc30
-rw-r--r--extensions/browser/process_manager.cc836
-rw-r--r--extensions/browser/process_manager.h221
5 files changed, 1077 insertions, 20 deletions
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index 0f912bf..497895d 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -8,10 +8,12 @@ include_rules = [
#
# TODO(jamescook): Remove these. http://crbug.com/162530
"+chrome/browser/chrome_notification_types.h",
+ "+chrome/browser/extensions/api/runtime/runtime_api.h",
"+chrome/browser/extensions/extension_host.h",
- "+chrome/browser/extensions/extension_process_manager.h",
+ "+chrome/browser/extensions/extension_host_mac.h",
"+chrome/browser/extensions/extension_service.h",
"+chrome/browser/extensions/extension_system.h",
+ "+chrome/browser/extensions/extension_util.h",
"+chrome/browser/extensions/process_map.h",
"+chrome/common/extensions/background_info.h",
"+chrome/common/extensions/extension.h",
diff --git a/extensions/browser/lazy_background_task_queue.cc b/extensions/browser/lazy_background_task_queue.cc
index 584d897..77a219b 100644
--- a/extensions/browser/lazy_background_task_queue.cc
+++ b/extensions/browser/lazy_background_task_queue.cc
@@ -7,7 +7,6 @@
#include "base/callback.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/process_map.h"
@@ -21,6 +20,7 @@
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/process_manager.h"
#include "extensions/common/view_type.h"
namespace extensions {
@@ -44,7 +44,7 @@ bool LazyBackgroundTaskQueue::ShouldEnqueueTask(
const Extension* extension) {
DCHECK(extension);
if (BackgroundInfo::HasBackgroundPage(extension)) {
- ExtensionProcessManager* pm = ExtensionSystem::GetForBrowserContext(
+ ProcessManager* pm = ExtensionSystem::GetForBrowserContext(
browser_context)->process_manager();
DCHECK(pm);
ExtensionHost* background_host =
@@ -81,7 +81,7 @@ void LazyBackgroundTaskQueue::AddPendingTask(
if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) {
// If this is the first enqueued task, and we're not waiting for the
// background page to unload, ensure the background page is loaded.
- ExtensionProcessManager* pm = ExtensionSystem::GetForBrowserContext(
+ ProcessManager* pm = ExtensionSystem::GetForBrowserContext(
browser_context)->process_manager();
pm->IncrementLazyKeepaliveCount(extension);
// Creating the background host may fail, e.g. if |profile| is incognito
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc
index e355cac..863a520 100644
--- a/extensions/browser/lazy_background_task_queue_unittest.cc
+++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -6,31 +6,30 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service_unittest.h"
#include "chrome/browser/extensions/test_extension_system.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/process_manager.h"
#include "extensions/common/extension_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
-// An ExtensionProcessManager that doesn't create background host pages.
-class TestExtensionProcessManager : public ExtensionProcessManager {
+// A ProcessManager that doesn't create background host pages.
+class TestProcessManager : public ProcessManager {
public:
- explicit TestExtensionProcessManager(Profile* profile)
- : ExtensionProcessManager(profile, profile->GetOriginalProfile()),
+ explicit TestProcessManager(Profile* profile)
+ : ProcessManager(profile, profile->GetOriginalProfile()),
create_count_(0) {}
- virtual ~TestExtensionProcessManager() {}
+ virtual ~TestProcessManager() {}
int create_count() { return create_count_; }
- // ExtensionProcessManager overrides:
- virtual extensions::ExtensionHost* CreateBackgroundHost(
- const extensions::Extension* extension,
- const GURL& url) OVERRIDE {
+ // ProcessManager overrides:
+ virtual ExtensionHost* CreateBackgroundHost(const Extension* extension,
+ const GURL& url) OVERRIDE {
// Don't actually try to create a web contents.
create_count_++;
return NULL;
@@ -39,7 +38,7 @@ class TestExtensionProcessManager : public ExtensionProcessManager {
private:
int create_count_;
- DISALLOW_COPY_AND_ASSIGN(TestExtensionProcessManager);
+ DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
};
// Derives from ExtensionServiceTestBase because ExtensionService is difficult
@@ -96,7 +95,7 @@ class LazyBackgroundTaskQueueTest : public ExtensionServiceTestBase {
// Tests that only extensions with background pages should have tasks queued.
TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) {
InitializeEmptyExtensionService();
- InitializeExtensionProcessManager();
+ InitializeProcessManager();
LazyBackgroundTaskQueue queue(profile_.get());
@@ -114,14 +113,13 @@ TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) {
TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) {
InitializeEmptyExtensionService();
- // Swap in our stub TestExtensionProcessManager.
+ // Swap in our stub TestProcessManager.
TestExtensionSystem* extension_system =
static_cast<extensions::TestExtensionSystem*>(
ExtensionSystem::Get(profile_.get()));
// Owned by |extension_system|.
- TestExtensionProcessManager* process_manager =
- new TestExtensionProcessManager(profile_.get());
- extension_system->SetExtensionProcessManager(process_manager);
+ TestProcessManager* process_manager = new TestProcessManager(profile_.get());
+ extension_system->SetProcessManager(process_manager);
LazyBackgroundTaskQueue queue(profile_.get());
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
new file mode 100644
index 0000000..f5134d1
--- /dev/null
+++ b/extensions/browser/process_manager.cc
@@ -0,0 +1,836 @@
+// 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 "extensions/browser/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;
+
+namespace extensions {
+class RenderViewHostDestructionObserver;
+}
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(
+ extensions::RenderViewHostDestructionObserver);
+
+namespace extensions {
+
+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 ProcessManager based
+// on whether a given extension uses "split" or "spanning" incognito behavior.
+class IncognitoProcessManager : public ProcessManager {
+ public:
+ IncognitoProcessManager(BrowserContext* incognito_context,
+ BrowserContext* original_context);
+ virtual ~IncognitoProcessManager();
+ 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);
+
+ ProcessManager* original_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
+};
+
+static void CreateBackgroundHostForExtensionLoad(
+ ProcessManager* 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);
+ }
+
+ ProcessManager* process_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
+};
+
+struct ProcessManager::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) {}
+};
+
+//
+// ProcessManager
+//
+
+// static
+ProcessManager* ProcessManager::Create(BrowserContext* context) {
+ if (context->IsOffTheRecord()) {
+ BrowserContext* original_context =
+ ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+ return new IncognitoProcessManager(context, original_context);
+ }
+ return new ProcessManager(context, context);
+}
+
+ProcessManager::ProcessManager(BrowserContext* context,
+ BrowserContext* original_context)
+ : site_instance_(SiteInstance::Create(context)),
+ defer_background_host_creation_(false),
+ startup_background_hosts_created_(false),
+ devtools_callback_(base::Bind(
+ &ProcessManager::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_);
+}
+
+ProcessManager::~ProcessManager() {
+ CloseBackgroundHosts();
+ DCHECK(background_hosts_.empty());
+ content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
+ devtools_callback_);
+}
+
+const ProcessManager::ViewSet ProcessManager::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* ProcessManager::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 ExtensionHostMac(
+ extension, GetSiteInstanceForURL(url), url,
+ VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+#else
+ new ExtensionHost(extension, GetSiteInstanceForURL(url), url,
+ VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+#endif
+
+ host->CreateRenderViewSoon();
+ OnBackgroundHostCreated(host);
+ return host;
+}
+
+ExtensionHost* ProcessManager::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*> ProcessManager::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* ProcessManager::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 ProcessManager::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);
+ ViewType view_type = view->second;
+ all_extension_views_.erase(view);
+
+ // Keepalive count, balanced in RegisterRenderViewHost.
+ if (view_type != VIEW_TYPE_INVALID &&
+ view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
+ const Extension* extension = GetExtensionForRenderViewHost(
+ render_view_host);
+ if (extension)
+ DecrementLazyKeepaliveCount(extension);
+ }
+}
+
+void ProcessManager::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] = 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* ProcessManager::GetSiteInstanceForURL(const GURL& url) {
+ return site_instance_->GetRelatedSiteInstance(url);
+}
+
+bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) {
+ ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
+ return (host && background_page_data_[extension_id].is_closing);
+}
+
+int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
+ if (!BackgroundInfo::HasLazyBackgroundPage(extension))
+ return 0;
+
+ return background_page_data_[extension->id()].lazy_keepalive_count;
+}
+
+int ProcessManager::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 ProcessManager::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(&ProcessManager::OnLazyBackgroundPageIdle,
+ weak_ptr_factory_.GetWeakPtr(), extension->id(),
+ ++background_page_data_[extension->id()].close_sequence_id),
+ event_page_idle_time_);
+ }
+
+ return count;
+}
+
+void ProcessManager::IncrementLazyKeepaliveCountForView(
+ RenderViewHost* render_view_host) {
+ WebContents* web_contents =
+ WebContents::FromRenderViewHost(render_view_host);
+ ViewType view_type = GetViewType(web_contents);
+ if (view_type != VIEW_TYPE_INVALID &&
+ view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
+ const Extension* extension = GetExtensionForRenderViewHost(
+ render_view_host);
+ if (extension)
+ IncrementLazyKeepaliveCount(extension);
+ }
+}
+
+void ProcessManager::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 ProcessManager::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 ProcessManager::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 ProcessManager::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(&ProcessManager::CloseLazyBackgroundPageNow,
+ weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id),
+ event_page_suspending_time_);
+}
+
+void ProcessManager::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 ProcessManager::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 ProcessManager::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 ProcessManager::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 ProcessManager::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 ProcessManager::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* ProcessManager::GetBrowserContext() const {
+ return site_instance_->GetBrowserContext();
+}
+
+void ProcessManager::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<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() == 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 ProcessManager::OnDevToolsStateChanged(
+ content::DevToolsAgentHost* agent_host,
+ bool attached) {
+ RenderViewHost* rvh = agent_host->GetRenderViewHost();
+ // Ignore unrelated notifications.
+ if (!rvh ||
+ rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() !=
+ GetBrowserContext())
+ return;
+ if (GetViewType(WebContents::FromRenderViewHost(rvh)) !=
+ 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 ProcessManager::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());
+
+ 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 ProcessManager::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 ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
+ CHECK(host->extension_host_type() ==
+ VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
+ delete host;
+ // |host| should deregister itself from our structures.
+ CHECK(background_hosts_.find(host) == background_hosts_.end());
+}
+
+void ProcessManager::CloseBackgroundHosts() {
+ for (ExtensionHostSet::iterator iter = background_hosts_.begin();
+ iter != background_hosts_.end(); ) {
+ ExtensionHostSet::iterator current = iter++;
+ delete *current;
+ }
+}
+
+void ProcessManager::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 ProcessManager::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 ProcessManager::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());
+}
+
+//
+// IncognitoProcessManager
+//
+
+IncognitoProcessManager::IncognitoProcessManager(
+ BrowserContext* incognito_context,
+ BrowserContext* original_context)
+ : ProcessManager(incognito_context, original_context),
+ original_manager_(ExtensionSystem::GetForBrowserContext(
+ original_context)->process_manager()) {
+ DCHECK(incognito_context->IsOffTheRecord());
+
+ // The original profile will have its own ProcessManager 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));
+}
+
+IncognitoProcessManager::~IncognitoProcessManager() {
+ // 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* IncognitoProcessManager::CreateBackgroundHost(
+ const Extension* extension, const GURL& url) {
+ if (IncognitoInfo::IsSplitMode(extension)) {
+ if (IsIncognitoEnabled(extension))
+ return ProcessManager::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* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
+ if (service) {
+ const Extension* extension =
+ service->extensions()->GetExtensionOrAppByURL(url);
+ if (extension && !IncognitoInfo::IsSplitMode(extension)) {
+ return original_manager_->GetSiteInstanceForURL(url);
+ }
+ }
+ return ProcessManager::GetSiteInstanceForURL(url);
+}
+
+bool IncognitoProcessManager::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);
+}
+
+} // namespace extensions
diff --git a/extensions/browser/process_manager.h b/extensions/browser/process_manager.h
new file mode 100644
index 0000000..be47f0d
--- /dev/null
+++ b/extensions/browser/process_manager.h
@@ -0,0 +1,221 @@
+// 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.
+
+#ifndef EXTENSIONS_BROWSER_PROCESS_MANAGER_H_
+#define EXTENSIONS_BROWSER_PROCESS_MANAGER_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "extensions/common/view_type.h"
+
+class GURL;
+
+namespace content {
+class BrowserContext;
+class DevToolsAgentHost;
+class RenderViewHost;
+class SiteInstance;
+};
+
+namespace extensions {
+
+class Extension;
+class ExtensionHost;
+
+// Manages dynamic state of running Chromium extensions. There is one instance
+// of this class per Profile. OTR Profiles have a separate instance that keeps
+// track of split-mode extensions only.
+class ProcessManager : public content::NotificationObserver {
+ public:
+ typedef std::set<extensions::ExtensionHost*> ExtensionHostSet;
+ typedef ExtensionHostSet::const_iterator const_iterator;
+
+ static ProcessManager* Create(content::BrowserContext* context);
+ virtual ~ProcessManager();
+
+ const ExtensionHostSet& background_hosts() const {
+ return background_hosts_;
+ }
+
+ typedef std::set<content::RenderViewHost*> ViewSet;
+ const ViewSet GetAllViews() const;
+
+ // Creates a new UI-less extension instance. Like CreateViewHost, but not
+ // displayed anywhere.
+ virtual ExtensionHost* CreateBackgroundHost(const Extension* extension,
+ const GURL& url);
+
+ // Gets the ExtensionHost for the background page for an extension, or NULL if
+ // the extension isn't running or doesn't have a background page.
+ ExtensionHost* GetBackgroundHostForExtension(const std::string& extension_id);
+
+ // Returns the SiteInstance that the given URL belongs to.
+ // TODO(aa): This only returns correct results for extensions and packaged
+ // apps, not hosted apps.
+ virtual content::SiteInstance* GetSiteInstanceForURL(const GURL& url);
+
+ // Unregisters a RenderViewHost as hosting any extension.
+ void UnregisterRenderViewHost(content::RenderViewHost* render_view_host);
+
+ // Returns all RenderViewHosts that are registered for the specified
+ // extension.
+ std::set<content::RenderViewHost*> GetRenderViewHostsForExtension(
+ const std::string& extension_id);
+
+ // Returns the extension associated with the specified RenderViewHost, or
+ // NULL.
+ const Extension* GetExtensionForRenderViewHost(
+ content::RenderViewHost* render_view_host);
+
+ // Returns true if the (lazy) background host for the given extension has
+ // already been sent the unload event and is shutting down.
+ bool IsBackgroundHostClosing(const std::string& extension_id);
+
+ // Getter and setter for the lazy background page's keepalive count. This is
+ // the count of how many outstanding "things" are keeping the page alive.
+ // When this reaches 0, we will begin the process of shutting down the page.
+ // "Things" include pending events, resource loads, and API calls.
+ int GetLazyKeepaliveCount(const Extension* extension);
+ int IncrementLazyKeepaliveCount(const Extension* extension);
+ int DecrementLazyKeepaliveCount(const Extension* extension);
+
+ void IncrementLazyKeepaliveCountForView(
+ content::RenderViewHost* render_view_host);
+
+ // Handles a response to the ShouldSuspend message, used for lazy background
+ // pages.
+ void OnShouldSuspendAck(const std::string& extension_id, int sequence_id);
+
+ // Same as above, for the Suspend message.
+ void OnSuspendAck(const std::string& extension_id);
+
+ // Tracks network requests for a given RenderViewHost, used to know
+ // when network activity is idle for lazy background pages.
+ void OnNetworkRequestStarted(content::RenderViewHost* render_view_host);
+ void OnNetworkRequestDone(content::RenderViewHost* render_view_host);
+
+ // Prevents |extension|'s background page from being closed and sends the
+ // onSuspendCanceled() event to it.
+ void CancelSuspend(const Extension* extension);
+
+ // If |defer| is true background host creation is to be deferred until this is
+ // called again with |defer| set to false, at which point all deferred
+ // background hosts will be created. Defaults to false.
+ void DeferBackgroundHostCreation(bool defer);
+
+ // Ensures background hosts are loaded for a new browser window.
+ void OnBrowserWindowReady();
+
+ // Gets the BrowserContext associated with site_instance_ and all other
+ // related SiteInstances.
+ content::BrowserContext* GetBrowserContext() const;
+
+ protected:
+ // If |context| is incognito pass the master context as |original_context|.
+ // Otherwise pass the same context for both.
+ ProcessManager(content::BrowserContext* context,
+ content::BrowserContext* original_context);
+
+ // Called on browser shutdown to close our extension hosts.
+ void CloseBackgroundHosts();
+
+ // content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // Load all background pages once the profile data is ready and the pages
+ // should be loaded.
+ void CreateBackgroundHostsForProfileStartup();
+
+ content::NotificationRegistrar registrar_;
+
+ // The set of ExtensionHosts running viewless background extensions.
+ ExtensionHostSet background_hosts_;
+
+ // A SiteInstance related to the SiteInstance for all extensions in
+ // this profile. We create it in such a way that a new
+ // browsing instance is created. This controls process grouping.
+ scoped_refptr<content::SiteInstance> site_instance_;
+
+ private:
+ friend class ProcessManagerTest;
+
+ // Extra information we keep for each extension's background page.
+ struct BackgroundPageData;
+ typedef std::string ExtensionId;
+ typedef std::map<ExtensionId, BackgroundPageData> BackgroundPageDataMap;
+ typedef std::map<content::RenderViewHost*,
+ extensions::ViewType> ExtensionRenderViews;
+
+ // Called just after |host| is created so it can be registered in our lists.
+ void OnBackgroundHostCreated(ExtensionHost* host);
+
+ // Close the given |host| iff it's a background page.
+ void CloseBackgroundHost(ExtensionHost* host);
+
+ // These are called when the extension transitions between idle and active.
+ // They control the process of closing the background page when idle.
+ void OnLazyBackgroundPageIdle(const std::string& extension_id,
+ int sequence_id);
+ void OnLazyBackgroundPageActive(const std::string& extension_id);
+ void CloseLazyBackgroundPageNow(const std::string& extension_id,
+ int sequence_id);
+
+ // Potentially registers a RenderViewHost, if it is associated with an
+ // extension. Does nothing if this is not an extension renderer.
+ void RegisterRenderViewHost(content::RenderViewHost* render_view_host);
+
+ // Unregister RenderViewHosts and clear background page data for an extension
+ // which has been unloaded.
+ void UnregisterExtension(const std::string& extension_id);
+
+ // Clears background page data for this extension.
+ void ClearBackgroundPageData(const std::string& extension_id);
+
+ // Returns true if loading background pages should be deferred.
+ bool DeferLoadingBackgroundHosts() const;
+
+ void OnDevToolsStateChanged(content::DevToolsAgentHost*, bool attached);
+
+ // Contains all active extension-related RenderViewHost instances for all
+ // extensions. We also keep a cache of the host's view type, because that
+ // information is not accessible at registration/deregistration time.
+ ExtensionRenderViews all_extension_views_;
+
+ BackgroundPageDataMap background_page_data_;
+
+ // The time to delay between an extension becoming idle and
+ // sending a ShouldSuspend message; read from command-line switch.
+ base::TimeDelta event_page_idle_time_;
+
+ // The time to delay between sending a ShouldSuspend message and
+ // sending a Suspend message; read from command-line switch.
+ base::TimeDelta event_page_suspending_time_;
+
+ // If true, then creation of background hosts is suspended.
+ bool defer_background_host_creation_;
+
+ // True if we have created the startup set of background hosts.
+ bool startup_background_hosts_created_;
+
+ base::Callback<void(content::DevToolsAgentHost*, bool)> devtools_callback_;
+
+ base::WeakPtrFactory<ProcessManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessManager);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_PROCESS_MANAGER_H_