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