Change the way lazy background pages shutdown.
The browser process now keeps a generic count of activity from the lazy background page. This will be used for all types of activity, such as outstanding events, resource requests, and API calls.
BUG=81752
TEST=no
Review URL: https://chromiumcodereview.appspot.com/9447042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123821 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index 4c4b8f69..c92521e 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -259,11 +259,9 @@
if (extension->has_background_page() &&
!extension->background_page_persists()) {
ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
-
- // TODO(mpcomplete): this is incorrect. We need to check whether the page
- // has finished loading. If not, we can't dispatch the event (because the
- // listener hasn't been set up yet).
- if (!pm->GetBackgroundHostForExtension(extension->id()))
+ ExtensionHost* background_host =
+ pm->GetBackgroundHostForExtension(extension->id());
+ if (!background_host || !background_host->did_stop_loading())
return false;
}
@@ -369,18 +367,20 @@
}
void ExtensionEventRouter::IncrementInFlightEvents(const Extension* extension) {
- if (!extension->background_page_persists())
- in_flight_events_[extension->id()]++;
+ if (!extension->background_page_persists()) {
+ profile_->GetExtensionProcessManager()->IncrementLazyKeepaliveCount(
+ extension);
+ }
}
void ExtensionEventRouter::OnExtensionEventAck(
const std::string& extension_id) {
- CHECK(in_flight_events_[extension_id] > 0);
- in_flight_events_[extension_id]--;
-}
-
-bool ExtensionEventRouter::HasInFlightEvents(const std::string& extension_id) {
- return in_flight_events_[extension_id] > 0;
+ const Extension* extension =
+ profile_->GetExtensionService()->extensions()->GetByID(extension_id);
+ if (extension && !extension->background_page_persists()) {
+ profile_->GetExtensionProcessManager()->DecrementLazyKeepaliveCount(
+ extension);
+ }
}
void ExtensionEventRouter::AppendEvent(
@@ -403,8 +403,18 @@
CHECK(!extension_id.empty());
PendingEventsPerExtMap::const_iterator map_it =
pending_events_.find(extension_id);
- if (map_it == pending_events_.end())
+ if (map_it == pending_events_.end()) {
+ NOTREACHED(); // lazy page should not load without any pending events
return;
+ }
+
+ // Temporarily increment the keepalive count while dispatching the events.
+ // This also ensures that if no events were dispatched, the extension returns
+ // to "idle" and is shut down.
+ const Extension* extension =
+ profile_->GetExtensionService()->extensions()->GetByID(extension_id);
+ ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
+ pm->IncrementLazyKeepaliveCount(extension);
PendingEventsList* events_list = map_it->second.get();
for (PendingEventsList::const_iterator it = events_list->begin();
@@ -414,9 +424,7 @@
events_list->clear();
pending_events_.erase(extension_id);
- // Check if the extension is idle, which may be the case if no events were
- // successfully dispatched.
- profile_->GetExtensionProcessManager()->OnExtensionIdle(extension_id);
+ pm->DecrementLazyKeepaliveCount(extension);
}
void ExtensionEventRouter::Observe(
@@ -452,6 +460,7 @@
if (eh->extension_host_type() ==
chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
!eh->extension()->background_page_persists()) {
+ CHECK(eh->did_stop_loading());
DispatchPendingEvents(eh->extension_id());
}
break;
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index daef554..80e6df0 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -103,10 +103,6 @@
// Record the Event Ack from the renderer. (One less event in-flight.)
void OnExtensionEventAck(const std::string& extension_id);
- // Check if there are any Extension Events that have not yet been acked by
- // the renderer.
- bool HasInFlightEvents(const std::string& extension_id);
-
protected:
// The details of an event to be dispatched.
struct ExtensionEvent;
@@ -179,7 +175,6 @@
// Track of the number of dispatched events that have not yet sent an
// ACK from the renderer.
void IncrementInFlightEvents(const Extension* extension);
- std::map<std::string, int> in_flight_events_;
DISALLOW_COPY_AND_ASSIGN(ExtensionEventRouter);
};
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 0519aa5..4299d5c5 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -151,6 +151,8 @@
}
UIThreadExtensionFunction::~UIThreadExtensionFunction() {
+ if (dispatcher())
+ dispatcher()->OnExtensionFunctionCompleted(GetExtension());
}
UIThreadExtensionFunction*
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index bbf89c9..b595fb5 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -287,7 +287,7 @@
private:
// Helper class to track the lifetime of ExtensionFunction's RenderViewHost
// pointer and NULL it out when it dies. It also allows us to filter IPC
- // messages comming from the RenderViewHost. We use this separate class
+ // messages coming from the RenderViewHost. We use this separate class
// (instead of implementing NotificationObserver on ExtensionFunction) because
// it is/ common for subclasses of ExtensionFunction to be
// NotificationObservers, and it would be an easy error to forget to call the
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index e16c810fe..9191e2d 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -728,6 +728,19 @@
function->OnQuotaExceeded();
LogFailure(extension, params.name, kQuotaExceeded);
}
+
+ // We only adjust the keepalive count for UIThreadExtensionFunction for
+ // now, largely for simplicity's sake. This is OK because currently, only
+ // the webRequest API uses IOThreadExtensionFunction, and that API is not
+ // compatible with lazy background pages.
+ profile()->GetExtensionProcessManager()->IncrementLazyKeepaliveCount(
+ extension);
+}
+
+void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
+ const Extension* extension) {
+ profile()->GetExtensionProcessManager()->DecrementLazyKeepaliveCount(
+ extension);
}
// static
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index 120c7b1..cb429e0b 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -100,6 +100,10 @@
void Dispatch(const ExtensionHostMsg_Request_Params& params,
RenderViewHost* sender);
+ // Called when an ExtensionFunction is done executing, after it has sent
+ // a response (if any) to the extension.
+ void OnExtensionFunctionCompleted(const Extension* extension);
+
// Returns the current browser. Callers should generally prefer
// ExtensionFunction::GetCurrentBrowser() over this method, as that one
// provides the correct value for |include_incognito|.
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 3eae9ca..3b91af0 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -131,7 +131,8 @@
ALLOW_THIS_IN_INITIALIZER_LIST(
extension_function_dispatcher_(profile_, this)),
extension_host_type_(host_type),
- associated_web_contents_(NULL) {
+ associated_web_contents_(NULL),
+ close_sequence_id_(0) {
host_contents_.reset(WebContents::Create(
profile_, site_instance, MSG_ROUTING_NONE, NULL, NULL));
content::WebContentsObserver::Observe(host_contents_.get());
@@ -214,6 +215,25 @@
}
}
+void ExtensionHost::SendShouldClose() {
+ CHECK(!extension()->background_page_persists());
+ render_view_host()->Send(new ExtensionMsg_ShouldClose(
+ extension()->id(), ++close_sequence_id_));
+ // TODO(mpcomplete): start timeout
+}
+
+void ExtensionHost::CancelShouldClose() {
+ CHECK(!extension()->background_page_persists());
+ ++close_sequence_id_;
+}
+
+void ExtensionHost::OnShouldCloseAck(int sequence_id) {
+ CHECK(!extension()->background_page_persists());
+ if (sequence_id != close_sequence_id_)
+ return;
+ Close();
+}
+
const Browser* ExtensionHost::GetBrowser() const {
return view() ? view()->browser() : NULL;
}
@@ -240,6 +260,13 @@
std::string());
}
+void ExtensionHost::Close() {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ content::Source<Profile>(profile_),
+ content::Details<ExtensionHost>(this));
+}
+
void ExtensionHost::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -380,16 +407,14 @@
}
void ExtensionHost::CloseContents(WebContents* contents) {
+ // TODO(mpcomplete): is this check really necessary?
if (extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_POPUP ||
extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_DIALOG ||
extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_INFOBAR ||
extension_host_type_ == chrome::VIEW_TYPE_APP_SHELL ||
extension_host_type_ == chrome::VIEW_TYPE_PANEL) {
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- content::Source<Profile>(profile_),
- content::Details<ExtensionHost>(this));
+ Close();
}
}
@@ -433,10 +458,7 @@
if (extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_POPUP) {
if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
event.windowsKeyCode == ui::VKEY_ESCAPE) {
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- content::Source<Profile>(profile_),
- content::Details<ExtensionHost>(this));
+ Close();
return;
}
}
@@ -545,7 +567,6 @@
browser::Navigate(¶ms);
}
-
void ExtensionHost::RenderViewReady() {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 2a5d1d34..6d27b68 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -95,6 +95,21 @@
// Helper variant of the above for cases where no Browser is present.
void CreateViewWithoutBrowser();
+ // Send a message to the renderer to notify it 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.
+ void SendShouldClose();
+
+ // Cancels the current close sequence. Any future Close ACKs will be ignored
+ // (unless SendShouldClose is called again).
+ void CancelShouldClose();
+
+ // Handles the close ACK. The sequence ID lets us identify whether we have
+ // cancelled this close sequence.
+ void OnShouldCloseAck(int sequence_id);
+
const Extension* extension() const { return extension_; }
const std::string& extension_id() const { return extension_id_; }
content::WebContents* host_contents() const { return host_contents_.get(); }
@@ -179,6 +194,9 @@
// Navigates to the initial page.
void LoadInitialURL();
+ // Closes this host (results in deletion).
+ void Close();
+
// Const version of below function.
const Browser* GetBrowser() const;
@@ -233,8 +251,7 @@
ExtensionFunctionDispatcher extension_function_dispatcher_;
- // Only EXTENSION_INFOBAR, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE
- // are used here, others are not hosted by ExtensionHost.
+ // The type of view being hosted.
content::ViewType extension_host_type_;
// The relevant WebContents associated with this ExtensionHost, if any.
@@ -243,6 +260,10 @@
// Used to measure how long it's been since the host was created.
PerfTimer since_created_;
+ // A unique ID associated with each call to ShouldClose. This allows us
+ // to differentiate which ShouldClose message the renderer is responding to.
+ int close_sequence_id_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionHost);
};
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index 9e824dbc..f249cf4 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -37,6 +37,22 @@
namespace {
+// An accessor for an extension's lazy_keepalive_count.
+// TODO(mpcomplete): Should we store this on ExtensionHost instead?
+static base::LazyInstance<base::PropertyAccessor<int> >
+ g_property_accessor = LAZY_INSTANCE_INITIALIZER;
+
+int& GetLazyKeepaliveCount(Profile* profile, const Extension* extension) {
+ base::PropertyBag* bag =
+ profile->GetExtensionService()->GetPropertyBag(extension);
+ int* count = g_property_accessor.Get().GetProperty(bag);
+ if (!count) {
+ g_property_accessor.Get().SetProperty(bag, 0);
+ count = g_property_accessor.Get().GetProperty(bag);
+ }
+ return *count;
+}
+
// 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.
@@ -290,13 +306,58 @@
return all_hosts_.find(host) != all_hosts_.end();
}
-void ExtensionProcessManager::OnExtensionIdle(const std::string& extension_id) {
+int ExtensionProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
+ if (extension->background_page_persists())
+ return 0;
+
+ return ::GetLazyKeepaliveCount(GetProfile(), extension);
+}
+
+int ExtensionProcessManager::IncrementLazyKeepaliveCount(
+ const Extension* extension) {
+ if (extension->background_page_persists())
+ return 0;
+
+ // TODO(mpcomplete): Handle visible views changing.
+ int& count = ::GetLazyKeepaliveCount(GetProfile(), extension);
+ if (++count == 1)
+ OnLazyBackgroundPageActive(extension->id());
+
+ return count;
+}
+
+int ExtensionProcessManager::DecrementLazyKeepaliveCount(
+ const Extension* extension) {
+ if (extension->background_page_persists())
+ return 0;
+
+ int& count = ::GetLazyKeepaliveCount(GetProfile(), extension);
+ DCHECK(count > 0);
+ if (--count == 0)
+ OnLazyBackgroundPageIdle(extension->id());
+
+ return count;
+}
+
+void ExtensionProcessManager::OnLazyBackgroundPageIdle(
+ const std::string& extension_id) {
ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
- if (host && !HasVisibleViews(extension_id)) {
- Profile* profile = GetProfile();
- if (!profile->GetExtensionEventRouter()->HasInFlightEvents(extension_id))
- CloseBackgroundHost(host);
- }
+ if (host && !HasVisibleViews(extension_id))
+ host->SendShouldClose();
+}
+
+void ExtensionProcessManager::OnLazyBackgroundPageActive(
+ const std::string& extension_id) {
+ ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
+ if (host)
+ host->CancelShouldClose();
+}
+
+void ExtensionProcessManager::OnShouldCloseAck(
+ const std::string& extension_id, int sequence_id) {
+ ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
+ if (host)
+ host->OnShouldCloseAck(sequence_id);
}
bool ExtensionProcessManager::HasVisibleViews(const std::string& extension_id) {
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index 41f7c60..bbf2109f 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -89,9 +89,22 @@
// Returns true if |host| is managed by this process manager.
bool HasExtensionHost(ExtensionHost* host) const;
- // Called when the render reports that the extension is idle (only if
- // lazy background pages are enabled).
- void OnExtensionIdle(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);
+
+ // 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);
+ void OnLazyBackgroundPageActive(const std::string& extension_id);
+
+ // Handle a response to the ShouldClose message, used for lazy background
+ // pages.
+ void OnShouldCloseAck(const std::string& extension_id, int sequence_id);
typedef std::set<ExtensionHost*> ExtensionHostSet;
typedef ExtensionHostSet::const_iterator const_iterator;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 3bc6a49..1698552 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -2528,7 +2528,8 @@
}
bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
- return (!extension->has_background_page() ||
+ return (!(extension->has_background_page() &&
+ extension->background_page_persists()) ||
extension_runtime_data_[extension->id()].background_page_ready);
}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 819dc19..86bb3b0 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -263,9 +263,9 @@
bool GetBrowserActionVisibility(const Extension* extension);
void SetBrowserActionVisibility(const Extension* extension, bool visible);
- // Whether the background page, if any, is ready. We don't load other
- // components until then. If there is no background page, we consider it to
- // be ready.
+ // Whether the persistent background page, if any, is ready. We don't load
+ // other components until then. If there is no background page, or if it is
+ // non-persistent (lazy), we consider it to be ready.
bool IsBackgroundPageReady(const Extension* extension);
void SetBackgroundPageReady(const Extension* extension);
diff --git a/chrome/browser/extensions/lazy_background_page_apitest.cc b/chrome/browser/extensions/lazy_background_page_apitest.cc
index c23d307..593a422 100644
--- a/chrome/browser/extensions/lazy_background_page_apitest.cc
+++ b/chrome/browser/extensions/lazy_background_page_apitest.cc
@@ -45,18 +45,24 @@
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
}
+
+ // Loads the extension, which temporarily starts the lazy background page
+ // to dispatch the onInstalled event. We wait until it shuts down again.
+ const Extension* LoadExtensionAndWait(const std::string& test_name) {
+ LazyBackgroundObserver page_complete;
+ FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
+ AppendASCII(test_name);
+ const Extension* extension = LoadExtension(extdir);
+ if (extension)
+ page_complete.Wait();
+ return extension;
+ }
};
IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BrowserActionCreateTab) {
- FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
- AppendASCII("browser_action_create_tab");
- ASSERT_TRUE(LoadExtension(extdir));
+ ASSERT_TRUE(LoadExtensionAndWait("browser_action_create_tab"));
// Lazy Background Page doesn't exist yet.
- // Note: We actually loaded and destroyed the page to dispatch the onInstalled
- // event. LoadExtension waits for the load to finish, after which onInstalled
- // is dispatched. Since the extension isn't listening to it, we immediately
- // tear it down again.
ExtensionProcessManager* pm =
browser()->profile()->GetExtensionProcessManager();
EXPECT_FALSE(pm->GetBackgroundHostForExtension(last_loaded_extension_id_));
@@ -77,9 +83,7 @@
IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest,
BrowserActionCreateTabAfterCallback) {
- FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
- AppendASCII("browser_action_with_callback");
- ASSERT_TRUE(LoadExtension(extdir));
+ ASSERT_TRUE(LoadExtensionAndWait("browser_action_with_callback"));
// Lazy Background Page doesn't exist yet.
ExtensionProcessManager* pm =
@@ -101,9 +105,7 @@
IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, BroadcastEvent) {
ASSERT_TRUE(StartTestServer());
- FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
- AppendASCII("broadcast_event");
- const Extension* extension = LoadExtension(extdir);
+ const Extension* extension = LoadExtensionAndWait("broadcast_event");
ASSERT_TRUE(extension);
// Lazy Background Page doesn't exist yet.
@@ -131,16 +133,12 @@
GetLocationBarForTesting()->PageActionVisibleCount());
}
+// Tests that the lazy background page receives the onInstalled event and shuts
+// down.
IN_PROC_BROWSER_TEST_F(LazyBackgroundPageApiTest, OnInstalled) {
- LazyBackgroundObserver page_complete;
ResultCatcher catcher;
- FilePath extdir = test_data_dir_.AppendASCII("lazy_background_page").
- AppendASCII("on_installed");
- const Extension* extension = LoadExtension(extdir);
- ASSERT_TRUE(extension);
-
+ ASSERT_TRUE(LoadExtensionAndWait("on_installed"));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
- page_complete.Wait();
// Lazy Background Page has been shut down.
ExtensionProcessManager* pm =
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 5dff4e01..1563b5e8 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -90,11 +90,12 @@
OnExtensionAddLazyListener)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveLazyListener,
OnExtensionRemoveLazyListener)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExtensionIdle, OnExtensionIdle)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExtensionEventAck, OnExtensionEventAck)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread,
OnExtensionRequestForIOThread)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_ShouldCloseAck,
+ OnExtensionShouldCloseAck)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_WriteTcmallocHeapProfile_ACK,
@@ -139,9 +140,9 @@
case ExtensionHostMsg_RemoveListener::ID:
case ExtensionHostMsg_AddLazyListener::ID:
case ExtensionHostMsg_RemoveLazyListener::ID:
- case ExtensionHostMsg_ExtensionIdle::ID:
case ExtensionHostMsg_ExtensionEventAck::ID:
case ExtensionHostMsg_CloseChannel::ID:
+ case ExtensionHostMsg_ShouldCloseAck::ID:
case ChromeViewHostMsg_UpdatedCacheStats::ID:
*thread = BrowserThread::UI;
break;
@@ -370,12 +371,6 @@
event_name, extension_id);
}
-void ChromeRenderMessageFilter::OnExtensionIdle(
- const std::string& extension_id) {
- if (profile_->GetExtensionProcessManager())
- profile_->GetExtensionProcessManager()->OnExtensionIdle(extension_id);
-}
-
void ChromeRenderMessageFilter::OnExtensionEventAck(
const std::string& extension_id) {
if (profile_->GetExtensionEventRouter())
@@ -400,6 +395,13 @@
weak_ptr_factory_.GetWeakPtr(), routing_id, params);
}
+void ChromeRenderMessageFilter::OnExtensionShouldCloseAck(
+ const std::string& extension_id, int sequence_id) {
+ if (profile_->GetExtensionProcessManager())
+ profile_->GetExtensionProcessManager()->OnShouldCloseAck(
+ extension_id, sequence_id);
+}
+
#if defined(USE_TCMALLOC)
void ChromeRenderMessageFilter::OnRendererTcmalloc(const std::string& output) {
base::ProcessId pid = base::GetProcId(peer_handle());
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h
index f3271c9..2e6fa44 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.h
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.h
@@ -117,12 +117,13 @@
const std::string& event_name);
void OnExtensionRemoveLazyListener(const std::string& extension_id,
const std::string& event_name);
- void OnExtensionIdle(const std::string& extension_id);
void OnExtensionEventAck(const std::string& extension_id);
void OnExtensionCloseChannel(int port_id);
void OnExtensionRequestForIOThread(
int routing_id,
const ExtensionHostMsg_Request_Params& params);
+ void OnExtensionShouldCloseAck(const std::string& extension_id,
+ int sequence_id);
#if defined(USE_TCMALLOC)
void OnRendererTcmalloc(const std::string& output);
void OnWriteTcmallocHeapProfile(const FilePath::StringType& filename,
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index c295985..5207734 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -231,7 +231,7 @@
// Tell the renderer to update an extension's permission set.
IPC_MESSAGE_CONTROL5(ExtensionMsg_UpdatePermissions,
int /* UpdateExtensionPermissionsInfo::REASON */,
- std::string /* extension_id*/,
+ std::string /* extension_id */,
ExtensionAPIPermissionSet /* permissions */,
URLPatternSet /* explicit_hosts */,
URLPatternSet /* scriptable_hosts */)
@@ -246,6 +246,13 @@
bool /* adblock_plus */,
bool /* other_webrequest */)
+// Ask the renderer if it is ready to shutdown. Used for lazy background pages
+// when they are considered idle. The renderer will reply with the same
+// sequence_id so that we can tell which message it is responding to.
+IPC_MESSAGE_CONTROL2(ExtensionMsg_ShouldClose,
+ std::string /* extension_id */,
+ int /* sequence_id */)
+
// Messages sent from the renderer to the browser.
// A renderer sends this message when an extension process starts an API
@@ -282,11 +289,6 @@
std::string /* extension_id */,
std::string /* name */)
-// Notify the browser that the extension is idle so it's lazy background page
-// can be closed.
-IPC_MESSAGE_CONTROL1(ExtensionHostMsg_ExtensionIdle,
- std::string /* extension_id */)
-
// Notify the browser that an event has finished being dispatched.
IPC_MESSAGE_CONTROL1(ExtensionHostMsg_ExtensionEventAck,
std::string /* extension_id */)
@@ -368,6 +370,11 @@
IPC_MESSAGE_ROUTED1(ExtensionHostMsg_ResponseAck,
int /* request_id */)
+// Response to ExtensionMsg_ShouldClose.
+IPC_MESSAGE_CONTROL2(ExtensionHostMsg_ShouldCloseAck,
+ std::string /* extension_id */,
+ int /* sequence_id */)
+
// Response to the renderer for the above message.
IPC_MESSAGE_ROUTED3(ExtensionMsg_GetAppNotifyChannelResponse,
std::string /* channel_id */,
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index f357830..e59922c3 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -95,6 +95,7 @@
IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
+ IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldClose, OnShouldClose)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -183,17 +184,9 @@
function_name == "Event.dispatchJSON") { // may always be true
RenderThread::Get()->Send(
new ExtensionHostMsg_ExtensionEventAck(extension_id));
- CheckIdleStatus(extension_id);
}
}
-void ExtensionDispatcher::CheckIdleStatus(const std::string& extension_id) {
- const Extension* extension = extensions_.GetByID(extension_id);
- if (extension && !extension->background_page_persists() &&
- !SchemaGeneratedBindings::HasPendingRequests(extension_id))
- RenderThread::Get()->Send(new ExtensionHostMsg_ExtensionIdle(extension_id));
-}
-
void ExtensionDispatcher::OnDeliverMessage(int target_port_id,
const std::string& message) {
MiscellaneousBindings::DeliverMessage(
@@ -542,3 +535,9 @@
webrequest_adblock_plus_ = adblock_plus;
webrequest_other_ = other;
}
+
+void ExtensionDispatcher::OnShouldClose(const std::string& extension_id,
+ int sequence_id) {
+ RenderThread::Get()->Send(
+ new ExtensionHostMsg_ShouldCloseAck(extension_id, sequence_id));
+}
diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h
index 5f42c873f..7a2de8c 100644
--- a/chrome/renderer/extensions/extension_dispatcher.h
+++ b/chrome/renderer/extensions/extension_dispatcher.h
@@ -88,10 +88,6 @@
return webrequest_other_;
}
- // If the extension is in fact idle, tell the browser process to close
- // the background page.
- void CheckIdleStatus(const std::string& extension_id);
-
private:
friend class RenderViewTest;
@@ -125,6 +121,7 @@
bool adblock,
bool adblock_plus,
bool other_webrequest);
+ void OnShouldClose(const std::string& extension_id, int sequence_id);
// Update the list of active extensions that will be reported when we crash.
void UpdateActiveExtensions();
diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc
index d144f2c..0e33ec4 100644
--- a/chrome/renderer/extensions/extension_helper.cc
+++ b/chrome/renderer/extensions/extension_helper.cc
@@ -189,8 +189,6 @@
SchemaGeneratedBindings::HandleResponse(
extension_dispatcher_->v8_context_set(), request_id, success,
response, error, &extension_id);
-
- extension_dispatcher_->CheckIdleStatus(extension_id);
}
void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id,