Chromium Code Reviews| Index: chrome/browser/extensions/extension_event_router.cc |
| diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc |
| index ab072009a98978ba445a432cb022c3bb4e934f7c..31d0e2677a3d15a449100896f544509af4d62f46 100644 |
| --- a/chrome/browser/extensions/extension_event_router.cc |
| +++ b/chrome/browser/extensions/extension_event_router.cc |
| @@ -65,38 +65,18 @@ struct ExtensionEventRouter::ListenerProcess { |
| } |
| }; |
| -struct ExtensionEventRouter::ExtensionEvent { |
| - std::string event_name; |
| - std::string event_args; |
| - GURL event_url; |
| - Profile* restrict_to_profile; |
| - std::string cross_incognito_args; |
| - UserGestureState user_gesture; |
| - |
| - ExtensionEvent(const std::string& event_name, |
| - const std::string& event_args, |
| - const GURL& event_url, |
| - Profile* restrict_to_profile, |
| - const std::string& cross_incognito_args, |
| - UserGestureState user_gesture) |
| - : event_name(event_name), |
| - event_args(event_args), |
| - event_url(event_url), |
| - restrict_to_profile(restrict_to_profile), |
| - cross_incognito_args(cross_incognito_args), |
| - user_gesture(user_gesture) {} |
| -}; |
| - |
| // static |
| void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, |
| const std::string& extension_id, |
| const std::string& event_name, |
| const std::string& event_args, |
| const GURL& event_url, |
| - UserGestureState user_gesture) { |
| + UserGestureState user_gesture, |
| + extensions::EventFilteringInfo info) { |
| ListValue args; |
| args.Set(0, Value::CreateStringValue(event_name)); |
| args.Set(1, Value::CreateStringValue(event_args)); |
| + args.Set(2, Value::CreateStringValue(info.AsJSONString())); |
| ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, |
| extension_id, kDispatchEvent, args, event_url, |
| user_gesture == USER_GESTURE_ENABLED)); |
| @@ -124,9 +104,8 @@ void ExtensionEventRouter::AddEventListener( |
| const std::string& event_name, |
| content::RenderProcessHost* process, |
| const std::string& extension_id) { |
| - ListenerProcess listener(process, extension_id); |
| - DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; |
| - listeners_[event_name].insert(listener); |
| + listeners_.AddListener(scoped_ptr<EventListener>(new EventListener( |
| + event_name, extension_id, process, scoped_ptr<DictionaryValue>()))); |
| if (extension_devtools_manager_.get()) |
| extension_devtools_manager_->AddEventListener(event_name, |
| @@ -144,17 +123,22 @@ void ExtensionEventRouter::RemoveEventListener( |
| const std::string& event_name, |
| content::RenderProcessHost* process, |
| const std::string& extension_id) { |
| - ListenerProcess listener(process, extension_id); |
| - DCHECK_EQ(listeners_[event_name].count(listener), 1u) << |
| - " PID=" << process->GetID() << " extension=" << extension_id << |
| - " event=" << event_name; |
| - listeners_[event_name].erase(listener); |
| - // Note: extension_id may point to data in the now-deleted listeners_ object. |
| - // Do not use. |
| + scoped_ptr<EventListener> listener(new EventListener( |
| + event_name, extension_id, process, scoped_ptr<DictionaryValue>())); |
| + std::string id = extension_id; |
|
Matt Perry
2012/06/13 01:24:27
unused
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + OnListenerRemoved(listener.get()); |
| + listeners_.RemoveListener(listener.Pass()); |
| +} |
| + |
| +void ExtensionEventRouter::OnListenerRemoved(const EventListener* listener) { |
| + // We don't care about lazy events being removed. |
| + if (!listener->process) |
| + return; |
| + const std::string& event_name = listener->event_name; |
| if (extension_devtools_manager_.get()) |
| - extension_devtools_manager_->RemoveEventListener(event_name, |
| - process->GetID()); |
| + extension_devtools_manager_->RemoveEventListener( |
| + event_name, listener->process->GetID()); |
| // If a processes.onUpdated or processes.onUpdatedWithMemory event listener |
| // is removed (or a process with one exits), then we let the extension API |
| @@ -168,14 +152,16 @@ void ExtensionEventRouter::RemoveEventListener( |
| BrowserThread::IO, FROM_HERE, |
| base::Bind( |
| &NotifyEventListenerRemovedOnIOThread, |
| - profile_, listener.extension_id, event_name)); |
| + profile_, listener->extension_id, listener->event_name)); |
| } |
| void ExtensionEventRouter::AddLazyEventListener( |
| const std::string& event_name, |
| const std::string& extension_id) { |
| - ListenerProcess lazy_listener(NULL, extension_id); |
| - bool is_new = lazy_listeners_[event_name].insert(lazy_listener).second; |
| + scoped_ptr<EventListener> listener(new EventListener( |
| + event_name, extension_id, NULL, scoped_ptr<DictionaryValue>())); |
| + bool is_new = listeners_.AddListener(listener.Pass()); |
| + |
| if (is_new) { |
| ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs(); |
| std::set<std::string> events = prefs->GetRegisteredEvents(extension_id); |
| @@ -188,8 +174,10 @@ void ExtensionEventRouter::AddLazyEventListener( |
| void ExtensionEventRouter::RemoveLazyEventListener( |
| const std::string& event_name, |
| const std::string& extension_id) { |
| - ListenerProcess lazy_listener(NULL, extension_id); |
| - bool did_exist = lazy_listeners_[event_name].erase(lazy_listener) > 0; |
| + scoped_ptr<EventListener> listener(new EventListener( |
| + event_name, extension_id, NULL, scoped_ptr<DictionaryValue>())); |
| + bool did_exist = listeners_.RemoveListener(listener.Pass()); |
| + |
| if (did_exist) { |
| ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs(); |
| std::set<std::string> events = prefs->GetRegisteredEvents(extension_id); |
| @@ -199,15 +187,59 @@ void ExtensionEventRouter::RemoveLazyEventListener( |
| } |
| } |
| +void ExtensionEventRouter::AddFilteredEventListener( |
| + const std::string& event_name, |
| + content::RenderProcessHost* process, |
| + const std::string& extension_id, |
| + const base::DictionaryValue& filter, |
| + bool lazy) { |
| + listeners_.AddListener(scoped_ptr<EventListener>(new EventListener( |
| + event_name, extension_id, process, |
| + scoped_ptr<DictionaryValue>(filter.DeepCopy())))); |
| + |
| + if (lazy) { |
| + bool added = listeners_.AddListener(scoped_ptr<EventListener>( |
| + new EventListener(event_name, extension_id, NULL, |
| + scoped_ptr<DictionaryValue>(filter.DeepCopy())))); |
| + |
| + if (added) { |
| + ExtensionPrefs* prefs = |
| + profile_->GetExtensionService()->extension_prefs(); |
| + prefs->AddFilterToEvent(event_name, extension_id, &filter); |
| + } |
| + } |
| +} |
| + |
| +void ExtensionEventRouter::RemoveFilteredEventListener( |
| + const std::string& event_name, |
| + content::RenderProcessHost* process, |
| + const std::string& extension_id, |
| + const base::DictionaryValue& filter, |
| + bool lazy) { |
| + listeners_.RemoveListener(scoped_ptr<EventListener>(new EventListener( |
| + event_name, extension_id, process, |
| + scoped_ptr<DictionaryValue>(filter.DeepCopy())))); |
| + |
| + if (lazy) { |
| + bool removed = listeners_.RemoveListener(scoped_ptr<EventListener>( |
| + new EventListener(event_name, extension_id, NULL, |
| + scoped_ptr<DictionaryValue>(filter.DeepCopy())))); |
| + |
| + if (removed) { |
| + ExtensionPrefs* prefs = |
| + profile_->GetExtensionService()->extension_prefs(); |
| + prefs->RemoveFilterFromEvent(event_name, extension_id, &filter); |
| + } |
| + } |
| +} |
| + |
| bool ExtensionEventRouter::HasEventListener(const std::string& event_name) { |
| - return (HasEventListenerImpl(listeners_, "", event_name) || |
| - HasEventListenerImpl(lazy_listeners_, "", event_name)); |
| + return listeners_.AnyListenersForEvent(event_name); |
| } |
| bool ExtensionEventRouter::ExtensionHasEventListener( |
| const std::string& extension_id, const std::string& event_name) { |
| - return (HasEventListenerImpl(listeners_, extension_id, event_name) || |
| - HasEventListenerImpl(lazy_listeners_, extension_id, event_name)); |
| + return listeners_.AnyListenersForExtension(extension_id, event_name); |
| } |
| bool ExtensionEventRouter::HasEventListenerImpl( |
| @@ -234,10 +266,11 @@ void ExtensionEventRouter::DispatchEventToRenderers( |
| const std::string& event_name, |
| const std::string& event_args, |
| Profile* restrict_to_profile, |
| - const GURL& event_url) { |
| + const GURL& event_url, |
| + extensions::EventFilteringInfo info) { |
| linked_ptr<ExtensionEvent> event( |
| new ExtensionEvent(event_name, event_args, event_url, |
| - restrict_to_profile, "", USER_GESTURE_UNKNOWN)); |
| + restrict_to_profile, "", USER_GESTURE_UNKNOWN, info)); |
| DispatchEventImpl("", event); |
| } |
| @@ -250,7 +283,8 @@ void ExtensionEventRouter::DispatchEventToExtension( |
| DCHECK(!extension_id.empty()); |
| linked_ptr<ExtensionEvent> event( |
| new ExtensionEvent(event_name, event_args, event_url, |
| - restrict_to_profile, "", USER_GESTURE_UNKNOWN)); |
| + restrict_to_profile, "", USER_GESTURE_UNKNOWN, |
| + EventFilteringInfo())); |
| DispatchEventImpl(extension_id, event); |
| } |
| @@ -264,7 +298,8 @@ void ExtensionEventRouter::DispatchEventToExtension( |
| DCHECK(!extension_id.empty()); |
| linked_ptr<ExtensionEvent> event( |
| new ExtensionEvent(event_name, event_args, event_url, |
| - restrict_to_profile, "", user_gesture)); |
| + restrict_to_profile, "", user_gesture, |
| + EventFilteringInfo())); |
| DispatchEventImpl(extension_id, event); |
| } |
| @@ -277,7 +312,7 @@ void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( |
| linked_ptr<ExtensionEvent> event( |
| new ExtensionEvent(event_name, event_args, event_url, |
| restrict_to_profile, cross_incognito_args, |
| - USER_GESTURE_UNKNOWN)); |
| + USER_GESTURE_UNKNOWN, EventFilteringInfo())); |
| DispatchEventImpl("", event); |
| } |
| @@ -288,28 +323,48 @@ void ExtensionEventRouter::DispatchEventImpl( |
| DCHECK(!event->restrict_to_profile || |
| profile_->IsSameProfile(event->restrict_to_profile)); |
| - LoadLazyBackgroundPagesForEvent(extension_id, event); |
| - |
| - ListenerMap::iterator it = listeners_.find(event->event_name); |
| - if (it == listeners_.end()) |
| - return; |
| - |
| - std::set<ListenerProcess>& listeners = it->second; |
| - for (std::set<ListenerProcess>::iterator listener = listeners.begin(); |
| - listener != listeners.end(); ++listener) { |
| - if (!extension_id.empty() && extension_id != listener->extension_id) |
| - continue; |
| + scoped_ptr<std::set<const EventListener*> > listeners( |
| + listeners_.GetEventTargets(*event)); |
| + for (std::set<const EventListener*>::iterator it = listeners->begin(); |
| + it != listeners->end(); it++) { |
| + const EventListener* listener = *it; |
| + if (listener->process) { |
| + if (extension_id.empty() || extension_id == listener->extension_id) |
| + DispatchEventToExtension(listener->extension_id, listener->process, |
| + event); |
| + } else { |
| + DispatchLazyEvent(linked_ptr<EventListener>(listener->Copy().release()), |
| + event); |
| + } |
| + } |
| +} |
| - DispatchEventToListener(*listener, event); |
| +void ExtensionEventRouter::DispatchLazyEvent( |
| + const linked_ptr<EventListener>& listener, |
| + const linked_ptr<ExtensionEvent>& event) { |
| + ExtensionService* service = profile_->GetExtensionService(); |
| + // Check both the original and the incognito profile to see if we |
| + // should load a lazy bg page to handle the event. The latter case |
| + // occurs in the case of split-mode extensions. |
| + const Extension* extension = service->extensions()->GetByID( |
| + listener->extension_id); |
| + if (extension) { |
| + MaybeLoadLazyBackgroundPage(profile_, extension, event, listener); |
| + if (profile_->HasOffTheRecordProfile() && |
| + extension->incognito_split_mode()) { |
| + MaybeLoadLazyBackgroundPage( |
| + profile_->GetOffTheRecordProfile(), extension, event, listener); |
| + } |
| } |
| } |
| -void ExtensionEventRouter::DispatchEventToListener( |
| - const ListenerProcess& listener, |
| +void ExtensionEventRouter::DispatchEventToExtension( |
| + const std::string& extension_id, |
| + content::RenderProcessHost* process, |
| const linked_ptr<ExtensionEvent>& event) { |
| ExtensionService* service = profile_->GetExtensionService(); |
| const Extension* extension = service->extensions()->GetByID( |
| - listener.extension_id); |
| + extension_id); |
| // The extension could have been removed, but we do not unregister it until |
| // the extension process is unloaded. |
| @@ -317,13 +372,13 @@ void ExtensionEventRouter::DispatchEventToListener( |
| return; |
| Profile* listener_profile = Profile::FromBrowserContext( |
| - listener.process->GetBrowserContext()); |
| + process->GetBrowserContext()); |
| extensions::ProcessMap* process_map = |
| listener_profile->GetExtensionService()->process_map(); |
| // If the event is privileged, only send to extension processes. Otherwise, |
| // it's OK to send to normal renderers (e.g., for content scripts). |
| if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) && |
| - !process_map->Contains(extension->id(), listener.process->GetID())) { |
| + !process_map->Contains(extension->id(), process->GetID())) { |
| return; |
| } |
| @@ -332,9 +387,10 @@ void ExtensionEventRouter::DispatchEventToListener( |
| event, &event_args)) |
| return; |
| - DispatchEvent(listener.process, listener.extension_id, |
| + DispatchEvent(process, extension_id, |
| event->event_name, *event_args, |
| - event->event_url, event->user_gesture); |
| + event->event_url, event->user_gesture, |
| + event->info); |
| IncrementInFlightEvents(listener_profile, extension); |
| } |
| @@ -361,41 +417,11 @@ bool ExtensionEventRouter::CanDispatchEventToProfile( |
| return true; |
| } |
| -void ExtensionEventRouter::LoadLazyBackgroundPagesForEvent( |
| - const std::string& extension_id, |
| - const linked_ptr<ExtensionEvent>& event) { |
| - ExtensionService* service = profile_->GetExtensionService(); |
| - |
| - ListenerMap::iterator it = lazy_listeners_.find(event->event_name); |
| - if (it == lazy_listeners_.end()) |
| - return; |
| - |
| - std::set<ListenerProcess>& listeners = it->second; |
| - for (std::set<ListenerProcess>::iterator listener = listeners.begin(); |
| - listener != listeners.end(); ++listener) { |
| - if (!extension_id.empty() && extension_id != listener->extension_id) |
| - continue; |
| - |
| - // Check both the original and the incognito profile to see if we |
| - // should load a lazy bg page to handle the event. The latter case |
| - // occurs in the case of split-mode extensions. |
| - const Extension* extension = service->extensions()->GetByID( |
| - listener->extension_id); |
| - if (extension) { |
| - MaybeLoadLazyBackgroundPage(profile_, extension, event); |
| - if (profile_->HasOffTheRecordProfile() && |
| - extension->incognito_split_mode()) { |
| - MaybeLoadLazyBackgroundPage( |
| - profile_->GetOffTheRecordProfile(), extension, event); |
| - } |
| - } |
| - } |
| -} |
| - |
| void ExtensionEventRouter::MaybeLoadLazyBackgroundPage( |
| Profile* profile, |
| const Extension* extension, |
| - const linked_ptr<ExtensionEvent>& event) { |
| + const linked_ptr<ExtensionEvent>& event, |
| + const linked_ptr<EventListener>& listener) { |
| const std::string* event_args; |
| if (!CanDispatchEventToProfile(profile, extension, event, &event_args)) |
| return; |
| @@ -406,7 +432,7 @@ void ExtensionEventRouter::MaybeLoadLazyBackgroundPage( |
| queue->AddPendingTask( |
| profile, extension->id(), |
| base::Bind(&ExtensionEventRouter::DispatchPendingEvent, |
| - base::Unretained(this), event)); |
| + base::Unretained(this), event, listener)); |
| } |
| } |
| @@ -436,14 +462,15 @@ void ExtensionEventRouter::OnEventAck( |
| } |
| void ExtensionEventRouter::DispatchPendingEvent( |
| - const linked_ptr<ExtensionEvent>& event, ExtensionHost* host) { |
| + const linked_ptr<ExtensionEvent>& event, |
| + const linked_ptr<EventListener>& listener, |
| + ExtensionHost* host) { |
| if (!host) |
| return; |
| - ListenerProcess listener(host->render_process_host(), |
| - host->extension()->id()); |
| - if (listeners_[event->event_name].count(listener) > 0u) |
| - DispatchEventToListener(listener, event); |
| + if (listeners_.HasListener(listener.get())) |
|
Matt Perry
2012/06/13 01:24:27
This is not quite right. IIUC, here |listener| is
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + DispatchEventToExtension(host->extension()->id(), |
| + host->render_process_host(), event); |
| } |
| void ExtensionEventRouter::Observe( |
| @@ -456,19 +483,11 @@ void ExtensionEventRouter::Observe( |
| content::RenderProcessHost* renderer = |
| content::Source<content::RenderProcessHost>(source).ptr(); |
| // Remove all event listeners associated with this renderer. |
| - for (ListenerMap::iterator it = listeners_.begin(); |
| - it != listeners_.end(); ) { |
| - ListenerMap::iterator current_it = it++; |
| - for (std::set<ListenerProcess>::iterator jt = |
| - current_it->second.begin(); |
| - jt != current_it->second.end(); ) { |
| - std::set<ListenerProcess>::iterator current_jt = jt++; |
| - if (current_jt->process == renderer) { |
| - RemoveEventListener(current_it->first, |
| - current_jt->process, |
| - current_jt->extension_id); |
| - } |
| - } |
| + EventListenerMap::ListenerList removed = |
| + listeners_.RemoveListenersForProcess(renderer); |
| + for (EventListenerMap::ListenerList::iterator it = removed.begin(); |
| + it != removed.end(); it++) { |
| + OnListenerRemoved(it->get()); |
| } |
| break; |
| } |
| @@ -476,25 +495,23 @@ void ExtensionEventRouter::Observe( |
| // Add all registered lazy listeners to our cache. |
| const Extension* extension = |
| content::Details<const Extension>(details).ptr(); |
| + ExtensionPrefs* prefs = |
| + profile_->GetExtensionService()->extension_prefs(); |
| std::set<std::string> registered_events = |
| - profile_->GetExtensionService()->extension_prefs()-> |
| - GetRegisteredEvents(extension->id()); |
| - ListenerProcess lazy_listener(NULL, extension->id()); |
| - for (std::set<std::string>::iterator it = registered_events.begin(); |
| - it != registered_events.end(); ++it) { |
| - lazy_listeners_[*it].insert(lazy_listener); |
| - } |
| + prefs->GetRegisteredEvents(extension->id()); |
| + const DictionaryValue* filtered_events = |
| + prefs->GetFilteredEvents(extension->id()); |
| + if (filtered_events) |
| + listeners_.AddLazyListenersFromPreferences(extension->id(), |
| + registered_events, |
|
Matt Perry
2012/06/13 01:24:27
indent
koz (OOO until 15th September)
2012/06/14 02:15:55
Done.
|
| + *filtered_events); |
| break; |
| } |
| case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
|
Matt Perry
2012/06/13 01:24:27
These top 4 notifications should be handled direct
koz (OOO until 15th September)
2012/06/14 02:15:55
I've added the callback for OnListenerRemoved(), b
|
| // Remove all registered lazy listeners from our cache. |
| extensions::UnloadedExtensionInfo* unloaded = |
| content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); |
| - ListenerProcess lazy_listener(NULL, unloaded->extension->id()); |
| - for (ListenerMap::iterator it = lazy_listeners_.begin(); |
| - it != lazy_listeners_.end(); ++it) { |
| - it->second.erase(lazy_listener); |
| - } |
| + listeners_.RemoveLazyListenersFor(unloaded->extension->id()); |
| break; |
| } |
| case chrome::NOTIFICATION_EXTENSION_INSTALLED: { |
| @@ -511,3 +528,23 @@ void ExtensionEventRouter::Observe( |
| return; |
| } |
| } |
| + |
| +ExtensionEvent::ExtensionEvent( |
| + const std::string& event_name, |
| + const std::string& event_args, |
| + const GURL& event_url, |
| + Profile* restrict_to_profile, |
| + const std::string& cross_incognito_args, |
| + ExtensionEventRouter::UserGestureState user_gesture, |
| + const extensions::EventFilteringInfo& info) |
| + : event_name(event_name), |
| + event_args(event_args), |
| + event_url(event_url), |
| + restrict_to_profile(restrict_to_profile), |
| + cross_incognito_args(cross_incognito_args), |
| + user_gesture(user_gesture), |
| + info(info) { |
| +} |
| + |
| +ExtensionEvent::~ExtensionEvent() { |
| +} |