Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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.
      4 
      5 #include "chrome/browser/extensions/extension_event_router.h"
      6 
      7 #include "base/values.h"
      8 #include "chrome/browser/extensions/extension_devtools_manager.h"
      9 #include "chrome/browser/extensions/extension_processes_api.h"
     10 #include "chrome/browser/extensions/extension_processes_api_constants.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/extensions/extension_tabs_module.h"
     13 #include "chrome/browser/extensions/extension_webrequest_api.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/common/extensions/extension.h"
     16 #include "chrome/common/extensions/extension_messages.h"
     17 #include "content/browser/child_process_security_policy.h"
     18 #include "content/browser/renderer_host/render_process_host.h"
     19 #include "content/common/notification_service.h"
     20 
     21 namespace {
     22 
     23 const char kDispatchEvent[] = "Event.dispatchJSON";
     24 
     25 static void DispatchEvent(RenderProcessHost* renderer,
     26                           const std::string& extension_id,
     27                           const std::string& event_name,
     28                           const std::string& event_args,
     29                           const GURL& event_url) {
     30   ListValue args;
     31   args.Set(0, Value::CreateStringValue(event_name));
     32   args.Set(1, Value::CreateStringValue(event_args));
     33   renderer->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
     34       extension_id, kDispatchEvent, args, event_url));
     35 }
     36 
     37 static void NotifyEventListenerRemovedOnIOThread(
     38     ProfileId profile_id,
     39     const std::string& extension_id,
     40     const std::string& sub_event_name) {
     41   ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
     42       profile_id, extension_id, sub_event_name);
     43 }
     44 
     45 }  // namespace
     46 
     47 struct ExtensionEventRouter::EventListener {
     48   RenderProcessHost* process;
     49   std::string extension_id;
     50 
     51   explicit EventListener(RenderProcessHost* process,
     52                          const std::string& extension_id)
     53       : process(process), extension_id(extension_id) {}
     54 
     55   bool operator<(const EventListener& that) const {
     56     if (process < that.process)
     57       return true;
     58     if (process == that.process && extension_id < that.extension_id)
     59       return true;
     60     return false;
     61   }
     62 };
     63 
     64 // static
     65 bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
     66                                              const std::string& extension_id) {
     67   const Extension* extension =
     68       profile->GetExtensionService()->GetExtensionById(extension_id, false);
     69   return CanCrossIncognito(profile, extension);
     70 }
     71 
     72 // static
     73 bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
     74                                              const Extension* extension) {
     75   // We allow the extension to see events and data from another profile iff it
     76   // uses "spanning" behavior and it has incognito access. "split" mode
     77   // extensions only see events for a matching profile.
     78   return
     79       (profile->GetExtensionService()->IsIncognitoEnabled(extension->id()) &&
     80        !extension->incognito_split_mode());
     81 }
     82 
     83 ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
     84     : profile_(profile),
     85       extension_devtools_manager_(profile->GetExtensionDevToolsManager()) {
     86   registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED,
     87                  NotificationService::AllSources());
     88   registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED,
     89                  NotificationService::AllSources());
     90 }
     91 
     92 ExtensionEventRouter::~ExtensionEventRouter() {
     93 }
     94 
     95 void ExtensionEventRouter::AddEventListener(
     96     const std::string& event_name,
     97     RenderProcessHost* process,
     98     const std::string& extension_id) {
     99   EventListener listener(process, extension_id);
    100   DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name;
    101   listeners_[event_name].insert(listener);
    102 
    103   if (extension_devtools_manager_.get())
    104     extension_devtools_manager_->AddEventListener(event_name, process->id());
    105 
    106   // We lazily tell the TaskManager to start updating when listeners to the
    107   // processes.onUpdated event arrive.
    108   if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0)
    109     ExtensionProcessesEventRouter::GetInstance()->ListenerAdded();
    110 }
    111 
    112 void ExtensionEventRouter::RemoveEventListener(
    113     const std::string& event_name,
    114     RenderProcessHost* process,
    115     const std::string& extension_id) {
    116   EventListener listener(process, extension_id);
    117   DCHECK_EQ(listeners_[event_name].count(listener), 1u) <<
    118       " PID=" << process->id() << " extension=" << extension_id <<
    119       " event=" << event_name;
    120   listeners_[event_name].erase(listener);
    121   // Note: extension_id may point to data in the now-deleted listeners_ object.
    122   // Do not use.
    123 
    124   if (extension_devtools_manager_.get())
    125     extension_devtools_manager_->RemoveEventListener(event_name, process->id());
    126 
    127   // If a processes.onUpdated event listener is removed (or a process with one
    128   // exits), then we let the TaskManager know that it has one fewer listener.
    129   if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0)
    130     ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved();
    131 
    132   BrowserThread::PostTask(
    133       BrowserThread::IO, FROM_HERE,
    134       NewRunnableFunction(
    135           &NotifyEventListenerRemovedOnIOThread,
    136           profile_->GetRuntimeId(), listener.extension_id, event_name));
    137 }
    138 
    139 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) {
    140   return (listeners_.find(event_name) != listeners_.end() &&
    141           !listeners_[event_name].empty());
    142 }
    143 
    144 bool ExtensionEventRouter::ExtensionHasEventListener(
    145     const std::string& extension_id, const std::string& event_name) {
    146   ListenerMap::iterator it = listeners_.find(event_name);
    147   if (it == listeners_.end())
    148     return false;
    149 
    150   std::set<EventListener>& listeners = it->second;
    151   for (std::set<EventListener>::iterator listener = listeners.begin();
    152        listener != listeners.end(); ++listener) {
    153     if (listener->extension_id == extension_id)
    154       return true;
    155   }
    156   return false;
    157 }
    158 
    159 void ExtensionEventRouter::DispatchEventToRenderers(
    160     const std::string& event_name, const std::string& event_args,
    161     Profile* restrict_to_profile, const GURL& event_url) {
    162   DispatchEventImpl("", event_name, event_args, restrict_to_profile, event_url);
    163 }
    164 
    165 void ExtensionEventRouter::DispatchEventToExtension(
    166     const std::string& extension_id,
    167     const std::string& event_name, const std::string& event_args,
    168     Profile* restrict_to_profile, const GURL& event_url) {
    169   DCHECK(!extension_id.empty());
    170   DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile,
    171                     event_url);
    172 }
    173 
    174 void ExtensionEventRouter::DispatchEventImpl(
    175     const std::string& extension_id,
    176     const std::string& event_name, const std::string& event_args,
    177     Profile* restrict_to_profile, const GURL& event_url) {
    178   if (!profile_)
    179     return;
    180 
    181   // We don't expect to get events from a completely different profile.
    182   DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile));
    183 
    184   ListenerMap::iterator it = listeners_.find(event_name);
    185   if (it == listeners_.end())
    186     return;
    187 
    188   std::set<EventListener>& listeners = it->second;
    189   ExtensionService* service = profile_->GetExtensionService();
    190 
    191   // Send the event only to renderers that are listening for it.
    192   for (std::set<EventListener>::iterator listener = listeners.begin();
    193        listener != listeners.end(); ++listener) {
    194     if (!ChildProcessSecurityPolicy::GetInstance()->
    195             HasExtensionBindings(listener->process->id())) {
    196       // Don't send browser-level events to unprivileged processes.
    197       continue;
    198     }
    199 
    200     if (!extension_id.empty() && extension_id != listener->extension_id)
    201       continue;
    202 
    203     // Is this event from a different profile than the renderer (ie, an
    204     // incognito tab event sent to a normal process, or vice versa).
    205     bool cross_incognito = restrict_to_profile &&
    206         listener->process->profile() != restrict_to_profile;
    207     const Extension* extension = service->GetExtensionById(
    208         listener->extension_id, false);
    209     if (cross_incognito && !service->CanCrossIncognito(extension))
    210       continue;
    211 
    212     DispatchEvent(listener->process, listener->extension_id,
    213                   event_name, event_args, event_url);
    214   }
    215 }
    216 
    217 void ExtensionEventRouter::Observe(NotificationType type,
    218                                    const NotificationSource& source,
    219                                    const NotificationDetails& details) {
    220   switch (type.value) {
    221     case NotificationType::RENDERER_PROCESS_TERMINATED:
    222     case NotificationType::RENDERER_PROCESS_CLOSED: {
    223       RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr();
    224       // Remove all event listeners associated with this renderer
    225       for (ListenerMap::iterator it = listeners_.begin();
    226            it != listeners_.end(); ) {
    227         ListenerMap::iterator current_it = it++;
    228         for (std::set<EventListener>::iterator jt = current_it->second.begin();
    229              jt != current_it->second.end(); ) {
    230           std::set<EventListener>::iterator current_jt = jt++;
    231           if (current_jt->process == renderer) {
    232             RemoveEventListener(current_it->first,
    233                                 current_jt->process,
    234                                 current_jt->extension_id);
    235           }
    236         }
    237       }
    238       break;
    239     }
    240     default:
    241       NOTREACHED();
    242       return;
    243   }
    244 }
    245