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

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

Issue 9350024: Unrevert again r119770 - "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"
27 #include "content/public/browser/notification_service.h" 26 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_process_host.h"
29 28
30 using content::BrowserThread; 29 using content::BrowserThread;
31 using extensions::ExtensionAPI; 30 using extensions::ExtensionAPI;
32 31
33 namespace { 32 namespace {
34 33
35 const char kDispatchEvent[] = "Event.dispatchJSON"; 34 const char kDispatchEvent[] = "Event.dispatchJSON";
36 35
(...skipping 18 matching lines...) Expand all
55 bool operator<(const EventListener& that) const { 54 bool operator<(const EventListener& that) const {
56 if (process < that.process) 55 if (process < that.process)
57 return true; 56 return true;
58 if (process == that.process && extension_id < that.extension_id) 57 if (process == that.process && extension_id < that.extension_id)
59 return true; 58 return true;
60 return false; 59 return false;
61 } 60 }
62 }; 61 };
63 62
64 struct ExtensionEventRouter::ExtensionEvent { 63 struct ExtensionEventRouter::ExtensionEvent {
65 std::string extension_id;
66 std::string event_name; 64 std::string event_name;
67 std::string event_args; 65 std::string event_args;
68 GURL event_url; 66 GURL event_url;
69 Profile* restrict_to_profile; 67 Profile* restrict_to_profile;
70 std::string cross_incognito_args; 68 std::string cross_incognito_args;
71 69
72 ExtensionEvent(const std::string& extension_id, 70 ExtensionEvent(const std::string& event_name,
73 const std::string& event_name,
74 const std::string& event_args, 71 const std::string& event_args,
75 const GURL& event_url, 72 const GURL& event_url,
76 Profile* restrict_to_profile, 73 Profile* restrict_to_profile,
77 const std::string& cross_incognito_args) 74 const std::string& cross_incognito_args)
78 : extension_id(extension_id), 75 : event_name(event_name),
79 event_name(event_name),
80 event_args(event_args), 76 event_args(event_args),
81 event_url(event_url), 77 event_url(event_url),
82 restrict_to_profile(restrict_to_profile), 78 restrict_to_profile(restrict_to_profile),
83 cross_incognito_args(cross_incognito_args) {} 79 cross_incognito_args(cross_incognito_args) {}
84 }; 80 };
85 81
86 // static 82 // static
87 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, 83 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender,
88 const std::string& extension_id, 84 const std::string& extension_id,
89 const std::string& event_name, 85 const std::string& event_name,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) 145 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0)
150 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved(); 146 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved();
151 147
152 BrowserThread::PostTask( 148 BrowserThread::PostTask(
153 BrowserThread::IO, FROM_HERE, 149 BrowserThread::IO, FROM_HERE,
154 base::Bind( 150 base::Bind(
155 &NotifyEventListenerRemovedOnIOThread, 151 &NotifyEventListenerRemovedOnIOThread,
156 profile_, listener.extension_id, event_name)); 152 profile_, listener.extension_id, event_name));
157 } 153 }
158 154
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
159 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) { 170 bool ExtensionEventRouter::HasEventListener(const std::string& event_name) {
160 return (listeners_.find(event_name) != listeners_.end() && 171 return (listeners_.find(event_name) != listeners_.end() &&
161 !listeners_[event_name].empty()); 172 !listeners_[event_name].empty());
162 } 173 }
163 174
164 bool ExtensionEventRouter::ExtensionHasEventListener( 175 bool ExtensionEventRouter::ExtensionHasEventListener(
165 const std::string& extension_id, const std::string& event_name) { 176 const std::string& extension_id, const std::string& event_name) {
166 ListenerMap::iterator it = listeners_.find(event_name); 177 ListenerMap::iterator it = listeners_.find(event_name);
167 if (it == listeners_.end()) 178 if (it == listeners_.end())
168 return false; 179 return false;
169 180
170 std::set<EventListener>& listeners = it->second; 181 std::set<EventListener>& listeners = it->second;
171 for (std::set<EventListener>::iterator listener = listeners.begin(); 182 for (std::set<EventListener>::iterator listener = listeners.begin();
172 listener != listeners.end(); ++listener) { 183 listener != listeners.end(); ++listener) {
173 if (listener->extension_id == extension_id) 184 if (listener->extension_id == extension_id)
174 return true; 185 return true;
175 } 186 }
176 return false; 187 return false;
177 } 188 }
178 189
179 void ExtensionEventRouter::DispatchEventToRenderers( 190 void ExtensionEventRouter::DispatchEventToRenderers(
180 const std::string& event_name, 191 const std::string& event_name,
181 const std::string& event_args, 192 const std::string& event_args,
182 Profile* restrict_to_profile, 193 Profile* restrict_to_profile,
183 const GURL& event_url) { 194 const GURL& event_url) {
184 linked_ptr<ExtensionEvent> event( 195 linked_ptr<ExtensionEvent> event(
185 new ExtensionEvent("", event_name, event_args, event_url, 196 new ExtensionEvent(event_name, event_args, event_url,
186 restrict_to_profile, "")); 197 restrict_to_profile, ""));
187 DispatchEventImpl(event, false); 198 DispatchEventImpl("", event, false);
188 } 199 }
189 200
190 void ExtensionEventRouter::DispatchEventToExtension( 201 void ExtensionEventRouter::DispatchEventToExtension(
191 const std::string& extension_id, 202 const std::string& extension_id,
192 const std::string& event_name, 203 const std::string& event_name,
193 const std::string& event_args, 204 const std::string& event_args,
194 Profile* restrict_to_profile, 205 Profile* restrict_to_profile,
195 const GURL& event_url) { 206 const GURL& event_url) {
196 DCHECK(!extension_id.empty()); 207 DCHECK(!extension_id.empty());
197 linked_ptr<ExtensionEvent> event( 208 linked_ptr<ExtensionEvent> event(
198 new ExtensionEvent(extension_id, event_name, event_args, event_url, 209 new ExtensionEvent(event_name, event_args, event_url,
199 restrict_to_profile, "")); 210 restrict_to_profile, ""));
200 DispatchEventImpl(event, false); 211 DispatchEventImpl(extension_id, event, false);
201 } 212 }
202 213
203 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( 214 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito(
204 const std::string& event_name, 215 const std::string& event_name,
205 const std::string& event_args, 216 const std::string& event_args,
206 Profile* restrict_to_profile, 217 Profile* restrict_to_profile,
207 const std::string& cross_incognito_args, 218 const std::string& cross_incognito_args,
208 const GURL& event_url) { 219 const GURL& event_url) {
209 linked_ptr<ExtensionEvent> event( 220 linked_ptr<ExtensionEvent> event(
210 new ExtensionEvent("", event_name, event_args, event_url, 221 new ExtensionEvent(event_name, event_args, event_url,
211 restrict_to_profile, cross_incognito_args)); 222 restrict_to_profile, cross_incognito_args));
212 DispatchEventImpl(event, false); 223 DispatchEventImpl("", event, false);
213 } 224 }
214 225
215 bool ExtensionEventRouter::CanDispatchEventNow( 226 bool ExtensionEventRouter::CanDispatchEventNow(const Extension* extension) {
216 const std::string& extension_id) { 227 DCHECK(extension);
217 if (extension_id.empty()) 228 if (extension->has_background_page() &&
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() &&
225 !extension->background_page_persists()) { 229 !extension->background_page_persists()) {
226 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager(); 230 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
227 if (!pm->GetBackgroundHostForExtension(extension_id)) { 231
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())) {
228 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); 236 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL());
229 return false; 237 return false;
230 } 238 }
231 } 239 }
232 240
233 return true; 241 return true;
234 } 242 }
235 243
236 void ExtensionEventRouter::DispatchEventImpl( 244 void ExtensionEventRouter::DispatchEventImpl(
237 const linked_ptr<ExtensionEvent>& event, bool was_pending) { 245 const std::string& extension_id,
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
238 if (!profile_) 252 if (!profile_)
239 return; 253 return;
240 254
241 // We don't expect to get events from a completely different profile. 255 // We don't expect to get events from a completely different profile.
242 DCHECK(!event->restrict_to_profile || 256 DCHECK(!event->restrict_to_profile ||
243 profile_->IsSameProfile(event->restrict_to_profile)); 257 profile_->IsSameProfile(event->restrict_to_profile));
244 258
245 if (!CanDispatchEventNow(event->extension_id)) { 259 if (!was_pending)
246 // Events should not be made pending twice. This may happen if the 260 LoadLazyBackgroundPagesForEvent(extension_id, event);
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 }
254 261
255 ListenerMap::iterator it = listeners_.find(event->event_name); 262 ListenerMap::iterator it = listeners_.find(event->event_name);
256 if (it == listeners_.end()) 263 if (it == listeners_.end())
257 return; 264 return;
258 265
259 std::set<EventListener>& listeners = it->second; 266 std::set<EventListener>& listeners = it->second;
260 ExtensionService* service = profile_->GetExtensionService(); 267 ExtensionService* service = profile_->GetExtensionService();
261 268
262 // Send the event only to renderers that are listening for it. 269 // Send the event only to renderers that are listening for it.
263 for (std::set<EventListener>::iterator listener = listeners.begin(); 270 for (std::set<EventListener>::iterator listener = listeners.begin();
264 listener != listeners.end(); ++listener) { 271 listener != listeners.end(); ++listener) {
265 if (!event->extension_id.empty() && 272 if (!extension_id.empty() && extension_id != listener->extension_id)
266 event->extension_id != listener->extension_id)
267 continue; 273 continue;
268 274
269 const Extension* extension = service->GetExtensionById( 275 const Extension* extension = service->extensions()->GetByID(
270 listener->extension_id, false); 276 listener->extension_id);
271 277
272 // The extension could have been removed, but we do not unregister it until 278 // The extension could have been removed, but we do not unregister it until
273 // the extension process is unloaded. 279 // the extension process is unloaded.
274 if (!extension) 280 if (!extension)
275 continue; 281 continue;
276 282
277 Profile* listener_profile = Profile::FromBrowserContext( 283 Profile* listener_profile = Profile::FromBrowserContext(
278 listener->process->GetBrowserContext()); 284 listener->process->GetBrowserContext());
279 extensions::ProcessMap* process_map = 285 extensions::ProcessMap* process_map =
280 listener_profile->GetExtensionService()->process_map(); 286 listener_profile->GetExtensionService()->process_map();
(...skipping 19 matching lines...) Expand all
300 } 306 }
301 continue; 307 continue;
302 } 308 }
303 309
304 DispatchEvent(listener->process, listener->extension_id, 310 DispatchEvent(listener->process, listener->extension_id,
305 event->event_name, event->event_args, event->event_url); 311 event->event_name, event->event_args, event->event_url);
306 IncrementInFlightEvents(extension); 312 IncrementInFlightEvents(extension);
307 } 313 }
308 } 314 }
309 315
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
310 void ExtensionEventRouter::IncrementInFlightEvents(const Extension* extension) { 342 void ExtensionEventRouter::IncrementInFlightEvents(const Extension* extension) {
311 if (!extension->background_page_persists()) 343 if (!extension->background_page_persists())
312 in_flight_events_[extension->id()]++; 344 in_flight_events_[extension->id()]++;
313 } 345 }
314 346
315 void ExtensionEventRouter::OnExtensionEventAck( 347 void ExtensionEventRouter::OnExtensionEventAck(
316 const std::string& extension_id) { 348 const std::string& extension_id) {
317 CHECK(in_flight_events_[extension_id] > 0); 349 CHECK(in_flight_events_[extension_id] > 0);
318 in_flight_events_[extension_id]--; 350 in_flight_events_[extension_id]--;
319 } 351 }
320 352
321 bool ExtensionEventRouter::HasInFlightEvents(const std::string& extension_id) { 353 bool ExtensionEventRouter::HasInFlightEvents(const std::string& extension_id) {
322 return in_flight_events_[extension_id] > 0; 354 return in_flight_events_[extension_id] > 0;
323 } 355 }
324 356
325 void ExtensionEventRouter::AppendEvent( 357 void ExtensionEventRouter::AppendEvent(
358 const std::string& extension_id,
326 const linked_ptr<ExtensionEvent>& event) { 359 const linked_ptr<ExtensionEvent>& event) {
327 PendingEventsList* events_list = NULL; 360 PendingEventsList* events_list = NULL;
328 PendingEventsPerExtMap::iterator it = 361 PendingEventsPerExtMap::iterator it = pending_events_.find(extension_id);
329 pending_events_.find(event->extension_id);
330 if (it == pending_events_.end()) { 362 if (it == pending_events_.end()) {
331 events_list = new PendingEventsList(); 363 events_list = new PendingEventsList();
332 pending_events_[event->extension_id] = 364 pending_events_[extension_id] = linked_ptr<PendingEventsList>(events_list);
333 linked_ptr<PendingEventsList>(events_list);
334 } else { 365 } else {
335 events_list = it->second.get(); 366 events_list = it->second.get();
336 } 367 }
337 368
338 events_list->push_back(event); 369 events_list->push_back(event);
339 } 370 }
340 371
341 void ExtensionEventRouter::DispatchPendingEvents( 372 void ExtensionEventRouter::DispatchPendingEvents(
342 const std::string &extension_id) { 373 const std::string& extension_id) {
343 // Find the list of pending events for this extension. 374 CHECK(!extension_id.empty());
344 PendingEventsPerExtMap::const_iterator map_it = 375 PendingEventsPerExtMap::const_iterator map_it =
345 pending_events_.find(extension_id); 376 pending_events_.find(extension_id);
346 if (map_it == pending_events_.end()) 377 if (map_it == pending_events_.end())
347 return; 378 return;
348 379
349 PendingEventsList* events_list = map_it->second.get(); 380 PendingEventsList* events_list = map_it->second.get();
350 for (PendingEventsList::const_iterator it = events_list->begin(); 381 for (PendingEventsList::const_iterator it = events_list->begin();
351 it != events_list->end(); ++it) 382 it != events_list->end(); ++it)
352 DispatchEventImpl(*it, true); 383 DispatchEventImpl(extension_id, *it, true);
353 384
354 // Delete list.
355 events_list->clear(); 385 events_list->clear();
356 pending_events_.erase(extension_id); 386 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);
357 } 391 }
358 392
359 void ExtensionEventRouter::Observe( 393 void ExtensionEventRouter::Observe(
360 int type, 394 int type,
361 const content::NotificationSource& source, 395 const content::NotificationSource& source,
362 const content::NotificationDetails& details) { 396 const content::NotificationDetails& details) {
363 switch (type) { 397 switch (type) {
364 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 398 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
365 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 399 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
366 content::RenderProcessHost* renderer = 400 content::RenderProcessHost* renderer =
367 content::Source<content::RenderProcessHost>(source).ptr(); 401 content::Source<content::RenderProcessHost>(source).ptr();
368 // Remove all event listeners associated with this renderer 402 // Remove all event listeners associated with this renderer
369 for (ListenerMap::iterator it = listeners_.begin(); 403 for (ListenerMap::iterator it = listeners_.begin();
370 it != listeners_.end(); ) { 404 it != listeners_.end(); ) {
371 ListenerMap::iterator current_it = it++; 405 ListenerMap::iterator current_it = it++;
372 for (std::set<EventListener>::iterator jt = current_it->second.begin(); 406 for (std::set<EventListener>::iterator jt = current_it->second.begin();
373 jt != current_it->second.end(); ) { 407 jt != current_it->second.end(); ) {
374 std::set<EventListener>::iterator current_jt = jt++; 408 std::set<EventListener>::iterator current_jt = jt++;
375 if (current_jt->process == renderer) { 409 if (current_jt->process == renderer) {
376 RemoveEventListener(current_it->first, 410 RemoveEventListener(current_it->first,
377 current_jt->process, 411 current_jt->process,
378 current_jt->extension_id); 412 current_jt->extension_id);
379 } 413 }
380 } 414 }
381 } 415 }
382 break; 416 break;
383 } 417 }
384 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { 418 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
385 // TODO: dispatch events in queue. ExtensionHost is in the details. 419 // If an on-demand background page finished loading, dispatch queued up
420 // events for it.
386 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr(); 421 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr();
387 DispatchPendingEvents(eh->extension_id()); 422 if (eh->extension_host_type() ==
423 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
424 !eh->extension()->background_page_persists()) {
425 DispatchPendingEvents(eh->extension_id());
426 }
388 break; 427 break;
389 } 428 }
390 // TODO(tessamac): if background page crashed/failed clear queue. 429 // TODO(tessamac): if background page crashed/failed clear queue.
391 default: 430 default:
392 NOTREACHED(); 431 NOTREACHED();
393 return; 432 return;
394 } 433 }
395 } 434 }
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