• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DispatchEvent(RenderProcessHost * renderer,const std::string & extension_id,const std::string & event_name,const std::string & event_args,const GURL & event_url)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 
NotifyEventListenerRemovedOnIOThread(ProfileId profile_id,const std::string & extension_id,const std::string & sub_event_name)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 
EventListenerExtensionEventRouter::EventListener51   explicit EventListener(RenderProcessHost* process,
52                          const std::string& extension_id)
53       : process(process), extension_id(extension_id) {}
54 
operator <ExtensionEventRouter::EventListener55   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
CanCrossIncognito(Profile * profile,const std::string & extension_id)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
CanCrossIncognito(Profile * profile,const Extension * extension)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 
ExtensionEventRouter(Profile * profile)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 
~ExtensionEventRouter()92 ExtensionEventRouter::~ExtensionEventRouter() {
93 }
94 
AddEventListener(const std::string & event_name,RenderProcessHost * process,const std::string & extension_id)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 
RemoveEventListener(const std::string & event_name,RenderProcessHost * process,const std::string & extension_id)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 
HasEventListener(const std::string & event_name)139 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) {
140   return (listeners_.find(event_name) != listeners_.end() &&
141           !listeners_[event_name].empty());
142 }
143 
ExtensionHasEventListener(const std::string & extension_id,const std::string & event_name)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 
DispatchEventToRenderers(const std::string & event_name,const std::string & event_args,Profile * restrict_to_profile,const GURL & event_url)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 
DispatchEventToExtension(const std::string & extension_id,const std::string & event_name,const std::string & event_args,Profile * restrict_to_profile,const GURL & event_url)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 
DispatchEventImpl(const std::string & extension_id,const std::string & event_name,const std::string & event_args,Profile * restrict_to_profile,const GURL & event_url)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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