OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |