Revert 200220 "Make ExtensionPrefs a ProfileKeyedService."
[chromium-blink-merge.git] / chrome / browser / extensions / event_router.cc
blob130ff5850acf07121a2a31d03bb5aafcc1ea82a8
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/event_router.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/message_loop.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "base/version.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/activity_log.h"
17 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
18 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
19 #include "chrome/browser/extensions/event_names.h"
20 #include "chrome/browser/extensions/extension_host.h"
21 #include "chrome/browser/extensions/extension_prefs.h"
22 #include "chrome/browser/extensions/extension_process_manager.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/extension_system.h"
25 #include "chrome/browser/extensions/lazy_background_task_queue.h"
26 #include "chrome/browser/extensions/process_map.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_manager.h"
29 #include "chrome/common/chrome_notification_types.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/extensions/api/extension_api.h"
32 #include "chrome/common/extensions/background_info.h"
33 #include "chrome/common/extensions/extension.h"
34 #include "chrome/common/extensions/extension_messages.h"
35 #include "chrome/common/extensions/incognito_handler.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/render_process_host.h"
39 using base::Value;
40 using content::BrowserThread;
42 namespace extensions {
44 namespace {
46 const char kDispatchEvent[] = "Event.dispatchEvent";
48 void NotifyEventListenerRemovedOnIOThread(
49 void* profile,
50 const std::string& extension_id,
51 const std::string& sub_event_name) {
52 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
53 profile, extension_id, sub_event_name);
56 void DispatchOnInstalledEvent(
57 Profile* profile,
58 const std::string& extension_id,
59 const Version& old_version,
60 bool chrome_updated) {
61 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
62 return;
64 RuntimeEventRouter::DispatchOnInstalledEvent(profile, extension_id,
65 old_version, chrome_updated);
68 void DoNothing(ExtensionHost* host) {}
70 } // namespace
72 struct EventRouter::ListenerProcess {
73 content::RenderProcessHost* process;
74 std::string extension_id;
76 ListenerProcess(content::RenderProcessHost* process,
77 const std::string& extension_id)
78 : process(process), extension_id(extension_id) {}
80 bool operator<(const ListenerProcess& that) const {
81 if (process < that.process)
82 return true;
83 if (process == that.process && extension_id < that.extension_id)
84 return true;
85 return false;
89 // static
90 void EventRouter::LogExtensionEventMessage(void* profile_id,
91 const std::string& extension_id,
92 const std::string& event_name,
93 scoped_ptr<ListValue> event_args) {
94 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
95 BrowserThread::PostTask(BrowserThread::UI,
96 FROM_HERE,
97 base::Bind(&LogExtensionEventMessage,
98 profile_id,
99 extension_id,
100 event_name,
101 base::Passed(&event_args)));
102 } else {
103 Profile* profile = reinterpret_cast<Profile*>(profile_id);
104 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
105 return;
107 // An ExtensionService might not be running during unit tests, or an
108 // extension might have been unloaded by the time we get to logging it. In
109 // those cases log a warning.
110 ExtensionService* extension_service =
111 ExtensionSystem::Get(profile)->extension_service();
112 if (!extension_service) {
113 LOG(WARNING) << "ExtensionService does not seem to be available "
114 << "(this may be normal for unit tests)";
115 } else {
116 const Extension* extension =
117 extension_service->extensions()->GetByID(extension_id);
118 if (!extension) {
119 LOG(WARNING) << "Extension " << extension_id << " not found!";
120 } else {
121 ActivityLog::GetInstance(profile)->LogEventAction(
122 extension, event_name, event_args.get(), std::string());
128 // static
129 void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
130 void* profile_id,
131 const std::string& extension_id,
132 const std::string& event_name,
133 ListValue* event_args,
134 const GURL& event_url,
135 UserGestureState user_gesture,
136 const EventFilteringInfo& info) {
137 if (ActivityLog::IsLogEnabled()) {
138 LogExtensionEventMessage(profile_id, extension_id, event_name,
139 scoped_ptr<ListValue>(event_args->DeepCopy()));
142 ListValue args;
143 args.Set(0, Value::CreateStringValue(event_name));
144 args.Set(1, event_args);
145 args.Set(2, info.AsValue().release());
146 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
147 extension_id, kDispatchEvent, args, event_url,
148 user_gesture == USER_GESTURE_ENABLED));
150 // DispatchExtensionMessage does _not_ take ownership of event_args, so we
151 // must ensure that the destruction of args does not attempt to free it.
152 Value* removed_event_args = NULL;
153 args.Remove(1, &removed_event_args);
156 // static
157 void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
158 void* profile_id,
159 const std::string& extension_id,
160 const std::string& event_name,
161 scoped_ptr<ListValue> event_args,
162 const GURL& event_url,
163 UserGestureState user_gesture,
164 const EventFilteringInfo& info) {
165 DispatchExtensionMessage(ipc_sender, profile_id, extension_id, event_name,
166 event_args.get(), event_url, user_gesture, info);
169 EventRouter::EventRouter(Profile* profile, ExtensionPrefs* extension_prefs)
170 : profile_(profile),
171 listeners_(this),
172 activity_log_(ActivityLog::GetInstance(profile)),
173 dispatch_chrome_updated_event_(false) {
174 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
175 content::NotificationService::AllSources());
176 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
177 content::NotificationService::AllSources());
178 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
179 content::Source<Profile>(profile_));
180 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
181 content::Source<Profile>(profile_));
182 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
183 content::Source<Profile>(profile_));
184 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
185 content::Source<Profile>(profile_));
186 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
187 content::Source<Profile>(profile_));
189 // NULL in unit_tests.
190 if (extension_prefs) {
191 // Check if registered events are up-to-date. We can only do this once
192 // per profile, since it updates internal state when called.
193 dispatch_chrome_updated_event_ =
194 !extension_prefs->CheckRegisteredEventsUpToDate();
198 EventRouter::~EventRouter() {}
200 void EventRouter::AddEventListener(const std::string& event_name,
201 content::RenderProcessHost* process,
202 const std::string& extension_id) {
203 listeners_.AddListener(scoped_ptr<EventListener>(new EventListener(
204 event_name, extension_id, process, scoped_ptr<DictionaryValue>())));
207 void EventRouter::RemoveEventListener(const std::string& event_name,
208 content::RenderProcessHost* process,
209 const std::string& extension_id) {
210 EventListener listener(event_name, extension_id, process,
211 scoped_ptr<DictionaryValue>());
212 listeners_.RemoveListener(&listener);
215 void EventRouter::RegisterObserver(Observer* observer,
216 const std::string& event_name) {
217 observers_[event_name] = observer;
220 void EventRouter::UnregisterObserver(Observer* observer) {
221 std::vector<ObserverMap::iterator> iters_to_remove;
222 for (ObserverMap::iterator iter = observers_.begin();
223 iter != observers_.end(); ++iter) {
224 if (iter->second == observer)
225 iters_to_remove.push_back(iter);
227 for (size_t i = 0; i < iters_to_remove.size(); ++i)
228 observers_.erase(iters_to_remove[i]);
231 void EventRouter::OnListenerAdded(const EventListener* listener) {
232 const std::string& event_name = listener->event_name;
233 const EventListenerInfo details(event_name, listener->extension_id);
234 ObserverMap::iterator observer = observers_.find(event_name);
235 if (observer != observers_.end())
236 observer->second->OnListenerAdded(details);
238 #if 0
239 // TODO(felt): Experimentally determine if these are needed, or if they
240 // can be permanently removed. Temporarily removing for now to reduce log
241 // size while under investigation.
242 const Extension* extension = ExtensionSystem::Get(profile_)->
243 extension_service()->GetExtensionById(listener->extension_id,
244 ExtensionService::INCLUDE_ENABLED);
245 if (extension) {
246 scoped_ptr<ListValue> args(new ListValue());
247 if (listener->filter)
248 args->Append(listener->filter->DeepCopy());
249 activity_log_->LogAPIAction(
250 extension, event_name + ".addListener", args.get(), std::string());
252 #endif
255 void EventRouter::OnListenerRemoved(const EventListener* listener) {
256 const std::string& event_name = listener->event_name;
257 const EventListenerInfo details(event_name, listener->extension_id);
258 ObserverMap::iterator observer = observers_.find(event_name);
259 if (observer != observers_.end())
260 observer->second->OnListenerRemoved(details);
262 void* profile =
263 listener->process
264 ? Profile::FromBrowserContext(listener->process->GetBrowserContext())
265 : NULL;
266 BrowserThread::PostTask(
267 BrowserThread::IO, FROM_HERE,
268 base::Bind(&NotifyEventListenerRemovedOnIOThread,
269 profile, listener->extension_id, event_name));
270 #if 0
271 // TODO(felt): Experimentally determine if these are needed, or if they
272 // can be permanently removed. Temporarily removing for now to reduce log
273 // size while under investigation.
274 const Extension* extension = ExtensionSystem::Get(profile_)->
275 extension_service()->GetExtensionById(listener->extension_id,
276 ExtensionService::INCLUDE_ENABLED);
277 if (extension) {
278 scoped_ptr<ListValue> args(new ListValue());
279 activity_log_->LogAPIAction(
280 extension, event_name + ".removeListener", args.get(), std::string());
282 #endif
285 void EventRouter::AddLazyEventListener(const std::string& event_name,
286 const std::string& extension_id) {
287 scoped_ptr<EventListener> listener(new EventListener(
288 event_name, extension_id, NULL, scoped_ptr<DictionaryValue>()));
289 bool is_new = listeners_.AddListener(listener.Pass());
291 if (is_new) {
292 ExtensionPrefs* prefs = ExtensionSystem::Get(profile_)->extension_prefs();
293 std::set<std::string> events = prefs->GetRegisteredEvents(extension_id);
294 bool prefs_is_new = events.insert(event_name).second;
295 if (prefs_is_new)
296 prefs->SetRegisteredEvents(extension_id, events);
300 void EventRouter::RemoveLazyEventListener(const std::string& event_name,
301 const std::string& extension_id) {
302 EventListener listener(event_name, extension_id, NULL,
303 scoped_ptr<DictionaryValue>());
304 bool did_exist = listeners_.RemoveListener(&listener);
306 if (did_exist) {
307 ExtensionPrefs* prefs = ExtensionSystem::Get(profile_)->extension_prefs();
308 std::set<std::string> events = prefs->GetRegisteredEvents(extension_id);
309 bool prefs_did_exist = events.erase(event_name) > 0;
310 DCHECK(prefs_did_exist);
311 prefs->SetRegisteredEvents(extension_id, events);
315 void EventRouter::AddFilteredEventListener(const std::string& event_name,
316 content::RenderProcessHost* process,
317 const std::string& extension_id,
318 const base::DictionaryValue& filter,
319 bool add_lazy_listener) {
320 listeners_.AddListener(scoped_ptr<EventListener>(new EventListener(
321 event_name, extension_id, process,
322 scoped_ptr<DictionaryValue>(filter.DeepCopy()))));
324 if (add_lazy_listener) {
325 bool added = listeners_.AddListener(scoped_ptr<EventListener>(
326 new EventListener(event_name, extension_id, NULL,
327 scoped_ptr<DictionaryValue>(filter.DeepCopy()))));
329 if (added) {
330 ExtensionPrefs* prefs = ExtensionSystem::Get(profile_)->extension_prefs();
331 prefs->AddFilterToEvent(event_name, extension_id, &filter);
336 void EventRouter::RemoveFilteredEventListener(
337 const std::string& event_name,
338 content::RenderProcessHost* process,
339 const std::string& extension_id,
340 const base::DictionaryValue& filter,
341 bool remove_lazy_listener) {
342 EventListener listener(event_name, extension_id, process,
343 scoped_ptr<DictionaryValue>(filter.DeepCopy()));
345 listeners_.RemoveListener(&listener);
347 if (remove_lazy_listener) {
348 listener.process = NULL;
349 bool removed = listeners_.RemoveListener(&listener);
351 if (removed) {
352 ExtensionPrefs* prefs = ExtensionSystem::Get(profile_)->extension_prefs();
353 prefs->RemoveFilterFromEvent(event_name, extension_id, &filter);
358 bool EventRouter::HasEventListener(const std::string& event_name) {
359 return listeners_.HasListenerForEvent(event_name);
362 bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
363 const std::string& event_name) {
364 return listeners_.HasListenerForExtension(extension_id, event_name);
367 bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map,
368 const std::string& extension_id,
369 const std::string& event_name) {
370 ListenerMap::const_iterator it = listener_map.find(event_name);
371 if (it == listener_map.end())
372 return false;
374 const std::set<ListenerProcess>& listeners = it->second;
375 if (extension_id.empty())
376 return !listeners.empty();
378 for (std::set<ListenerProcess>::const_iterator listener = listeners.begin();
379 listener != listeners.end(); ++listener) {
380 if (listener->extension_id == extension_id)
381 return true;
383 return false;
386 void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
387 DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
390 void EventRouter::DispatchEventToExtension(const std::string& extension_id,
391 scoped_ptr<Event> event) {
392 DCHECK(!extension_id.empty());
393 DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
396 void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
397 const linked_ptr<Event>& event) {
398 // We don't expect to get events from a completely different profile.
399 DCHECK(!event->restrict_to_profile ||
400 profile_->IsSameProfile(event->restrict_to_profile));
402 std::set<const EventListener*> listeners(
403 listeners_.GetEventListeners(*event));
405 std::set<EventDispatchIdentifier> already_dispatched;
407 // We dispatch events for lazy background pages first because attempting to do
408 // so will cause those that are being suspended to cancel that suspension.
409 // As canceling a suspension entails sending an event to the affected
410 // background page, and as that event needs to be delivered before we dispatch
411 // the event we are dispatching here, we dispatch to the lazy listeners here
412 // first.
413 for (std::set<const EventListener*>::iterator it = listeners.begin();
414 it != listeners.end(); it++) {
415 const EventListener* listener = *it;
416 if (restrict_to_extension_id.empty() ||
417 restrict_to_extension_id == listener->extension_id) {
418 if (!listener->process) {
419 DispatchLazyEvent(listener->extension_id, event, &already_dispatched);
424 for (std::set<const EventListener*>::iterator it = listeners.begin();
425 it != listeners.end(); it++) {
426 const EventListener* listener = *it;
427 if (restrict_to_extension_id.empty() ||
428 restrict_to_extension_id == listener->extension_id) {
429 if (listener->process) {
430 EventDispatchIdentifier dispatch_id(
431 listener->process->GetBrowserContext(), listener->extension_id);
432 if (!ContainsKey(already_dispatched, dispatch_id)) {
433 DispatchEventToProcess(listener->extension_id, listener->process,
434 event);
441 void EventRouter::DispatchLazyEvent(
442 const std::string& extension_id,
443 const linked_ptr<Event>& event,
444 std::set<EventDispatchIdentifier>* already_dispatched) {
445 ExtensionService* service =
446 ExtensionSystem::Get(profile_)->extension_service();
447 // Check both the original and the incognito profile to see if we
448 // should load a lazy bg page to handle the event. The latter case
449 // occurs in the case of split-mode extensions.
450 const Extension* extension = service->extensions()->GetByID(extension_id);
451 if (extension) {
452 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
453 profile_, extension, event)) {
454 already_dispatched->insert(std::make_pair(profile_, extension_id));
457 if (profile_->HasOffTheRecordProfile() &&
458 IncognitoInfo::IsSplitMode(extension)) {
459 if (MaybeLoadLazyBackgroundPageToDispatchEvent(
460 profile_->GetOffTheRecordProfile(), extension, event)) {
461 already_dispatched->insert(
462 std::make_pair(profile_->GetOffTheRecordProfile(), extension_id));
468 void EventRouter::DispatchEventToProcess(const std::string& extension_id,
469 content::RenderProcessHost* process,
470 const linked_ptr<Event>& event) {
471 ExtensionService* service =
472 ExtensionSystem::Get(profile_)->extension_service();
473 const Extension* extension = service->extensions()->GetByID(extension_id);
475 // The extension could have been removed, but we do not unregister it until
476 // the extension process is unloaded.
477 if (!extension)
478 return;
480 Profile* listener_profile = Profile::FromBrowserContext(
481 process->GetBrowserContext());
482 ProcessMap* process_map = ExtensionSystem::Get(listener_profile)->
483 extension_service()->process_map();
484 // If the event is privileged, only send to extension processes. Otherwise,
485 // it's OK to send to normal renderers (e.g., for content scripts).
486 if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) &&
487 !process_map->Contains(extension->id(), process->GetID())) {
488 return;
491 if (!CanDispatchEventToProfile(listener_profile, extension, event))
492 return;
494 if (!event->will_dispatch_callback.is_null()) {
495 event->will_dispatch_callback.Run(listener_profile, extension,
496 event->event_args.get());
499 DispatchExtensionMessage(process, listener_profile, extension_id,
500 event->event_name, event->event_args.get(),
501 event->event_url, event->user_gesture,
502 event->filter_info);
503 IncrementInFlightEvents(listener_profile, extension);
506 bool EventRouter::CanDispatchEventToProfile(Profile* profile,
507 const Extension* extension,
508 const linked_ptr<Event>& event) {
509 // Is this event from a different profile than the renderer (ie, an
510 // incognito tab event sent to a normal process, or vice versa).
511 bool cross_incognito =
512 event->restrict_to_profile && profile != event->restrict_to_profile;
513 if (cross_incognito &&
514 !ExtensionSystem::Get(profile)->extension_service()->
515 CanCrossIncognito(extension)) {
516 return false;
519 return true;
522 bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
523 Profile* profile,
524 const Extension* extension,
525 const linked_ptr<Event>& event) {
526 if (!CanDispatchEventToProfile(profile, extension, event))
527 return false;
529 LazyBackgroundTaskQueue* queue =
530 ExtensionSystem::Get(profile)->lazy_background_task_queue();
531 if (queue->ShouldEnqueueTask(profile, extension)) {
532 linked_ptr<Event> dispatched_event(event);
534 // If there's a dispatch callback, call it now (rather than dispatch time)
535 // to avoid lifetime issues. Use a separate copy of the event args, so they
536 // last until the event is dispatched.
537 if (!event->will_dispatch_callback.is_null()) {
538 dispatched_event.reset(event->DeepCopy());
539 dispatched_event->will_dispatch_callback.Run(
540 profile, extension, dispatched_event->event_args.get());
541 // Ensure we don't call it again at dispatch time.
542 dispatched_event->will_dispatch_callback.Reset();
545 queue->AddPendingTask(profile, extension->id(),
546 base::Bind(&EventRouter::DispatchPendingEvent,
547 base::Unretained(this), dispatched_event));
548 return true;
551 return false;
554 void EventRouter::IncrementInFlightEvents(Profile* profile,
555 const Extension* extension) {
556 // Only increment in-flight events if the lazy background page is active,
557 // because that's the only time we'll get an ACK.
558 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
559 ExtensionProcessManager* pm =
560 ExtensionSystem::Get(profile)->process_manager();
561 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
562 if (host)
563 pm->IncrementLazyKeepaliveCount(extension);
567 void EventRouter::OnEventAck(Profile* profile,
568 const std::string& extension_id) {
569 ExtensionProcessManager* pm =
570 ExtensionSystem::Get(profile)->process_manager();
571 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
572 // The event ACK is routed to the background host, so this should never be
573 // NULL.
574 CHECK(host);
575 // TODO(mpcomplete): We should never get this message unless
576 // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
577 if (host->extension() &&
578 BackgroundInfo::HasLazyBackgroundPage(host->extension()))
579 pm->DecrementLazyKeepaliveCount(host->extension());
582 void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
583 ExtensionHost* host) {
584 if (!host)
585 return;
587 if (listeners_.HasProcessListener(host->render_process_host(),
588 host->extension()->id())) {
589 DispatchEventToProcess(host->extension()->id(),
590 host->render_process_host(), event);
594 void EventRouter::Observe(int type,
595 const content::NotificationSource& source,
596 const content::NotificationDetails& details) {
597 switch (type) {
598 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
599 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
600 content::RenderProcessHost* renderer =
601 content::Source<content::RenderProcessHost>(source).ptr();
602 // Remove all event listeners associated with this renderer.
603 listeners_.RemoveListenersForProcess(renderer);
604 break;
606 case chrome::NOTIFICATION_EXTENSIONS_READY: {
607 // We're done restarting Chrome after an update.
608 dispatch_chrome_updated_event_ = false;
609 break;
611 case chrome::NOTIFICATION_EXTENSION_ENABLED: {
612 // If the extension has a lazy background page, make sure it gets loaded
613 // to register the events the extension is interested in.
614 const Extension* extension =
615 content::Details<const Extension>(details).ptr();
616 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
617 LazyBackgroundTaskQueue* queue =
618 ExtensionSystem::Get(profile_)->lazy_background_task_queue();
619 queue->AddPendingTask(profile_, extension->id(),
620 base::Bind(&DoNothing));
622 break;
624 case chrome::NOTIFICATION_EXTENSION_LOADED: {
625 // Add all registered lazy listeners to our cache.
626 const Extension* extension =
627 content::Details<const Extension>(details).ptr();
628 ExtensionPrefs* prefs = ExtensionSystem::Get(profile_)->extension_prefs();
629 std::set<std::string> registered_events =
630 prefs->GetRegisteredEvents(extension->id());
631 listeners_.LoadUnfilteredLazyListeners(extension->id(),
632 registered_events);
633 const DictionaryValue* filtered_events =
634 prefs->GetFilteredEvents(extension->id());
635 if (filtered_events)
636 listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
638 if (dispatch_chrome_updated_event_) {
639 MessageLoop::current()->PostTask(FROM_HERE,
640 base::Bind(&DispatchOnInstalledEvent, profile_, extension->id(),
641 Version(), true));
643 break;
645 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
646 // Remove all registered lazy listeners from our cache.
647 UnloadedExtensionInfo* unloaded =
648 content::Details<UnloadedExtensionInfo>(details).ptr();
649 listeners_.RemoveLazyListenersForExtension(unloaded->extension->id());
650 break;
652 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
653 // Dispatch the onInstalled event.
654 const Extension* extension =
655 content::Details<const InstalledExtensionInfo>(details)->extension;
657 // Get the previous version, if this is an upgrade.
658 ExtensionService* service =
659 ExtensionSystem::Get(profile_)->extension_service();
660 const Extension* old = service->GetExtensionById(extension->id(), true);
661 Version old_version;
662 if (old)
663 old_version = *old->version();
665 MessageLoop::current()->PostTask(FROM_HERE,
666 base::Bind(&DispatchOnInstalledEvent, profile_, extension->id(),
667 old_version, false));
668 break;
670 default:
671 NOTREACHED();
672 return;
676 Event::Event(const std::string& event_name,
677 scoped_ptr<base::ListValue> event_args)
678 : event_name(event_name),
679 event_args(event_args.Pass()),
680 restrict_to_profile(NULL),
681 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
682 DCHECK(this->event_args.get());
685 Event::Event(const std::string& event_name,
686 scoped_ptr<base::ListValue> event_args,
687 Profile* restrict_to_profile)
688 : event_name(event_name),
689 event_args(event_args.Pass()),
690 restrict_to_profile(restrict_to_profile),
691 user_gesture(EventRouter::USER_GESTURE_UNKNOWN) {
692 DCHECK(this->event_args.get());
695 Event::Event(const std::string& event_name,
696 scoped_ptr<ListValue> event_args,
697 Profile* restrict_to_profile,
698 const GURL& event_url,
699 EventRouter::UserGestureState user_gesture,
700 const EventFilteringInfo& filter_info)
701 : event_name(event_name),
702 event_args(event_args.Pass()),
703 restrict_to_profile(restrict_to_profile),
704 event_url(event_url),
705 user_gesture(user_gesture),
706 filter_info(filter_info) {
707 DCHECK(this->event_args.get());
710 Event::~Event() {}
712 Event* Event::DeepCopy() {
713 Event* copy = new Event(event_name,
714 scoped_ptr<base::ListValue>(event_args->DeepCopy()),
715 restrict_to_profile,
716 event_url,
717 user_gesture,
718 filter_info);
719 copy->will_dispatch_callback = will_dispatch_callback;
720 return copy;
723 EventListenerInfo::EventListenerInfo(const std::string& event_name,
724 const std::string& extension_id)
725 : event_name(event_name),
726 extension_id(extension_id) {}
728 } // namespace extensions