Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: chrome/browser/extensions/extension_event_router.cc

Issue 9350006: Revert "Unrevert 119770 - "Event pages: remember events that the page registered for," (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 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/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "chrome/browser/extensions/extension_devtools_manager.h" 10 #include "chrome/browser/extensions/extension_devtools_manager.h"
11 #include "chrome/browser/extensions/extension_host.h" 11 #include "chrome/browser/extensions/extension_host.h"
12 #include "chrome/browser/extensions/extension_process_manager.h" 12 #include "chrome/browser/extensions/extension_process_manager.h"
13 #include "chrome/browser/extensions/extension_processes_api.h" 13 #include "chrome/browser/extensions/extension_processes_api.h"
14 #include "chrome/browser/extensions/extension_processes_api_constants.h" 14 #include "chrome/browser/extensions/extension_processes_api_constants.h"
15 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_tabs_module.h" 16 #include "chrome/browser/extensions/extension_tabs_module.h"
17 #include "chrome/browser/extensions/api/webrequest/webrequest_api.h" 17 #include "chrome/browser/extensions/api/webrequest/webrequest_api.h"
18 #include "chrome/browser/extensions/process_map.h" 18 #include "chrome/browser/extensions/process_map.h"
19 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_notification_types.h" 20 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/chrome_switches.h" 21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/chrome_view_type.h" 22 #include "chrome/common/chrome_view_type.h"
23 #include "chrome/common/extensions/extension.h" 23 #include "chrome/common/extensions/extension.h"
24 #include "chrome/common/extensions/extension_messages.h" 24 #include "chrome/common/extensions/extension_messages.h"
25 #include "chrome/common/extensions/api/extension_api.h" 25 #include "chrome/common/extensions/api/extension_api.h"
26 #include "content/browser/child_process_security_policy.h"
26 #include "content/public/browser/notification_service.h" 27 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/render_process_host.h" 28 #include "content/public/browser/render_process_host.h"
28 29
29 using content::BrowserThread; 30 using content::BrowserThread;
30 using extensions::ExtensionAPI; 31 using extensions::ExtensionAPI;
31 32
32 namespace { 33 namespace {
33 34
34 const char kDispatchEvent[] = "Event.dispatchJSON"; 35 const char kDispatchEvent[] = "Event.dispatchJSON";
35 36
(...skipping 18 matching lines...) Expand all
54 bool operator<(const EventListener& that) const { 55 bool operator<(const EventListener& that) const {
55 if (process < that.process) 56 if (process < that.process)
56 return true; 57 return true;
57 if (process == that.process && extension_id < that.extension_id) 58 if (process == that.process && extension_id < that.extension_id)
58 return true; 59 return true;
59 return false; 60 return false;
60 } 61 }
61 }; 62 };
62 63
63 struct ExtensionEventRouter::ExtensionEvent { 64 struct ExtensionEventRouter::ExtensionEvent {
65 std::string extension_id;
64 std::string event_name; 66 std::string event_name;
65 std::string event_args; 67 std::string event_args;
66 GURL event_url; 68 GURL event_url;
67 Profile* restrict_to_profile; 69 Profile* restrict_to_profile;
68 std::string cross_incognito_args; 70 std::string cross_incognito_args;
69 71
70 ExtensionEvent(const std::string& event_name, 72 ExtensionEvent(const std::string& extension_id,
73 const std::string& event_name,
71 const std::string& event_args, 74 const std::string& event_args,
72 const GURL& event_url, 75 const GURL& event_url,
73 Profile* restrict_to_profile, 76 Profile* restrict_to_profile,
74 const std::string& cross_incognito_args) 77 const std::string& cross_incognito_args)
75 : event_name(event_name), 78 : extension_id(extension_id),
79 event_name(event_name),
76 event_args(event_args), 80 event_args(event_args),
77 event_url(event_url), 81 event_url(event_url),
78 restrict_to_profile(restrict_to_profile), 82 restrict_to_profile(restrict_to_profile),
79 cross_incognito_args(cross_incognito_args) {} 83 cross_incognito_args(cross_incognito_args) {}
80 }; 84 };
81 85
82 // static 86 // static
83 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, 87 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender,
84 const std::string& extension_id, 88 const std::string& extension_id,
85 const std::string& event_name, 89 const std::string& event_name,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) 149 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0)
146 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved(); 150 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved();
147 151
148 BrowserThread::PostTask( 152 BrowserThread::PostTask(
149 BrowserThread::IO, FROM_HERE, 153 BrowserThread::IO, FROM_HERE,
150 base::Bind( 154 base::Bind(
151 &NotifyEventListenerRemovedOnIOThread, 155 &NotifyEventListenerRemovedOnIOThread,
152 profile_, listener.extension_id, event_name)); 156 profile_, listener.extension_id, event_name));
153 } 157 }
154 158
155 void ExtensionEventRouter::AddLazyEventListener(
156 const std::string& event_name,
157 const std::string& extension_id) {
158 EventListener lazy_listener(NULL, extension_id);
159 if (lazy_listeners_[event_name].count(lazy_listener) == 0)
160 lazy_listeners_[event_name].insert(lazy_listener);
161 }
162
163 void ExtensionEventRouter::RemoveLazyEventListener(
164 const std::string& event_name,
165 const std::string& extension_id) {
166 EventListener lazy_listener(NULL, extension_id);
167 lazy_listeners_[event_name].erase(lazy_listener);
168 }
169
170 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) { 159 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) {
171 return (listeners_.find(event_name) != listeners_.end() && 160 return (listeners_.find(event_name) != listeners_.end() &&
172 !listeners_[event_name].empty()); 161 !listeners_[event_name].empty());
173 } 162 }
174 163
175 bool ExtensionEventRouter::ExtensionHasEventListener( 164 bool ExtensionEventRouter::ExtensionHasEventListener(
176 const std::string& extension_id, const std::string& event_name) { 165 const std::string& extension_id, const std::string& event_name) {
177 ListenerMap::iterator it = listeners_.find(event_name); 166 ListenerMap::iterator it = listeners_.find(event_name);
178 if (it == listeners_.end()) 167 if (it == listeners_.end())
179 return false; 168 return false;
180 169
181 std::set<EventListener>& listeners = it->second; 170 std::set<EventListener>& listeners = it->second;
182 for (std::set<EventListener>::iterator listener = listeners.begin(); 171 for (std::set<EventListener>::iterator listener = listeners.begin();
183 listener != listeners.end(); ++listener) { 172 listener != listeners.end(); ++listener) {
184 if (listener->extension_id == extension_id) 173 if (listener->extension_id == extension_id)
185 return true; 174 return true;
186 } 175 }
187 return false; 176 return false;
188 } 177 }
189 178
190 void ExtensionEventRouter::DispatchEventToRenderers( 179 void ExtensionEventRouter::DispatchEventToRenderers(
191 const std::string& event_name, 180 const std::string& event_name,
192 const std::string& event_args, 181 const std::string& event_args,
193 Profile* restrict_to_profile, 182 Profile* restrict_to_profile,
194 const GURL& event_url) { 183 const GURL& event_url) {
195 linked_ptr<ExtensionEvent> event( 184 linked_ptr<ExtensionEvent> event(
196 new ExtensionEvent(event_name, event_args, event_url, 185 new ExtensionEvent("", event_name, event_args, event_url,
197 restrict_to_profile, "")); 186 restrict_to_profile, ""));
198 DispatchEventImpl("", event, false); 187 DispatchEventImpl(event, false);
199 } 188 }
200 189
201 void ExtensionEventRouter::DispatchEventToExtension( 190 void ExtensionEventRouter::DispatchEventToExtension(
202 const std::string& extension_id, 191 const std::string& extension_id,
203 const std::string& event_name, 192 const std::string& event_name,
204 const std::string& event_args, 193 const std::string& event_args,
205 Profile* restrict_to_profile, 194 Profile* restrict_to_profile,
206 const GURL& event_url) { 195 const GURL& event_url) {
207 DCHECK(!extension_id.empty()); 196 DCHECK(!extension_id.empty());
208 linked_ptr<ExtensionEvent> event( 197 linked_ptr<ExtensionEvent> event(
209 new ExtensionEvent(event_name, event_args, event_url, 198 new ExtensionEvent(extension_id, event_name, event_args, event_url,
210 restrict_to_profile, "")); 199 restrict_to_profile, ""));
211 DispatchEventImpl(extension_id, event, false); 200 DispatchEventImpl(event, false);
212 } 201 }
213 202
214 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( 203 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito(
215 const std::string& event_name, 204 const std::string& event_name,
216 const std::string& event_args, 205 const std::string& event_args,
217 Profile* restrict_to_profile, 206 Profile* restrict_to_profile,
218 const std::string& cross_incognito_args, 207 const std::string& cross_incognito_args,
219 const GURL& event_url) { 208 const GURL& event_url) {
220 linked_ptr<ExtensionEvent> event( 209 linked_ptr<ExtensionEvent> event(
221 new ExtensionEvent(event_name, event_args, event_url, 210 new ExtensionEvent("", event_name, event_args, event_url,
222 restrict_to_profile, cross_incognito_args)); 211 restrict_to_profile, cross_incognito_args));
223 DispatchEventImpl("", event, false); 212 DispatchEventImpl(event, false);
224 } 213 }
225 214
226 bool ExtensionEventRouter::CanDispatchEventNow(const Extension* extension) { 215 bool ExtensionEventRouter::CanDispatchEventNow(
227 DCHECK(extension); 216 const std::string& extension_id) {
228 if (extension->has_background_page() && 217 if (extension_id.empty())
218 // TODO(mpcomplete): We need to test this per-extension, rather than
219 // globally.
220 return true;
221
222 const Extension* extension = profile_->GetExtensionService()->
223 GetExtensionById(extension_id, false);
224 if (extension && extension->has_background_page() &&
229 !extension->background_page_persists()) { 225 !extension->background_page_persists()) {
230 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager(); 226 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
231 227 if (!pm->GetBackgroundHostForExtension(extension_id)) {
232 // TODO(mpcomplete): this is incorrect. We need to check whether the page
233 // has finished loading. If not, we can't dispatch the event (because the
234 // listener hasn't been set up yet).
235 if (!pm->GetBackgroundHostForExtension(extension->id())) {
236 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); 228 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL());
237 return false; 229 return false;
238 } 230 }
239 } 231 }
240 232
241 return true; 233 return true;
242 } 234 }
243 235
244 void ExtensionEventRouter::DispatchEventImpl( 236 void ExtensionEventRouter::DispatchEventImpl(
245 const std::string& extension_id, 237 const linked_ptr<ExtensionEvent>& event, bool was_pending) {
246 const linked_ptr<ExtensionEvent>& event,
247 bool was_pending) {
248 // Ensure we are only dispatching pending events to a particular extension.
249 if (was_pending)
250 CHECK(!extension_id.empty());
251
252 if (!profile_) 238 if (!profile_)
253 return; 239 return;
254 240
255 // We don't expect to get events from a completely different profile. 241 // We don't expect to get events from a completely different profile.
256 DCHECK(!event->restrict_to_profile || 242 DCHECK(!event->restrict_to_profile ||
257 profile_->IsSameProfile(event->restrict_to_profile)); 243 profile_->IsSameProfile(event->restrict_to_profile));
258 244
259 if (!was_pending) 245 if (!CanDispatchEventNow(event->extension_id)) {
260 LoadLazyBackgroundPagesForEvent(extension_id, event); 246 // Events should not be made pending twice. This may happen if the
247 // background page is shutdown before we finish dispatching pending events.
248 CHECK(!was_pending);
249 // TODO(tessamac): make sure Background Page notification doesn't
250 // happen before the event is added to the pending list.
251 AppendEvent(event);
252 return;
253 }
261 254
262 ListenerMap::iterator it = listeners_.find(event->event_name); 255 ListenerMap::iterator it = listeners_.find(event->event_name);
263 if (it == listeners_.end()) 256 if (it == listeners_.end())
264 return; 257 return;
265 258
266 std::set<EventListener>& listeners = it->second; 259 std::set<EventListener>& listeners = it->second;
267 ExtensionService* service = profile_->GetExtensionService(); 260 ExtensionService* service = profile_->GetExtensionService();
268 261
269 // Send the event only to renderers that are listening for it. 262 // Send the event only to renderers that are listening for it.
270 for (std::set<EventListener>::iterator listener = listeners.begin(); 263 for (std::set<EventListener>::iterator listener = listeners.begin();
271 listener != listeners.end(); ++listener) { 264 listener != listeners.end(); ++listener) {
272 if (!extension_id.empty() && extension_id != listener->extension_id) 265 if (!event->extension_id.empty() &&
266 event->extension_id != listener->extension_id)
273 continue; 267 continue;
274 268
275 const Extension* extension = service->extensions()->GetByID( 269 const Extension* extension = service->GetExtensionById(
276 listener->extension_id); 270 listener->extension_id, false);
277 271
278 // The extension could have been removed, but we do not unregister it until 272 // The extension could have been removed, but we do not unregister it until
279 // the extension process is unloaded. 273 // the extension process is unloaded.
280 if (!extension) 274 if (!extension)
281 continue; 275 continue;
282 276
283 Profile* listener_profile = Profile::FromBrowserContext( 277 Profile* listener_profile = Profile::FromBrowserContext(
284 listener->process->GetBrowserContext()); 278 listener->process->GetBrowserContext());
285 extensions::ProcessMap* process_map = 279 extensions::ProcessMap* process_map =
286 listener_profile->GetExtensionService()->process_map(); 280 listener_profile->GetExtensionService()->process_map();
(...skipping 19 matching lines...) Expand all
306 } 300 }
307 continue; 301 continue;
308 } 302 }
309 303
310 DispatchEvent(listener->process, listener->extension_id, 304 DispatchEvent(listener->process, listener->extension_id,
311 event->event_name, event->event_args, event->event_url); 305 event->event_name, event->event_args, event->event_url);
312 IncrementInFlightEvents(extension); 306 IncrementInFlightEvents(extension);
313 } 307 }
314 } 308 }
315 309
316 void ExtensionEventRouter::LoadLazyBackgroundPagesForEvent(
317 const std::string& extension_id,
318 const linked_ptr<ExtensionEvent>& event) {
319 ExtensionService* service = profile_->GetExtensionService();
320
321 ListenerMap::iterator it = lazy_listeners_.find(event->event_name);
322 if (it == lazy_listeners_.end())
323 return;
324
325 std::set<EventListener>& listeners = it->second;
326 for (std::set<EventListener>::iterator listener = listeners.begin();
327 listener != listeners.end(); ++listener) {
328 if (!extension_id.empty() && extension_id != listener->extension_id)
329 continue;
330
331 const Extension* extension = service->extensions()->GetByID(
332 listener->extension_id);
333
334 if (extension && !CanDispatchEventNow(extension)) {
335 // TODO(mpcomplete): make sure Background Page notification doesn't
336 // happen before the event is added to the pending list.
337 AppendEvent(extension->id(), event);
338 }
339 }
340 }
341
342 void ExtensionEventRouter::IncrementInFlightEvents(const Extension* extension) { 310 void ExtensionEventRouter::IncrementInFlightEvents(const Extension* extension) {
343 if (!extension->background_page_persists()) 311 if (!extension->background_page_persists())
344 in_flight_events_[extension->id()]++; 312 in_flight_events_[extension->id()]++;
345 } 313 }
346 314
347 void ExtensionEventRouter::OnExtensionEventAck( 315 void ExtensionEventRouter::OnExtensionEventAck(
348 const std::string& extension_id) { 316 const std::string& extension_id) {
349 CHECK(in_flight_events_[extension_id] > 0); 317 CHECK(in_flight_events_[extension_id] > 0);
350 in_flight_events_[extension_id]--; 318 in_flight_events_[extension_id]--;
351 } 319 }
352 320
353 bool ExtensionEventRouter::HasInFlightEvents(const std::string& extension_id) { 321 bool ExtensionEventRouter::HasInFlightEvents(const std::string& extension_id) {
354 return in_flight_events_[extension_id] > 0; 322 return in_flight_events_[extension_id] > 0;
355 } 323 }
356 324
357 void ExtensionEventRouter::AppendEvent( 325 void ExtensionEventRouter::AppendEvent(
358 const std::string& extension_id,
359 const linked_ptr<ExtensionEvent>& event) { 326 const linked_ptr<ExtensionEvent>& event) {
360 PendingEventsList* events_list = NULL; 327 PendingEventsList* events_list = NULL;
361 PendingEventsPerExtMap::iterator it = pending_events_.find(extension_id); 328 PendingEventsPerExtMap::iterator it =
329 pending_events_.find(event->extension_id);
362 if (it == pending_events_.end()) { 330 if (it == pending_events_.end()) {
363 events_list = new PendingEventsList(); 331 events_list = new PendingEventsList();
364 pending_events_[extension_id] = linked_ptr<PendingEventsList>(events_list); 332 pending_events_[event->extension_id] =
333 linked_ptr<PendingEventsList>(events_list);
365 } else { 334 } else {
366 events_list = it->second.get(); 335 events_list = it->second.get();
367 } 336 }
368 337
369 events_list->push_back(event); 338 events_list->push_back(event);
370 } 339 }
371 340
372 void ExtensionEventRouter::DispatchPendingEvents( 341 void ExtensionEventRouter::DispatchPendingEvents(
373 const std::string& extension_id) { 342 const std::string &extension_id) {
374 CHECK(!extension_id.empty()); 343 // Find the list of pending events for this extension.
375 PendingEventsPerExtMap::const_iterator map_it = 344 PendingEventsPerExtMap::const_iterator map_it =
376 pending_events_.find(extension_id); 345 pending_events_.find(extension_id);
377 if (map_it == pending_events_.end()) 346 if (map_it == pending_events_.end())
378 return; 347 return;
379 348
380 PendingEventsList* events_list = map_it->second.get(); 349 PendingEventsList* events_list = map_it->second.get();
381 for (PendingEventsList::const_iterator it = events_list->begin(); 350 for (PendingEventsList::const_iterator it = events_list->begin();
382 it != events_list->end(); ++it) 351 it != events_list->end(); ++it)
383 DispatchEventImpl(extension_id, *it, true); 352 DispatchEventImpl(*it, true);
384 353
354 // Delete list.
385 events_list->clear(); 355 events_list->clear();
386 pending_events_.erase(extension_id); 356 pending_events_.erase(extension_id);
387
388 // Check if the extension is idle, which may be the case if no events were
389 // successfully dispatched.
390 profile_->GetExtensionProcessManager()->OnExtensionIdle(extension_id);
391 } 357 }
392 358
393 void ExtensionEventRouter::Observe( 359 void ExtensionEventRouter::Observe(
394 int type, 360 int type,
395 const content::NotificationSource& source, 361 const content::NotificationSource& source,
396 const content::NotificationDetails& details) { 362 const content::NotificationDetails& details) {
397 switch (type) { 363 switch (type) {
398 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 364 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
399 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 365 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
400 content::RenderProcessHost* renderer = 366 content::RenderProcessHost* renderer =
401 content::Source<content::RenderProcessHost>(source).ptr(); 367 content::Source<content::RenderProcessHost>(source).ptr();
402 // Remove all event listeners associated with this renderer 368 // Remove all event listeners associated with this renderer
403 for (ListenerMap::iterator it = listeners_.begin(); 369 for (ListenerMap::iterator it = listeners_.begin();
404 it != listeners_.end(); ) { 370 it != listeners_.end(); ) {
405 ListenerMap::iterator current_it = it++; 371 ListenerMap::iterator current_it = it++;
406 for (std::set<EventListener>::iterator jt = current_it->second.begin(); 372 for (std::set<EventListener>::iterator jt = current_it->second.begin();
407 jt != current_it->second.end(); ) { 373 jt != current_it->second.end(); ) {
408 std::set<EventListener>::iterator current_jt = jt++; 374 std::set<EventListener>::iterator current_jt = jt++;
409 if (current_jt->process == renderer) { 375 if (current_jt->process == renderer) {
410 RemoveEventListener(current_it->first, 376 RemoveEventListener(current_it->first,
411 current_jt->process, 377 current_jt->process,
412 current_jt->extension_id); 378 current_jt->extension_id);
413 } 379 }
414 } 380 }
415 } 381 }
416 break; 382 break;
417 } 383 }
418 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { 384 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
419 // If an on-demand background page finished loading, dispatch queued up 385 // TODO: dispatch events in queue. ExtensionHost is in the details.
420 // events for it.
421 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr(); 386 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr();
422 if (eh->extension_host_type() == 387 DispatchPendingEvents(eh->extension_id());
423 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
424 !eh->extension()->background_page_persists()) {
425 DispatchPendingEvents(eh->extension_id());
426 }
427 break; 388 break;
428 } 389 }
429 // TODO(tessamac): if background page crashed/failed clear queue. 390 // TODO(tessamac): if background page crashed/failed clear queue.
430 default: 391 default:
431 NOTREACHED(); 392 NOTREACHED();
432 return; 393 return;
433 } 394 }
434 } 395 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_event_router.h ('k') | chrome/browser/extensions/extension_host.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698