OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_event_router.h" | 5 #include "chrome/browser/extensions/extension_event_router.h" |
6 | 6 |
7 #include "base/command_line.h" | |
7 #include "base/values.h" | 8 #include "base/values.h" |
8 #include "chrome/browser/extensions/extension_devtools_manager.h" | 9 #include "chrome/browser/extensions/extension_devtools_manager.h" |
10 #include "chrome/browser/extensions/extension_host.h" | |
9 #include "chrome/browser/extensions/extension_processes_api.h" | 11 #include "chrome/browser/extensions/extension_processes_api.h" |
10 #include "chrome/browser/extensions/extension_processes_api_constants.h" | 12 #include "chrome/browser/extensions/extension_processes_api_constants.h" |
11 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
12 #include "chrome/browser/extensions/extension_tabs_module.h" | 14 #include "chrome/browser/extensions/extension_tabs_module.h" |
13 #include "chrome/browser/extensions/extension_webrequest_api.h" | 15 #include "chrome/browser/extensions/extension_webrequest_api.h" |
14 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/common/chrome_switches.h" | |
15 #include "chrome/common/extensions/extension.h" | 18 #include "chrome/common/extensions/extension.h" |
16 #include "chrome/common/extensions/extension_messages.h" | 19 #include "chrome/common/extensions/extension_messages.h" |
17 #include "content/browser/child_process_security_policy.h" | 20 #include "content/browser/child_process_security_policy.h" |
18 #include "content/browser/renderer_host/render_process_host.h" | 21 #include "content/browser/renderer_host/render_process_host.h" |
19 #include "content/common/notification_service.h" | 22 #include "content/common/notification_service.h" |
20 | 23 |
21 namespace { | 24 namespace { |
22 | 25 |
23 const char kDispatchEvent[] = "Event.dispatchJSON"; | 26 const char kDispatchEvent[] = "Event.dispatchJSON"; |
24 | 27 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 const GURL& event_url) { | 59 const GURL& event_url) { |
57 ListValue args; | 60 ListValue args; |
58 args.Set(0, Value::CreateStringValue(event_name)); | 61 args.Set(0, Value::CreateStringValue(event_name)); |
59 args.Set(1, Value::CreateStringValue(event_args)); | 62 args.Set(1, Value::CreateStringValue(event_args)); |
60 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, | 63 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, |
61 extension_id, kDispatchEvent, args, event_url)); | 64 extension_id, kDispatchEvent, args, event_url)); |
62 } | 65 } |
63 | 66 |
64 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) | 67 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) |
65 : profile_(profile), | 68 : profile_(profile), |
66 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) { | 69 extension_devtools_manager_(profile->GetExtensionDevToolsManager()), |
70 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { | |
67 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 71 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
68 NotificationService::AllSources()); | 72 NotificationService::AllSources()); |
69 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 73 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
70 NotificationService::AllSources()); | 74 NotificationService::AllSources()); |
75 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, | |
76 Source<Profile>(profile_)); | |
77 // TODO(tessamac): also get notified for background page crash/failure. | |
71 } | 78 } |
72 | 79 |
73 ExtensionEventRouter::~ExtensionEventRouter() { | 80 ExtensionEventRouter::~ExtensionEventRouter() { |
81 // May not be necessary... | |
82 task_factory_.RevokeAll(); | |
Aaron Boodman
2011/08/23 22:41:16
Not necessary -- this happens automatically when t
Tessa MacDuff
2011/08/24 00:34:23
Done.
| |
74 } | 83 } |
75 | 84 |
76 void ExtensionEventRouter::AddEventListener( | 85 void ExtensionEventRouter::AddEventListener( |
77 const std::string& event_name, | 86 const std::string& event_name, |
78 RenderProcessHost* process, | 87 RenderProcessHost* process, |
79 const std::string& extension_id) { | 88 const std::string& extension_id) { |
80 EventListener listener(process, extension_id); | 89 EventListener listener(process, extension_id); |
81 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; | 90 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; |
82 listeners_[event_name].insert(listener); | 91 listeners_[event_name].insert(listener); |
83 | 92 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 } | 145 } |
137 return false; | 146 return false; |
138 } | 147 } |
139 | 148 |
140 void ExtensionEventRouter::DispatchEventToRenderers( | 149 void ExtensionEventRouter::DispatchEventToRenderers( |
141 const std::string& event_name, | 150 const std::string& event_name, |
142 const std::string& event_args, | 151 const std::string& event_args, |
143 Profile* restrict_to_profile, | 152 Profile* restrict_to_profile, |
144 const GURL& event_url) { | 153 const GURL& event_url) { |
145 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "", | 154 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "", |
146 event_url); | 155 event_url, false); |
147 } | 156 } |
148 | 157 |
149 void ExtensionEventRouter::DispatchEventToExtension( | 158 void ExtensionEventRouter::DispatchEventToExtension( |
150 const std::string& extension_id, | 159 const std::string& extension_id, |
151 const std::string& event_name, | 160 const std::string& event_name, |
152 const std::string& event_args, | 161 const std::string& event_args, |
153 Profile* restrict_to_profile, | 162 Profile* restrict_to_profile, |
154 const GURL& event_url) { | 163 const GURL& event_url) { |
155 DCHECK(!extension_id.empty()); | 164 DCHECK(!extension_id.empty()); |
156 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, | 165 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, |
157 "", event_url); | 166 "", event_url, false); |
158 } | 167 } |
159 | 168 |
160 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( | 169 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( |
161 const std::string& event_name, | 170 const std::string& event_name, |
162 const std::string& event_args, | 171 const std::string& event_args, |
163 Profile* restrict_to_profile, | 172 Profile* restrict_to_profile, |
164 const std::string& cross_incognito_args, | 173 const std::string& cross_incognito_args, |
165 const GURL& event_url) { | 174 const GURL& event_url) { |
166 DispatchEventImpl("", event_name, event_args, restrict_to_profile, | 175 DispatchEventImpl("", event_name, event_args, restrict_to_profile, |
167 cross_incognito_args, event_url); | 176 cross_incognito_args, event_url, false); |
177 } | |
178 | |
179 bool ExtensionEventRouter::CanDispatchEventNow( | |
180 const std::string& extension_id, bool was_pending) { | |
181 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
182 switches::kEnableLazyBackgroundPages)) { | |
Aaron Boodman
2011/08/23 22:41:16
Invert test and return early to reduce indenting.
Tessa MacDuff
2011/08/24 00:34:23
Done.
| |
183 if (extension_id.empty()) | |
184 // TODO(tessamac): Create all background pages. Wait for all to be loaded? | |
185 // or dispatch event to each extension when it's ready? | |
186 return true; | |
187 const Extension* extension = profile_->GetExtensionService()-> | |
188 GetExtensionById(extension_id, false); // exclude disabled extensions | |
189 if (extension && extension->background_url().is_valid()) { | |
190 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager(); | |
191 if (!pm->GetBackgroundHostForExtension(extension)) { | |
192 // Pending events are dispatched when the background page is done | |
193 // loading. Maybe it was then shutdown too soon? | |
194 DCHECK(!was_pending); | |
Aaron Boodman
2011/08/23 22:41:16
Can you move this to the call site?
if (!CanDispa
Tessa MacDuff
2011/08/24 00:34:23
Done.
But why does this mean I don't have to mess
Aaron Boodman
2011/08/24 18:49:32
Whoops, you're right. I suspect the owner of base/
| |
195 pm->CreateBackgroundHost(extension, extension->background_url()); | |
196 return false; | |
197 } | |
198 } | |
199 } | |
200 return true; | |
168 } | 201 } |
169 | 202 |
170 void ExtensionEventRouter::DispatchEventImpl( | 203 void ExtensionEventRouter::DispatchEventImpl( |
171 const std::string& extension_id, | 204 const std::string& extension_id, |
172 const std::string& event_name, | 205 const std::string& event_name, |
173 const std::string& event_args, | 206 const std::string& event_args, |
174 Profile* restrict_to_profile, | 207 Profile* restrict_to_profile, |
175 const std::string& cross_incognito_args, | 208 const std::string& cross_incognito_args, |
176 const GURL& event_url) { | 209 const GURL& event_url, |
210 bool was_pending) { | |
177 if (!profile_) | 211 if (!profile_) |
178 return; | 212 return; |
179 | 213 |
180 // We don't expect to get events from a completely different profile. | 214 // We don't expect to get events from a completely different profile. |
181 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile)); | 215 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile)); |
182 | 216 |
217 if (!CanDispatchEventNow(extension_id, was_pending)) { | |
218 // TODO(tessamac): make sure Background Page notification doesn't | |
219 // happen before the event is added to the pending list. | |
220 AppendEvent(extension_id, event_name, event_args, restrict_to_profile, | |
221 cross_incognito_args, event_url); | |
222 return; | |
223 } | |
224 | |
183 ListenerMap::iterator it = listeners_.find(event_name); | 225 ListenerMap::iterator it = listeners_.find(event_name); |
184 if (it == listeners_.end()) | 226 if (it == listeners_.end()) |
185 return; | 227 return; |
186 | 228 |
187 std::set<EventListener>& listeners = it->second; | 229 std::set<EventListener>& listeners = it->second; |
188 ExtensionService* service = profile_->GetExtensionService(); | 230 ExtensionService* service = profile_->GetExtensionService(); |
189 | 231 |
190 // Send the event only to renderers that are listening for it. | 232 // Send the event only to renderers that are listening for it. |
191 for (std::set<EventListener>::iterator listener = listeners.begin(); | 233 for (std::set<EventListener>::iterator listener = listeners.begin(); |
192 listener != listeners.end(); ++listener) { | 234 listener != listeners.end(); ++listener) { |
(...skipping 20 matching lines...) Expand all Loading... | |
213 event_name, cross_incognito_args, event_url); | 255 event_name, cross_incognito_args, event_url); |
214 } | 256 } |
215 continue; | 257 continue; |
216 } | 258 } |
217 | 259 |
218 DispatchEvent(listener->process, listener->extension_id, | 260 DispatchEvent(listener->process, listener->extension_id, |
219 event_name, event_args, event_url); | 261 event_name, event_args, event_url); |
220 } | 262 } |
221 } | 263 } |
222 | 264 |
265 void ExtensionEventRouter::AppendEvent(const std::string &extension_id, | |
266 const std::string& event_name, | |
267 const std::string& event_args, | |
268 Profile* restrict_to_profile, | |
269 const std::string& cross_incognito_args, | |
270 const GURL& event_url) { | |
271 // Put a new list of pending tasks into the map (more common) or get a | |
272 // pointer to the list that is already there (less common). | |
273 PendingTasksList* tasks_list = new PendingTasksList(); | |
274 PendingTasksPerExtMap::const_iterator it = pending_tasks_.find(extension_id); | |
Aaron Boodman
2011/08/23 22:41:16
You do the find(), then always end up trying to in
Tessa MacDuff
2011/08/24 00:34:23
Oops I just forgot to remove that line. 'it' is ne
| |
275 std::pair<PendingTasksPerExtMap::iterator, bool> ret = pending_tasks_.insert( | |
276 std::make_pair(extension_id, linked_ptr<PendingTasksList>(tasks_list))); | |
277 if (!ret.second) { // Insert failed. | |
278 // First part of return value is a pointer to what was already there. | |
279 tasks_list = ret.first->second.get(); | |
280 } | |
281 | |
282 // Append the new task. | |
283 tasks_list->push_back(linked_ptr<Task>( | |
284 task_factory_.NewRunnableMethod(&ExtensionEventRouter::DispatchEventImpl, | |
285 extension_id, event_name, event_args, | |
286 restrict_to_profile, cross_incognito_args, | |
287 event_url, true))); | |
288 } | |
289 | |
290 void ExtensionEventRouter::DispatchPendingEvents( | |
291 const std::string &extension_id) { | |
292 // Find the list of pending tasks for this extension. | |
293 PendingTasksPerExtMap::const_iterator map_it = | |
294 pending_tasks_.find(extension_id); | |
295 if (map_it == pending_tasks_.end()) | |
296 return; | |
297 | |
298 // The second element is the list of tasks (the first is the key/ext id). | |
Aaron Boodman
2011/08/23 22:41:16
Nit: You don't have to explain this since it is cl
Tessa MacDuff
2011/08/24 00:34:23
Done.
| |
299 PendingTasksList* tasks_list = map_it->second.get(); | |
300 for (PendingTasksList::const_iterator it = tasks_list->begin(); | |
301 it != tasks_list->end(); ++it) | |
302 it->get()->Run(); | |
303 | |
304 // Delete list. | |
305 tasks_list->clear(); | |
306 pending_tasks_.erase(extension_id); | |
307 } | |
308 | |
223 void ExtensionEventRouter::Observe(int type, | 309 void ExtensionEventRouter::Observe(int type, |
224 const NotificationSource& source, | 310 const NotificationSource& source, |
225 const NotificationDetails& details) { | 311 const NotificationDetails& details) { |
226 switch (type) { | 312 switch (type) { |
227 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: | 313 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: |
228 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 314 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
229 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); | 315 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
230 // Remove all event listeners associated with this renderer | 316 // Remove all event listeners associated with this renderer |
231 for (ListenerMap::iterator it = listeners_.begin(); | 317 for (ListenerMap::iterator it = listeners_.begin(); |
232 it != listeners_.end(); ) { | 318 it != listeners_.end(); ) { |
233 ListenerMap::iterator current_it = it++; | 319 ListenerMap::iterator current_it = it++; |
234 for (std::set<EventListener>::iterator jt = current_it->second.begin(); | 320 for (std::set<EventListener>::iterator jt = current_it->second.begin(); |
235 jt != current_it->second.end(); ) { | 321 jt != current_it->second.end(); ) { |
236 std::set<EventListener>::iterator current_jt = jt++; | 322 std::set<EventListener>::iterator current_jt = jt++; |
237 if (current_jt->process == renderer) { | 323 if (current_jt->process == renderer) { |
238 RemoveEventListener(current_it->first, | 324 RemoveEventListener(current_it->first, |
239 current_jt->process, | 325 current_jt->process, |
240 current_jt->extension_id); | 326 current_jt->extension_id); |
241 } | 327 } |
242 } | 328 } |
243 } | 329 } |
244 break; | 330 break; |
245 } | 331 } |
332 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { | |
333 // TODO: dispatch events in queue. ExtensionHost is in the details. | |
334 ExtensionHost* eh = Details<ExtensionHost>(details).ptr(); | |
335 DispatchPendingEvents(eh->extension_id()); | |
336 break; | |
337 } | |
338 // TODO(tessamac): if background page crashed/failed clear queue. | |
246 default: | 339 default: |
247 NOTREACHED(); | 340 NOTREACHED(); |
248 return; | 341 return; |
249 } | 342 } |
250 } | 343 } |
OLD | NEW |