event_router.cc revision 010d83a9304c5a91596085d917d248abff47903a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
11ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/api_activity_monitor.h"
1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_host.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/browser/lazy_background_task_queue.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/process_manager.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/process_map.h"
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "extensions/common/extension_api.h"
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/extension_messages.h"
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "extensions/common/extension_urls.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/background_info.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/incognito_info.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using base::DictionaryValue;
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using base::ListValue;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using content::BrowserContext;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void DoNothing(ExtensionHost* host) {}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// A dictionary of event names to lists of filters that this extension has
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// registered from its lazy background page.
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kFilteredEvents[] = "filtered_events";
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Sends a notification about an event to the API activity monitor on the
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// UI thread. Can be called from any thread.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NotifyApiEventDispatched(void* browser_context_id,
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const std::string& extension_id,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              const std::string& event_name,
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              scoped_ptr<ListValue> args) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The ApiActivityMonitor can only be accessed from the UI thread.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserThread::PostTask(
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BrowserThread::UI,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&NotifyApiEventDispatched,
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   browser_context_id,
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   extension_id,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   event_name,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Passed(&args)));
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Notify the ApiActivityMonitor about the event dispatch.
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserContext* context = static_cast<BrowserContext*>(browser_context_id);
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ExtensionsBrowserClient::Get()->IsValidContext(context))
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ApiActivityMonitor* monitor =
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionsBrowserClient::Get()->GetApiActivityMonitor(context);
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (monitor)
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    monitor->OnApiEventDispatched(extension_id, event_name, args.Pass());
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char EventRouter::kRegisteredEvents[] = "events";
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct EventRouter::ListenerProcess {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::RenderProcessHost* process;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string extension_id;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListenerProcess(content::RenderProcessHost* process,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const std::string& extension_id)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : process(process), extension_id(extension_id) {}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator<(const ListenerProcess& that) const {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (process < that.process)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (process == that.process && extension_id < that.extension_id)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                           void* browser_context_id,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::string& extension_id,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::string& event_name,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           ListValue* event_args,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           UserGestureState user_gesture,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const EventFilteringInfo& info) {
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NotifyApiEventDispatched(browser_context_id,
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           extension_id,
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           event_name,
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           make_scoped_ptr(event_args->DeepCopy()));
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListValue args;
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  args.Set(0, new base::StringValue(event_name));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.Set(1, event_args);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.Set(2, info.AsValue().release());
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ipc_sender->Send(new ExtensionMsg_MessageInvoke(
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      MSG_ROUTING_CONTROL,
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_id,
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      kEventBindings,
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      "dispatchEvent",
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      args,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_gesture == USER_GESTURE_ENABLED));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DispatchExtensionMessage does _not_ take ownership of event_args, so we
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // must ensure that the destruction of args does not attempt to free it.
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> removed_event_args;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args.Remove(1, &removed_event_args);
1273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  ignore_result(removed_event_args.release());
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
131effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochEventRouter* EventRouter::Get(content::BrowserContext* browser_context) {
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return ExtensionSystem::Get(browser_context)->event_router();
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string EventRouter::GetBaseEventName(const std::string& full_event_name) {
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  size_t slash_sep = full_event_name.find('/');
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return full_event_name.substr(0, slash_sep);
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchEvent(IPC::Sender* ipc_sender,
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                void* browser_context_id,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& extension_id,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& event_name,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                scoped_ptr<ListValue> event_args,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                UserGestureState user_gesture,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const EventFilteringInfo& info) {
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DispatchExtensionMessage(ipc_sender,
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           browser_context_id,
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           extension_id,
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           event_name,
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           event_args.get(),
154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           user_gesture,
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           info);
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  BrowserThread::PostTask(
15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      BrowserThread::UI,
15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      FROM_HERE,
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&EventRouter::IncrementInFlightEventsOnUI,
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                  browser_context_id,
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                  extension_id));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)EventRouter::EventRouter(BrowserContext* browser_context,
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         ExtensionPrefs* extension_prefs)
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : browser_context_(browser_context),
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_prefs_(extension_prefs),
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      listeners_(this) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllSources());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllSources());
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_ENABLED,
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 content::Source<BrowserContext>(browser_context_));
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  registrar_.Add(this,
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 content::Source<BrowserContext>(browser_context_));
17923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 content::Source<BrowserContext>(browser_context_));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EventRouter::~EventRouter() {}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::AddEventListener(const std::string& event_name,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   content::RenderProcessHost* process,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& extension_id) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners_.AddListener(scoped_ptr<EventListener>(new EventListener(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_name, extension_id, process, scoped_ptr<DictionaryValue>())));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::RemoveEventListener(const std::string& event_name,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      content::RenderProcessHost* process,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& extension_id) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EventListener listener(event_name, extension_id, process,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         scoped_ptr<DictionaryValue>());
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners_.RemoveListener(&listener);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::RegisterObserver(Observer* observer,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& event_name) {
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Observing sub-event names like "foo.onBar/123" is not allowed.
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(event_name.find('/') == std::string::npos);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_[event_name] = observer;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::UnregisterObserver(Observer* observer) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<ObserverMap::iterator> iters_to_remove;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ObserverMap::iterator iter = observers_.begin();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != observers_.end(); ++iter) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->second == observer)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iters_to_remove.push_back(iter);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < iters_to_remove.size(); ++i)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observers_.erase(iters_to_remove[i]);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::OnListenerAdded(const EventListener* listener) {
219010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const EventListenerInfo details(listener->event_name(),
220010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  listener->extension_id(),
221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  listener->GetBrowserContext());
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::string base_event_name = GetBaseEventName(listener->event_name());
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ObserverMap::iterator observer = observers_.find(base_event_name);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer != observers_.end())
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    observer->second->OnListenerAdded(details);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::OnListenerRemoved(const EventListener* listener) {
229010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const EventListenerInfo details(listener->event_name(),
230010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  listener->extension_id(),
231010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  listener->GetBrowserContext());
232010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::string base_event_name = GetBaseEventName(listener->event_name());
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ObserverMap::iterator observer = observers_.find(base_event_name);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (observer != observers_.end())
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    observer->second->OnListenerRemoved(details);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::AddLazyEventListener(const std::string& event_name,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& extension_id) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<EventListener> listener(new EventListener(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_name, extension_id, NULL, scoped_ptr<DictionaryValue>()));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_new = listeners_.AddListener(listener.Pass());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_new) {
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::set<std::string> events = GetRegisteredEvents(extension_id);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool prefs_is_new = events.insert(event_name).second;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (prefs_is_new)
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SetRegisteredEvents(extension_id, events);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::RemoveLazyEventListener(const std::string& event_name,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const std::string& extension_id) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EventListener listener(event_name, extension_id, NULL,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         scoped_ptr<DictionaryValue>());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool did_exist = listeners_.RemoveListener(&listener);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (did_exist) {
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::set<std::string> events = GetRegisteredEvents(extension_id);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool prefs_did_exist = events.erase(event_name) > 0;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(prefs_did_exist);
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SetRegisteredEvents(extension_id, events);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::AddFilteredEventListener(const std::string& event_name,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           content::RenderProcessHost* process,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const std::string& extension_id,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const base::DictionaryValue& filter,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           bool add_lazy_listener) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners_.AddListener(scoped_ptr<EventListener>(new EventListener(
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_name, extension_id, process,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<DictionaryValue>(filter.DeepCopy()))));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (add_lazy_listener) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool added = listeners_.AddListener(scoped_ptr<EventListener>(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new EventListener(event_name, extension_id, NULL,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scoped_ptr<DictionaryValue>(filter.DeepCopy()))));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (added)
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      AddFilterToEvent(event_name, extension_id, &filter);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::RemoveFilteredEventListener(
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& event_name,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderProcessHost* process,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue& filter,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool remove_lazy_listener) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EventListener listener(event_name, extension_id, process,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         scoped_ptr<DictionaryValue>(filter.DeepCopy()));
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners_.RemoveListener(&listener);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (remove_lazy_listener) {
297010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    listener.MakeLazy();
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool removed = listeners_.RemoveListener(&listener);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (removed)
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RemoveFilterFromEvent(event_name, extension_id, &filter);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EventRouter::HasEventListener(const std::string& event_name) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return listeners_.HasListenerForEvent(event_name);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EventRouter::ExtensionHasEventListener(const std::string& extension_id,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const std::string& event_name) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return listeners_.HasListenerForExtension(extension_id, event_name);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EventRouter::HasEventListenerImpl(const ListenerMap& listener_map,
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& extension_id,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& event_name) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListenerMap::const_iterator it = listener_map.find(event_name);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == listener_map.end())
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::set<ListenerProcess>& listeners = it->second;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension_id.empty())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !listeners.empty();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<ListenerProcess>::const_iterator listener = listeners.begin();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       listener != listeners.end(); ++listener) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (listener->extension_id == extension_id)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::set<std::string> EventRouter::GetRegisteredEvents(
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id) {
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::set<std::string> events;
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const ListValue* events_value = NULL;
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!extension_prefs_ ||
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !extension_prefs_->ReadPrefAsList(
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           extension_id, kRegisteredEvents, &events_value)) {
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return events;
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < events_value->GetSize(); ++i) {
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string event;
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (events_value->GetString(i, &event))
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      events.insert(event);
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return events;
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EventRouter::SetRegisteredEvents(const std::string& extension_id,
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                      const std::set<std::string>& events) {
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ListValue* events_value = new ListValue;
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (std::set<std::string>::const_iterator iter = events.begin();
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       iter != events.end(); ++iter) {
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    events_value->Append(new base::StringValue(*iter));
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  extension_prefs_->UpdateExtensionPref(
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_id, kRegisteredEvents, events_value);
36190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
36390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EventRouter::AddFilterToEvent(const std::string& event_name,
36490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   const std::string& extension_id,
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   const DictionaryValue* filter) {
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs::ScopedDictionaryUpdate update(
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_prefs_, extension_id, kFilteredEvents);
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DictionaryValue* filtered_events = update.Get();
36990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!filtered_events)
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    filtered_events = update.Create();
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ListValue* filter_list = NULL;
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!filtered_events->GetList(event_name, &filter_list)) {
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    filter_list = new ListValue;
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    filtered_events->SetWithoutPathExpansion(event_name, filter_list);
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  filter_list->Append(filter->DeepCopy());
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
38090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EventRouter::RemoveFilterFromEvent(const std::string& event_name,
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                        const std::string& extension_id,
38390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                        const DictionaryValue* filter) {
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionPrefs::ScopedDictionaryUpdate update(
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_prefs_, extension_id, kFilteredEvents);
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DictionaryValue* filtered_events = update.Get();
38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ListValue* filter_list = NULL;
38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!filtered_events ||
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      !filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) {
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < filter_list->GetSize(); i++) {
39490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DictionaryValue* filter = NULL;
39590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CHECK(filter_list->GetDictionary(i, &filter));
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (filter->Equals(filter)) {
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      filter_list->Remove(i, NULL);
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
40090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const DictionaryValue* EventRouter::GetFilteredEvents(
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id) {
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const DictionaryValue* events = NULL;
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  extension_prefs_->ReadPrefAsDictionary(
40790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      extension_id, kFilteredEvents, &events);
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return events;
40990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
41090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void EventRouter::BroadcastEvent(scoped_ptr<Event> event) {
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DispatchEventImpl(std::string(), linked_ptr<Event>(event.release()));
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchEventToExtension(const std::string& extension_id,
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           scoped_ptr<Event> event) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!extension_id.empty());
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DispatchEventImpl(extension_id, linked_ptr<Event>(event.release()));
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
421ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid EventRouter::DispatchEventWithLazyListener(const std::string& extension_id,
422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                scoped_ptr<Event> event) {
423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(!extension_id.empty());
424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::string event_name = event->event_name;
425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool has_listener = ExtensionHasEventListener(extension_id, event_name);
426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!has_listener)
427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    AddLazyEventListener(event_name, extension_id);
428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DispatchEventToExtension(extension_id, event.Pass());
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!has_listener)
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    RemoveLazyEventListener(event_name, extension_id);
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchEventImpl(const std::string& restrict_to_extension_id,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const linked_ptr<Event>& event) {
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // We don't expect to get events from a completely different browser context.
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!event->restrict_to_browser_context ||
437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         ExtensionsBrowserClient::Get()->IsSameContext(
438f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             browser_context_, event->restrict_to_browser_context));
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<const EventListener*> listeners(
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listeners_.GetEventListeners(*event));
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<EventDispatchIdentifier> already_dispatched;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We dispatch events for lazy background pages first because attempting to do
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so will cause those that are being suspended to cancel that suspension.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As canceling a suspension entails sending an event to the affected
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // background page, and as that event needs to be delivered before we dispatch
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the event we are dispatching here, we dispatch to the lazy listeners here
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // first.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<const EventListener*>::iterator it = listeners.begin();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != listeners.end(); it++) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const EventListener* listener = *it;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (restrict_to_extension_id.empty() ||
455010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        restrict_to_extension_id == listener->extension_id()) {
456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (listener->IsLazy()) {
457010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        DispatchLazyEvent(listener->extension_id(), event, &already_dispatched);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<const EventListener*>::iterator it = listeners.begin();
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != listeners.end(); it++) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const EventListener* listener = *it;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (restrict_to_extension_id.empty() ||
466010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        restrict_to_extension_id == listener->extension_id()) {
467010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (listener->process()) {
468010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        EventDispatchIdentifier dispatch_id(listener->GetBrowserContext(),
469010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                            listener->extension_id());
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!ContainsKey(already_dispatched, dispatch_id)) {
471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          DispatchEventToProcess(
472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)              listener->extension_id(), listener->process(), event);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchLazyEvent(
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const linked_ptr<Event>& event,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::set<EventDispatchIdentifier>* already_dispatched) {
483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Check both the original and the incognito browser context to see if we
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should load a lazy bg page to handle the event. The latter case
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // occurs in the case of split-mode extensions.
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension =
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extension_id);
489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!extension)
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (MaybeLoadLazyBackgroundPageToDispatchEvent(
493f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          browser_context_, extension, event)) {
494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    already_dispatched->insert(std::make_pair(browser_context_, extension_id));
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
497f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get();
498f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (browser_client->HasOffTheRecordContext(browser_context_) &&
499f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      IncognitoInfo::IsSplitMode(extension)) {
500f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BrowserContext* incognito_context =
501f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        browser_client->GetOffTheRecordContext(browser_context_);
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (MaybeLoadLazyBackgroundPageToDispatchEvent(
503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            incognito_context, extension, event)) {
504f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      already_dispatched->insert(
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          std::make_pair(incognito_context, extension_id));
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchEventToProcess(const std::string& extension_id,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         content::RenderProcessHost* process,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const linked_ptr<Event>& event) {
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension =
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionRegistry::Get(browser_context_)->enabled_extensions().GetByID(
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extension_id);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The extension could have been removed, but we do not unregister it until
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the extension process is unloaded.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserContext* listener_context = process->GetBrowserContext();
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessMap* process_map = ProcessMap::Get(listener_context);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the event is privileged, only send to extension processes. Otherwise,
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it's OK to send to normal renderers (e.g., for content scripts).
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ExtensionAPI::GetSharedInstance()->IsPrivileged(event->event_name) &&
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !process_map->Contains(extension->id(), process->GetID())) {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
531868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If the event is restricted to a URL, only dispatch if the extension has
532868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // permission for it (or if the event originated from itself).
533868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!event->event_url.is_empty() &&
534868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      event->event_url.host() != extension->id() &&
535868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      !extension->GetActivePermissions()->HasEffectiveAccessToURL(
536868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          event->event_url)) {
537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
539868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CanDispatchEventToBrowserContext(listener_context, extension, event))
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!event->will_dispatch_callback.is_null()) {
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    event->will_dispatch_callback.Run(listener_context, extension,
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      event->event_args.get());
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DispatchExtensionMessage(process, listener_context, extension->id(),
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           event->event_name, event->event_args.get(),
550868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           event->user_gesture, event->filter_info);
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  IncrementInFlightEvents(listener_context, extension);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool EventRouter::CanDispatchEventToBrowserContext(
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BrowserContext* context,
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const Extension* extension,
557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const linked_ptr<Event>& event) {
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Is this event from a different browser context than the renderer (ie, an
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // incognito tab event sent to a normal process, or vice versa).
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool cross_incognito = event->restrict_to_browser_context &&
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         context != event->restrict_to_browser_context;
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!cross_incognito)
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension, context);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EventRouter::MaybeLoadLazyBackgroundPageToDispatchEvent(
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    BrowserContext* context,
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension,
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const linked_ptr<Event>& event) {
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (extension->is_ephemeral() && !event->can_load_ephemeral_apps) {
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Most events can only be dispatched to ephemeral apps that are already
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // running.
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!pm->GetBackgroundHostForExtension(extension->id()))
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CanDispatchEventToBrowserContext(context, extension, event))
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      context)->lazy_background_task_queue();
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (queue->ShouldEnqueueTask(context, extension)) {
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    linked_ptr<Event> dispatched_event(event);
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If there's a dispatch callback, call it now (rather than dispatch time)
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to avoid lifetime issues. Use a separate copy of the event args, so they
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // last until the event is dispatched.
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!event->will_dispatch_callback.is_null()) {
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dispatched_event.reset(event->DeepCopy());
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dispatched_event->will_dispatch_callback.Run(
594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          context, extension, dispatched_event->event_args.get());
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Ensure we don't call it again at dispatch time.
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dispatched_event->will_dispatch_callback.Reset();
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    queue->AddPendingTask(context, extension->id(),
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          base::Bind(&EventRouter::DispatchPendingEvent,
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     base::Unretained(this), dispatched_event));
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
60990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void EventRouter::IncrementInFlightEventsOnUI(
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    void* browser_context_id,
61190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& extension_id) {
612effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserContext* browser_context =
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      reinterpret_cast<BrowserContext*>(browser_context_id);
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
6167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
6170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter* event_router = EventRouter::Get(browser_context);
61890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!event_router)
61990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
62090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const Extension* extension =
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extension_id);
62390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!extension)
62490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  event_router->IncrementInFlightEvents(browser_context, extension);
62690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
62790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void EventRouter::IncrementInFlightEvents(BrowserContext* context,
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const Extension* extension) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only increment in-flight events if the lazy background page is active,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because that's the only time we'll get an ACK.
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionHost* host = pm->GetBackgroundHostForExtension(extension->id());
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pm->IncrementLazyKeepaliveCount(extension);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void EventRouter::OnEventAck(BrowserContext* context,
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& extension_id) {
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ProcessManager* pm = ExtensionSystem::Get(context)->process_manager();
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The event ACK is routed to the background host, so this should never be
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NULL.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(host);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mpcomplete): We should never get this message unless
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HasLazyBackgroundPage is true. Find out why we're getting it anyway.
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (host->extension() &&
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BackgroundInfo::HasLazyBackgroundPage(host->extension()))
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pm->DecrementLazyKeepaliveCount(host->extension());
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event,
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       ExtensionHost* host) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!host)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (listeners_.HasProcessListener(host->render_process_host(),
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    host->extension()->id())) {
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DispatchEventToProcess(host->extension()->id(),
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           host->render_process_host(), event);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EventRouter::Observe(int type,
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const content::NotificationSource& source,
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          const content::NotificationDetails& details) {
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RenderProcessHost* renderer =
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Source<content::RenderProcessHost>(source).ptr();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove all event listeners associated with this renderer.
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listeners_.RemoveListenersForProcess(renderer);
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_ENABLED: {
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the extension has a lazy background page, make sure it gets loaded
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // to register the events the extension is interested in.
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension =
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content::Details<const Extension>(details).ptr();
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LazyBackgroundTaskQueue* queue = ExtensionSystem::Get(
685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            browser_context_)->lazy_background_task_queue();
686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        queue->AddPendingTask(browser_context_, extension->id(),
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              base::Bind(&DoNothing));
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add all registered lazy listeners to our cache.
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const Extension* extension =
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<const Extension>(details).ptr();
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::set<std::string> registered_events =
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GetRegisteredEvents(extension->id());
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listeners_.LoadUnfilteredLazyListeners(extension->id(),
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             registered_events);
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DictionaryValue* filtered_events =
70090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          GetFilteredEvents(extension->id());
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (filtered_events)
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        listeners_.LoadFilteredLazyListeners(extension->id(), *filtered_events);
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
70523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove all registered lazy listeners from our cache.
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UnloadedExtensionInfo* unloaded =
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Details<UnloadedExtensionInfo>(details).ptr();
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listeners_.RemoveLazyListenersForExtension(unloaded->extension->id());
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Event::Event(const std::string& event_name,
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             scoped_ptr<base::ListValue> event_args)
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : event_name(event_name),
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event_args(event_args.Pass()),
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      restrict_to_browser_context(NULL),
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_gesture(EventRouter::USER_GESTURE_UNKNOWN),
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      can_load_ephemeral_apps(false) {
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(this->event_args.get());
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Event::Event(const std::string& event_name,
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             scoped_ptr<base::ListValue> event_args,
730f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             BrowserContext* restrict_to_browser_context)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : event_name(event_name),
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_args(event_args.Pass()),
733f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      restrict_to_browser_context(restrict_to_browser_context),
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_gesture(EventRouter::USER_GESTURE_UNKNOWN),
7355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      can_load_ephemeral_apps(false) {
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(this->event_args.get());
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Event::Event(const std::string& event_name,
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             scoped_ptr<ListValue> event_args,
741f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)             BrowserContext* restrict_to_browser_context,
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const GURL& event_url,
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             EventRouter::UserGestureState user_gesture,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const EventFilteringInfo& filter_info)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : event_name(event_name),
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_args(event_args.Pass()),
747f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      restrict_to_browser_context(restrict_to_browser_context),
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event_url(event_url),
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_gesture(user_gesture),
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      filter_info(filter_info),
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      can_load_ephemeral_apps(false) {
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(this->event_args.get());
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Event::~Event() {}
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Event* Event::DeepCopy() {
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Event* copy = new Event(event_name,
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          scoped_ptr<base::ListValue>(event_args->DeepCopy()),
760f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          restrict_to_browser_context,
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          event_url,
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          user_gesture,
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          filter_info);
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  copy->will_dispatch_callback = will_dispatch_callback;
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return copy;
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)EventListenerInfo::EventListenerInfo(const std::string& event_name,
769f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     const std::string& extension_id,
770f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     content::BrowserContext* browser_context)
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : event_name(event_name),
772f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_id(extension_id),
773f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      browser_context(browser_context) {}
774f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
776