diff options
Diffstat (limited to 'chrome')
17 files changed, 306 insertions, 224 deletions
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc index 908c06c..0b957df 100644 --- a/chrome/browser/extensions/extension_event_router.cc +++ b/chrome/browser/extensions/extension_event_router.cc @@ -405,20 +405,27 @@ void ExtensionEventRouter::MaybeLoadLazyBackgroundPage( void ExtensionEventRouter::IncrementInFlightEvents( Profile* profile, const Extension* extension) { + // Only increment in-flight events if the lazy background page is active, + // because that's the only time we'll get an ACK. if (extension->has_lazy_background_page()) { - profile->GetExtensionProcessManager()->IncrementLazyKeepaliveCount( - extension); + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); + ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id()); + if (host) + pm->IncrementLazyKeepaliveCount(extension); } } -void ExtensionEventRouter::OnExtensionEventAck( +void ExtensionEventRouter::OnEventAck( Profile* profile, const std::string& extension_id) { - const Extension* extension = profile->GetExtensionService()->extensions()-> - GetByID(extension_id); - if (extension && extension->has_lazy_background_page()) { - profile->GetExtensionProcessManager()->DecrementLazyKeepaliveCount( - extension); - } + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); + ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id); + // The event ACK is routed to the background host, so this should never be + // NULL. + CHECK(host); + CHECK(host->extension()->has_lazy_background_page()); + pm->DecrementLazyKeepaliveCount(host->extension()); } void ExtensionEventRouter::DispatchPendingEvent( diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h index 2b52cc8..faf80e9 100644 --- a/chrome/browser/extensions/extension_event_router.h +++ b/chrome/browser/extensions/extension_event_router.h @@ -121,7 +121,7 @@ class ExtensionEventRouter : public content::NotificationObserver { const GURL& event_url); // Record the Event Ack from the renderer. (One less event in-flight.) - void OnExtensionEventAck(Profile* profile, const std::string& extension_id); + void OnEventAck(Profile* profile, const std::string& extension_id); private: // The details of an event to be dispatched. diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index b3b3105..b278df8 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -152,7 +152,7 @@ UIThreadExtensionFunction::UIThreadExtensionFunction() } UIThreadExtensionFunction::~UIThreadExtensionFunction() { - if (dispatcher()) + if (dispatcher() && render_view_host()) dispatcher()->OnExtensionFunctionCompleted(GetExtension()); } diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index ed4ee74..4a3900f 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -14,6 +14,7 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/browser_shutdown.h" +#include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_system.h" @@ -470,6 +471,11 @@ bool ExtensionHost::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message) IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAck, OnEventAck) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount, + OnIncrementLazyKeepaliveCount) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementLazyKeepaliveCount, + OnDecrementLazyKeepaliveCount) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -479,6 +485,27 @@ void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { extension_function_dispatcher_.Dispatch(params, render_view_host()); } +void ExtensionHost::OnEventAck() { + ExtensionEventRouter* router = ExtensionSystem::Get(profile_)->event_router(); + if (router) + router->OnEventAck(profile_, extension_id()); +} + +void ExtensionHost::OnIncrementLazyKeepaliveCount() { + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile_)->process_manager(); + if (pm) + pm->IncrementLazyKeepaliveCount(extension()); +} + +void ExtensionHost::OnDecrementLazyKeepaliveCount() { + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile_)->process_manager(); + if (pm) + pm->DecrementLazyKeepaliveCount(extension()); +} + + void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { render_view_host_ = render_view_host; diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 835f62f..be0208a 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -188,6 +188,9 @@ class ExtensionHost : public content::WebContentsDelegate, // Message handlers. void OnRequest(const ExtensionHostMsg_Request_Params& params); + void OnEventAck(); + void OnIncrementLazyKeepaliveCount(); + void OnDecrementLazyKeepaliveCount(); // Handles keyboard events that were not handled by HandleKeyboardEvent(). // Platform specific implementation may override this method to handle the diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index ccb555e..d041527 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -13,6 +13,7 @@ #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/extension_tab_util.h" #include "chrome/browser/extensions/lazy_background_task_queue.h" #include "chrome/browser/extensions/process_map.h" @@ -47,16 +48,25 @@ using content::WebContents; struct ExtensionMessageService::MessagePort { content::RenderProcessHost* process; int routing_id; - explicit MessagePort(content::RenderProcessHost* process = NULL, - int routing_id = MSG_ROUTING_CONTROL) - : process(process), routing_id(routing_id) {} + std::string extension_id; + void* background_host_ptr; // used in IncrementLazyKeepaliveCount + + MessagePort() + : process(NULL), + routing_id(MSG_ROUTING_CONTROL), + background_host_ptr(NULL) {} + MessagePort(content::RenderProcessHost* process, + int routing_id, + const std::string& extension_id) + : process(process), + routing_id(routing_id), + extension_id(extension_id), + background_host_ptr(NULL) {} }; struct ExtensionMessageService::MessageChannel { ExtensionMessageService::MessagePort opener; ExtensionMessageService::MessagePort receiver; - std::string source_extension_id; - std::string target_extension_id; }; struct ExtensionMessageService::OpenChannelParams { @@ -124,24 +134,30 @@ static content::RenderProcessHost* GetExtensionProcess( return site_instance->GetProcess(); } -static void IncrementLazyKeepaliveCount(content::RenderProcessHost* process, - const std::string& extension_id) { - Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); - const Extension* extension = profile->GetExtensionService()->extensions()-> - GetByID(extension_id); - if (extension) - profile->GetExtensionProcessManager()->IncrementLazyKeepaliveCount( - extension); +static void IncrementLazyKeepaliveCount( + ExtensionMessageService::MessagePort* port) { + Profile* profile = + Profile::FromBrowserContext(port->process->GetBrowserContext()); + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); + ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id); + if (host && host->extension()->has_lazy_background_page()) + pm->IncrementLazyKeepaliveCount(host->extension()); + + // Keep track of the background host, so when we decrement, we only do so if + // the host hasn't reloaded. + port->background_host_ptr = host; } -static void DecrementLazyKeepaliveCount(content::RenderProcessHost* process, - const std::string& extension_id) { - Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); - const Extension* extension = profile->GetExtensionService()->extensions()-> - GetByID(extension_id); - if (extension) - profile->GetExtensionProcessManager()->DecrementLazyKeepaliveCount( - extension); +static void DecrementLazyKeepaliveCount( + ExtensionMessageService::MessagePort* port) { + Profile* profile = + Profile::FromBrowserContext(port->process->GetBrowserContext()); + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); + ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id); + if (host && host == port->background_host_ptr) + pm->DecrementLazyKeepaliveCount(host->extension()); } } // namespace @@ -195,7 +211,8 @@ void ExtensionMessageService::OpenChannelToExtension( // which depends on whether the extension uses spanning or split mode. MessagePort receiver( GetExtensionProcess(profile, target_extension_id), - MSG_ROUTING_CONTROL); + MSG_ROUTING_CONTROL, + target_extension_id); WebContents* source_contents = tab_util::GetWebContentsByID( source_process_id, source_routing_id); @@ -237,12 +254,13 @@ void ExtensionMessageService::OpenChannelToTab( receiver.process = contents->web_contents()->GetRenderProcessHost(); receiver.routing_id = contents->web_contents()->GetRenderViewHost()->GetRoutingID(); + receiver.extension_id = extension_id; } if (contents && contents->web_contents()->GetController().NeedsReload()) { // The tab isn't loaded yet. Don't attempt to connect. Treat this as a // disconnect. - DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL), + DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL, extension_id), GET_OPPOSITE_PORT_ID(receiver_port_id), true); return; } @@ -269,7 +287,7 @@ bool ExtensionMessageService::OpenChannelImpl(const OpenChannelParams& params) { if (!params.receiver.process) { // Treat it as a disconnect. - DispatchOnDisconnect(MessagePort(params.source, MSG_ROUTING_CONTROL), + DispatchOnDisconnect(MessagePort(params.source, MSG_ROUTING_CONTROL, ""), GET_OPPOSITE_PORT_ID(params.receiver_port_id), true); return false; } @@ -279,10 +297,9 @@ bool ExtensionMessageService::OpenChannelImpl(const OpenChannelParams& params) { CHECK(params.receiver.process); MessageChannel* channel(new MessageChannel); - channel->opener = MessagePort(params.source, MSG_ROUTING_CONTROL); + channel->opener = MessagePort(params.source, MSG_ROUTING_CONTROL, + params.source_extension_id); channel->receiver = params.receiver; - channel->source_extension_id = params.source_extension_id; - channel->target_extension_id = params.target_extension_id; CHECK(params.receiver.process); @@ -300,10 +317,8 @@ bool ExtensionMessageService::OpenChannelImpl(const OpenChannelParams& params) { params.source_extension_id, params.target_extension_id); // Keep both ends of the channel alive until the channel is closed. - IncrementLazyKeepaliveCount(channel->opener.process, - channel->source_extension_id); - IncrementLazyKeepaliveCount(channel->receiver.process, - channel->target_extension_id); + IncrementLazyKeepaliveCount(&channel->opener); + IncrementLazyKeepaliveCount(&channel->receiver); return true; } @@ -338,10 +353,8 @@ void ExtensionMessageService::CloseChannelImpl( } // Balance the addrefs in OpenChannelImpl. - DecrementLazyKeepaliveCount(channel->opener.process, - channel->source_extension_id); - DecrementLazyKeepaliveCount(channel->receiver.process, - channel->target_extension_id); + DecrementLazyKeepaliveCount(&channel->opener); + DecrementLazyKeepaliveCount(&channel->receiver); delete channel_iter->second; channels_.erase(channel_iter); @@ -452,6 +465,7 @@ void ExtensionMessageService::PendingOpenChannel( return; params.receiver = MessagePort(host->render_process_host(), - MSG_ROUTING_CONTROL); + MSG_ROUTING_CONTROL, + params.target_extension_id); OpenChannelImpl(params); } diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 30fcb4d..100059e 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -373,6 +373,12 @@ bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const { return all_hosts_.find(host) != all_hosts_.end(); } +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 (!extension->has_lazy_background_page()) return 0; @@ -397,15 +403,10 @@ int ExtensionProcessManager::DecrementLazyKeepaliveCount( if (!extension->has_lazy_background_page()) return 0; - // Don't decrement the count if the background page has gone away. This can - // happen e.g. if an event was dispatched while unloading the page, or if - // the process is killed/closed while a message port remains open. - // TODO(mpcomplete): This might be insufficient.. what if the page goes away - // and comes back before we get here? Then we'll have an imbalanced - // keepalive count. - ExtensionHost* host = GetBackgroundHostForExtension(extension->id()); - if (!host) - return 0; + // This should never be called if the background page isn't active. + // Otherwise, the count can get out of sync, because we reset it when the + // page unloads. + CHECK(GetBackgroundHostForExtension(extension->id())); int& count = background_page_data_[extension->id()].lazy_keepalive_count; DCHECK_GT(count, 0); diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h index c5a936a..eddf0cf 100644 --- a/chrome/browser/extensions/extension_process_manager.h +++ b/chrome/browser/extensions/extension_process_manager.h @@ -89,6 +89,10 @@ class ExtensionProcessManager : public content::NotificationObserver { // Returns true if |host| is managed by this process manager. bool HasExtensionHost(ExtensionHost* host) const; + // 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. diff --git a/chrome/browser/extensions/lazy_background_task_queue.cc b/chrome/browser/extensions/lazy_background_task_queue.cc index bb1b1a2..dbe0ff6 100644 --- a/chrome/browser/extensions/lazy_background_task_queue.cc +++ b/chrome/browser/extensions/lazy_background_task_queue.cc @@ -5,6 +5,7 @@ #include "chrome/browser/extensions/lazy_background_task_queue.h" #include "base/callback.h" +#include "base/message_loop.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_service.h" @@ -43,10 +44,12 @@ bool LazyBackgroundTaskQueue::ShouldEnqueueTask( Profile* profile, const Extension* extension) { DCHECK(extension); if (extension->has_lazy_background_page()) { - ExtensionProcessManager* pm = profile->GetExtensionProcessManager(); + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); ExtensionHost* background_host = pm->GetBackgroundHostForExtension(extension->id()); - if (!background_host || !background_host->did_stop_loading()) + if (!background_host || !background_host->did_stop_loading() || + pm->IsBackgroundHostClosing(extension->id())) return true; } @@ -64,16 +67,10 @@ void LazyBackgroundTaskQueue::AddPendingTask( tasks_list = new PendingTasksList(); pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); - // If this is the first enqueued task, ensure the background page - // is loaded. - const Extension* extension = - ExtensionSystem::Get(profile)->extension_service()-> - extensions()->GetByID(extension_id); - DCHECK(extension->has_lazy_background_page()); - ExtensionProcessManager* pm = - ExtensionSystem::Get(profile)->process_manager(); - pm->IncrementLazyKeepaliveCount(extension); - pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); + // If this is the first enqueued task, and we're not waiting for the + // background page to unload, ensure the background page is loaded. + if (pending_page_loads_.count(key) == 0) + StartLazyBackgroundPage(profile, extension_id); } else { tasks_list = it->second.get(); } @@ -81,6 +78,26 @@ void LazyBackgroundTaskQueue::AddPendingTask( tasks_list->push_back(task); } +void LazyBackgroundTaskQueue::StartLazyBackgroundPage( + Profile* profile, const std::string& extension_id) { + ExtensionProcessManager* pm = + ExtensionSystem::Get(profile)->process_manager(); + if (pm->IsBackgroundHostClosing(extension_id)) { + // When the background host finishes closing, we will reload it. + pending_page_loads_.insert(PendingTasksKey(profile, extension_id)); + return; + } + + const Extension* extension = + ExtensionSystem::Get(profile)->extension_service()-> + extensions()->GetByID(extension_id); + DCHECK(extension->has_lazy_background_page()); + pm->IncrementLazyKeepaliveCount(extension); + pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); + + pending_page_loads_.erase(PendingTasksKey(profile, extension_id)); +} + void LazyBackgroundTaskQueue::ProcessPendingTasks( ExtensionHost* host, Profile* profile, @@ -130,15 +147,24 @@ void LazyBackgroundTaskQueue::Observe( break; } case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { - // Notify consumers about the load failure when the background host dies. - // This can happen if the extension crashes. This is not strictly - // necessary, since we also unload the extension in that case (which - // dispatches the tasks below), but is a good extra precaution. Profile* profile = content::Source<Profile>(source).ptr(); ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); if (host->extension_host_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { - ProcessPendingTasks(NULL, profile, host->extension()); + PendingTasksKey key(profile, host->extension()->id()); + if (pending_page_loads_.count(key) > 0) { + // We were waiting for the background page to unload. We can start it + // up again and dispatch any queued events. + MessageLoop::current()->PostTask(FROM_HERE, base::Bind( + &LazyBackgroundTaskQueue::StartLazyBackgroundPage, + AsWeakPtr(), profile, host->extension()->id())); + } else { + // This may be a load failure (e.g. a crash). In that case, notify + // consumers about the load failure. This is not strictly necessary, + // since we also unload the extension in that case (which dispatches + // the tasks below), but is a good extra precaution. + ProcessPendingTasks(NULL, profile, host->extension()); + } } break; } diff --git a/chrome/browser/extensions/lazy_background_task_queue.h b/chrome/browser/extensions/lazy_background_task_queue.h index 12b85ba..abe71b2 100644 --- a/chrome/browser/extensions/lazy_background_task_queue.h +++ b/chrome/browser/extensions/lazy_background_task_queue.h @@ -7,11 +7,13 @@ #pragma once #include <map> +#include <set> #include <string> #include "base/compiler_specific.h" #include "base/callback_forward.h" #include "base/memory/linked_ptr.h" +#include "base/memory/weak_ptr.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -27,7 +29,9 @@ namespace extensions { // // It is the consumer's responsibility to use this class when appropriate, i.e. // only with extensions that have not-yet-loaded lazy background pages. -class LazyBackgroundTaskQueue : public content::NotificationObserver { +class LazyBackgroundTaskQueue + : public content::NotificationObserver, + public base::SupportsWeakPtr<LazyBackgroundTaskQueue> { public: typedef base::Callback<void(ExtensionHost*)> PendingTask; @@ -56,6 +60,10 @@ class LazyBackgroundTaskQueue : public content::NotificationObserver { typedef std::vector<PendingTask> PendingTasksList; typedef std::map<PendingTasksKey, linked_ptr<PendingTasksList> > PendingTasksMap; + typedef std::set<PendingTasksKey> PendingPageLoadList; + + void StartLazyBackgroundPage(Profile* profile, + const std::string& extension_id); // content::NotificationObserver interface. virtual void Observe(int type, @@ -72,6 +80,7 @@ class LazyBackgroundTaskQueue : public content::NotificationObserver { Profile* profile_; content::NotificationRegistrar registrar_; PendingTasksMap pending_tasks_; + PendingPageLoadList pending_page_loads_; }; } // namespace extensions diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc index c1a0eb8..095057f 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc @@ -91,16 +91,11 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message, OnExtensionAddLazyListener) IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveLazyListener, OnExtensionRemoveLazyListener) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExtensionEventAck, OnExtensionEventAck) IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel) IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread, OnExtensionRequestForIOThread) IPC_MESSAGE_HANDLER(ExtensionHostMsg_ShouldUnloadAck, OnExtensionShouldUnloadAck) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount, - OnExtensionIncrementLazyKeepaliveCount) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementLazyKeepaliveCount, - OnExtensionDecrementLazyKeepaliveCount) IPC_MESSAGE_HANDLER(ExtensionHostMsg_GenerateUniqueID, OnExtensionGenerateUniqueID) IPC_MESSAGE_HANDLER(ExtensionHostMsg_UnloadAck, OnExtensionUnloadAck) @@ -150,12 +145,9 @@ void ChromeRenderMessageFilter::OverrideThreadForMessage( case ExtensionHostMsg_RemoveListener::ID: case ExtensionHostMsg_AddLazyListener::ID: case ExtensionHostMsg_RemoveLazyListener::ID: - case ExtensionHostMsg_ExtensionEventAck::ID: case ExtensionHostMsg_CloseChannel::ID: case ExtensionHostMsg_ShouldUnloadAck::ID: case ExtensionHostMsg_UnloadAck::ID: - case ExtensionHostMsg_IncrementLazyKeepaliveCount::ID: - case ExtensionHostMsg_DecrementLazyKeepaliveCount::ID: case ChromeViewHostMsg_UpdatedCacheStats::ID: *thread = BrowserThread::UI; break; @@ -388,13 +380,6 @@ void ChromeRenderMessageFilter::OnExtensionRemoveLazyListener( event_name, extension_id); } -void ChromeRenderMessageFilter::OnExtensionEventAck( - const std::string& extension_id) { - if (profile_->GetExtensionEventRouter()) - profile_->GetExtensionEventRouter()->OnExtensionEventAck( - profile_, extension_id); -} - void ChromeRenderMessageFilter::OnExtensionCloseChannel(int port_id, bool connection_error) { if (!content::RenderProcessHost::FromID(render_process_id_)) @@ -429,32 +414,6 @@ void ChromeRenderMessageFilter::OnExtensionUnloadAck( profile_->GetExtensionProcessManager()->OnUnloadAck(extension_id); } -void ChromeRenderMessageFilter::OnExtensionIncrementLazyKeepaliveCount( - const std::string& extension_id) { - ExtensionService* service = - ExtensionSystem::Get(profile_)->extension_service(); - ExtensionProcessManager* process_manager = - ExtensionSystem::Get(profile_)->process_manager(); - if (process_manager && service) { - const Extension* extension = service->extensions()->GetByID(extension_id); - if (extension) - process_manager->IncrementLazyKeepaliveCount(extension); - } -} - -void ChromeRenderMessageFilter::OnExtensionDecrementLazyKeepaliveCount( - const std::string& extension_id) { - ExtensionService* service = - ExtensionSystem::Get(profile_)->extension_service(); - ExtensionProcessManager* process_manager = - ExtensionSystem::Get(profile_)->process_manager(); - if (process_manager && service) { - const Extension* extension = service->extensions()->GetByID(extension_id); - if (extension) - process_manager->DecrementLazyKeepaliveCount(extension); - } -} - void ChromeRenderMessageFilter::OnExtensionGenerateUniqueID(int* unique_id) { static int next_unique_id = 1; *unique_id = next_unique_id++; diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h index 5068f94..0dfb1df 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.h +++ b/chrome/browser/renderer_host/chrome_render_message_filter.h @@ -117,7 +117,6 @@ class ChromeRenderMessageFilter : public content::BrowserMessageFilter { const std::string& event_name); void OnExtensionRemoveLazyListener(const std::string& extension_id, const std::string& event_name); - void OnExtensionEventAck(const std::string& extension_id); void OnExtensionCloseChannel(int port_id, bool connection_error); void OnExtensionRequestForIOThread( int routing_id, @@ -125,8 +124,6 @@ class ChromeRenderMessageFilter : public content::BrowserMessageFilter { void OnExtensionShouldUnloadAck(const std::string& extension_id, int sequence_id); void OnExtensionUnloadAck(const std::string& extension_id); - void OnExtensionIncrementLazyKeepaliveCount(const std::string& extension_id); - void OnExtensionDecrementLazyKeepaliveCount(const std::string& extension_id); void OnExtensionGenerateUniqueID(int* unique_id); #if defined(USE_TCMALLOC) void OnRendererTcmalloc(const std::string& output); diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h index 6cc83ae..ff35b1e 100644 --- a/chrome/common/extensions/extension_messages.h +++ b/chrome/common/extensions/extension_messages.h @@ -331,9 +331,7 @@ IPC_MESSAGE_CONTROL2(ExtensionHostMsg_RemoveLazyListener, std::string /* name */) // Notify the browser that an event has finished being dispatched. -IPC_MESSAGE_CONTROL1(ExtensionHostMsg_ExtensionEventAck, - std::string /* extension_id */) - +IPC_MESSAGE_ROUTED0(ExtensionHostMsg_EventAck) // Open a channel to all listening contexts owned by the extension with // the given ID. This always returns a valid port ID which can be used for @@ -417,13 +415,11 @@ IPC_MESSAGE_CONTROL1(ExtensionHostMsg_UnloadAck, // Informs the browser to increment the keepalive count for the lazy background // page, keeping it alive. -IPC_MESSAGE_CONTROL1(ExtensionHostMsg_IncrementLazyKeepaliveCount, - std::string /* extension_id */) +IPC_MESSAGE_ROUTED0(ExtensionHostMsg_IncrementLazyKeepaliveCount) // Informs the browser there is one less thing keeping the lazy background page // alive. -IPC_MESSAGE_CONTROL1(ExtensionHostMsg_DecrementLazyKeepaliveCount, - std::string /* extension_id */) +IPC_MESSAGE_ROUTED0(ExtensionHostMsg_DecrementLazyKeepaliveCount) // Fetches a globally unique ID (for the lifetime of the browser) from the // browser process. diff --git a/chrome/renderer/extensions/extension_custom_bindings.cc b/chrome/renderer/extensions/extension_custom_bindings.cc index 7b177e1..047588c 100644 --- a/chrome/renderer/extensions/extension_custom_bindings.cc +++ b/chrome/renderer/extensions/extension_custom_bindings.cc @@ -14,97 +14,16 @@ #include "chrome/renderer/extensions/extension_dispatcher.h" #include "chrome/renderer/extensions/extension_helper.h" #include "content/public/renderer/render_view.h" -#include "content/public/renderer/render_view_visitor.h" #include "grit/renderer_resources.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" -#include "v8/include/v8.h" #include "webkit/glue/webkit_glue.h" +#include "v8/include/v8.h" namespace extensions { namespace { -// A RenderViewVisitor class that iterates through the set of available -// views, looking for a view of the given type, in the given browser window -// and within the given extension. -// Used to accumulate the list of views associated with an extension. -class ExtensionViewAccumulator : public content::RenderViewVisitor { - public: - ExtensionViewAccumulator(const std::string& extension_id, - int browser_window_id, - content::ViewType view_type) - : extension_id_(extension_id), - browser_window_id_(browser_window_id), - view_type_(view_type), - views_(v8::Array::New()), - index_(0) { - } - - v8::Local<v8::Array> views() { return views_; } - - virtual bool Visit(content::RenderView* render_view) { - ExtensionHelper* helper = ExtensionHelper::Get(render_view); - if (!ViewTypeMatches(helper->view_type(), view_type_)) - return true; - - GURL url = render_view->GetWebView()->mainFrame()->document().url(); - if (!url.SchemeIs(chrome::kExtensionScheme)) - return true; - const std::string& extension_id = url.host(); - if (extension_id != extension_id_) - return true; - - if (browser_window_id_ != extension_misc::kUnknownWindowId && - helper->browser_window_id() != browser_window_id_) { - return true; - } - - v8::Local<v8::Context> context = - render_view->GetWebView()->mainFrame()->mainWorldScriptContext(); - if (!context.IsEmpty()) { - v8::Local<v8::Value> window = context->Global(); - DCHECK(!window.IsEmpty()); - - if (!OnMatchedView(window)) - return false; - } - return true; - } - - private: - // Called on each view found matching the search criteria. Returns false - // to terminate the iteration. - bool OnMatchedView(v8::Local<v8::Value> view_window) { - views_->Set(v8::Integer::New(index_), view_window); - index_++; - - if (view_type_ == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) - return false; // There can be only one... - - return true; - } - - // Returns true is |type| "isa" |match|. - static bool ViewTypeMatches(content::ViewType type, content::ViewType match) { - if (type == match) - return true; - - // INVALID means match all. - if (match == content::VIEW_TYPE_INVALID) - return true; - - return false; - } - - std::string extension_id_; - int browser_window_id_; - content::ViewType view_type_; - v8::Local<v8::Array> views_; - int index_; -}; - } // namespace ExtensionCustomBindings::ExtensionCustomBindings( @@ -159,10 +78,21 @@ v8::Handle<v8::Value> ExtensionCustomBindings::GetExtensionViews( if (!extension) return v8::Undefined(); - ExtensionViewAccumulator accumulator(extension->id(), browser_window_id, - view_type); - content::RenderView::ForEach(&accumulator); - return accumulator.views(); + std::vector<content::RenderView*> views = ExtensionHelper::GetExtensionViews( + extension->id(), browser_window_id, view_type); + v8::Local<v8::Array> v8_views = v8::Array::New(); + int v8_index = 0; + for (size_t i = 0; i < views.size(); ++i) { + v8::Local<v8::Context> context = + views[i]->GetWebView()->mainFrame()->mainWorldScriptContext(); + if (!context.IsEmpty()) { + v8::Local<v8::Value> window = context->Global(); + DCHECK(!window.IsEmpty()); + v8_views->Set(v8::Integer::New(v8_index++), window); + } + } + + return v8_views; } // static diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index fcfa1e7..9b2744c 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -45,6 +45,7 @@ #include "chrome/renderer/native_handler.h" #include "chrome/renderer/resource_bundle_source_map.h" #include "content/public/renderer/render_thread.h" +#include "content/public/renderer/render_view.h" #include "grit/renderer_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" @@ -141,10 +142,12 @@ class LazyBackgroundPageNativeHandler : public ChromeV8Extension { v8::Handle<v8::Value> IncrementKeepaliveCount(const v8::Arguments& args) { ChromeV8Context* context = extension_dispatcher()->v8_context_set().GetCurrent(); - if (IsCurrentContextLazyBackgroundPage(context->extension())) { - content::RenderThread::Get()->Send( - new ExtensionHostMsg_IncrementLazyKeepaliveCount( - context->extension()->id())); + if (!context) + return v8::Undefined(); + content::RenderView* render_view = context->GetRenderView(); + if (IsContextLazyBackgroundPage(render_view, context->extension())) { + render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount( + render_view->GetRoutingID())); } return v8::Undefined(); } @@ -152,17 +155,19 @@ class LazyBackgroundPageNativeHandler : public ChromeV8Extension { v8::Handle<v8::Value> DecrementKeepaliveCount(const v8::Arguments& args) { ChromeV8Context* context = extension_dispatcher()->v8_context_set().GetCurrent(); - if (IsCurrentContextLazyBackgroundPage(context->extension())) { - content::RenderThread::Get()->Send( - new ExtensionHostMsg_DecrementLazyKeepaliveCount( - context->extension()->id())); + if (!context) + return v8::Undefined(); + content::RenderView* render_view = context->GetRenderView(); + if (IsContextLazyBackgroundPage(render_view, context->extension())) { + render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount( + render_view->GetRoutingID())); } return v8::Undefined(); } private: - bool IsCurrentContextLazyBackgroundPage(const Extension* extension) { - content::RenderView* render_view = GetCurrentRenderView(); + bool IsContextLazyBackgroundPage(content::RenderView* render_view, + const Extension* extension) { if (!render_view) return false; @@ -305,12 +310,17 @@ void ExtensionDispatcher::OnMessageInvoke(const std::string& extension_id, kInitialExtensionIdleHandlerDelayMs); } + // Tell the browser process when an event has been dispatched with a lazy + // background page active. const Extension* extension = extensions_.GetByID(extension_id); - // Tell the browser process that the event is dispatched and we're idle. if (extension && extension->has_lazy_background_page() && function_name == kEventDispatchFunction) { - RenderThread::Get()->Send( - new ExtensionHostMsg_ExtensionEventAck(extension_id)); + content::RenderView* background_view = + ExtensionHelper::GetBackgroundPage(extension_id); + if (background_view) { + background_view->Send(new ExtensionHostMsg_EventAck( + background_view->GetRoutingID())); + } } } diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc index 73027de..41fd732 100644 --- a/chrome/renderer/extensions/extension_helper.cc +++ b/chrome/renderer/extensions/extension_helper.cc @@ -22,7 +22,9 @@ #include "chrome/renderer/extensions/user_script_scheduler.h" #include "chrome/renderer/extensions/user_script_slave.h" #include "content/public/renderer/render_view.h" +#include "content/public/renderer/render_view_visitor.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedUserGesture.h" @@ -48,6 +50,91 @@ namespace { typedef std::map<WebFrame*, UserScriptScheduler*> SchedulerMap; static base::LazyInstance<SchedulerMap> g_schedulers = LAZY_INSTANCE_INITIALIZER; + +// A RenderViewVisitor class that iterates through the set of available +// views, looking for a view of the given type, in the given browser window +// and within the given extension. +// Used to accumulate the list of views associated with an extension. +class ExtensionViewAccumulator : public content::RenderViewVisitor { + public: + ExtensionViewAccumulator(const std::string& extension_id, + int browser_window_id, + content::ViewType view_type) + : extension_id_(extension_id), + browser_window_id_(browser_window_id), + view_type_(view_type) { + } + + std::vector<content::RenderView*> views() { return views_; } + + // Returns false to terminate the iteration. + virtual bool Visit(content::RenderView* render_view) { + ExtensionHelper* helper = ExtensionHelper::Get(render_view); + if (!ViewTypeMatches(helper->view_type(), view_type_)) + return true; + + GURL url = render_view->GetWebView()->mainFrame()->document().url(); + if (!url.SchemeIs(chrome::kExtensionScheme)) + return true; + const std::string& extension_id = url.host(); + if (extension_id != extension_id_) + return true; + + if (browser_window_id_ != extension_misc::kUnknownWindowId && + helper->browser_window_id() != browser_window_id_) { + return true; + } + + views_.push_back(render_view); + + if (view_type_ == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) + return false; // There can be only one... + return true; + } + + private: + // Returns true if |type| "isa" |match|. + static bool ViewTypeMatches(content::ViewType type, content::ViewType match) { + if (type == match) + return true; + + // INVALID means match all. + if (match == content::VIEW_TYPE_INVALID) + return true; + + return false; + } + + std::string extension_id_; + int browser_window_id_; + content::ViewType view_type_; + std::vector<content::RenderView*> views_; +}; + +} + +// static +std::vector<content::RenderView*> ExtensionHelper::GetExtensionViews( + const std::string& extension_id, + int browser_window_id, + content::ViewType view_type) { + ExtensionViewAccumulator accumulator( + extension_id, browser_window_id, view_type); + content::RenderView::ForEach(&accumulator); + return accumulator.views(); +} + +// static +content::RenderView* ExtensionHelper::GetBackgroundPage( + const std::string& extension_id) { + ExtensionViewAccumulator accumulator( + extension_id, extension_misc::kUnknownWindowId, + chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); + content::RenderView::ForEach(&accumulator); + CHECK_LE(accumulator.views().size(), 1u); + if (accumulator.views().size() == 0) + return NULL; + return accumulator.views()[0]; } ExtensionHelper::ExtensionHelper(content::RenderView* render_view, diff --git a/chrome/renderer/extensions/extension_helper.h b/chrome/renderer/extensions/extension_helper.h index 0a0b949..a1ed3ed 100644 --- a/chrome/renderer/extensions/extension_helper.h +++ b/chrome/renderer/extensions/extension_helper.h @@ -36,6 +36,18 @@ class ExtensionHelper : public content::RenderViewObserver, public content::RenderViewObserverTracker<ExtensionHelper> { public: + // Returns a list of extension RenderViews that match the given filter + // criteria. If |browser_window_id| is not extension_misc::kUnknownWindowId, + // the list is restricted to views in that browser window. + static std::vector<content::RenderView*> GetExtensionViews( + const std::string& extension_id, + int browser_window_id, + content::ViewType view_type); + + // Returns the given extension's background page, or NULL if none. + static content::RenderView* GetBackgroundPage( + const std::string& extension_id); + ExtensionHelper(content::RenderView* render_view, ExtensionDispatcher* extension_dispatcher); virtual ~ExtensionHelper(); |