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

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

Issue 7672009: Lazy creating of background pages --enable-lazy-background-pages) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Switch from Task to ExtensionEvent Created 9 years, 3 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension_event_router.h" 5 #include "chrome/browser/extensions/extension_event_router.h"
6 6
7 #include "base/command_line.h"
7 #include "base/values.h" 8 #include "base/values.h"
8 #include "chrome/browser/extensions/extension_devtools_manager.h" 9 #include "chrome/browser/extensions/extension_devtools_manager.h"
10 #include "chrome/browser/extensions/extension_host.h"
9 #include "chrome/browser/extensions/extension_processes_api.h" 11 #include "chrome/browser/extensions/extension_processes_api.h"
10 #include "chrome/browser/extensions/extension_processes_api_constants.h" 12 #include "chrome/browser/extensions/extension_processes_api_constants.h"
11 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_tabs_module.h" 14 #include "chrome/browser/extensions/extension_tabs_module.h"
13 #include "chrome/browser/extensions/extension_webrequest_api.h" 15 #include "chrome/browser/extensions/extension_webrequest_api.h"
14 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/extension.h" 18 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_messages.h" 19 #include "chrome/common/extensions/extension_messages.h"
17 #include "content/browser/child_process_security_policy.h" 20 #include "content/browser/child_process_security_policy.h"
18 #include "content/browser/renderer_host/render_process_host.h" 21 #include "content/browser/renderer_host/render_process_host.h"
19 #include "content/common/notification_service.h" 22 #include "content/common/notification_service.h"
20 23
21 namespace { 24 namespace {
22 25
23 const char kDispatchEvent[] = "Event.dispatchJSON"; 26 const char kDispatchEvent[] = "Event.dispatchJSON";
24 27
(...skipping 16 matching lines...) Expand all
41 44
42 bool operator<(const EventListener& that) const { 45 bool operator<(const EventListener& that) const {
43 if (process < that.process) 46 if (process < that.process)
44 return true; 47 return true;
45 if (process == that.process && extension_id < that.extension_id) 48 if (process == that.process && extension_id < that.extension_id)
46 return true; 49 return true;
47 return false; 50 return false;
48 } 51 }
49 }; 52 };
50 53
54 struct ExtensionEventRouter::ExtensionEvent {
55 std::string extension_id;
56 std::string event_name;
57 std::string event_args;
58 GURL event_url;
59 Profile* restrict_to_profile;
60 std::string cross_incognito_args;
61
62 ExtensionEvent(const std::string& extension_id,
63 const std::string& event_name,
64 const std::string& event_args,
65 const GURL& event_url,
66 Profile* restrict_to_profile,
67 const std::string cross_incognito_args)
68 : extension_id(extension_id),
69 event_name(event_name),
70 event_args(event_args),
71 event_url(event_url),
72 restrict_to_profile(restrict_to_profile),
73 cross_incognito_args(cross_incognito_args) {}
74 };
75
51 // static 76 // static
52 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, 77 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender,
53 const std::string& extension_id, 78 const std::string& extension_id,
54 const std::string& event_name, 79 const std::string& event_name,
55 const std::string& event_args, 80 const std::string& event_args,
56 const GURL& event_url) { 81 const GURL& event_url) {
57 ListValue args; 82 ListValue args;
58 args.Set(0, Value::CreateStringValue(event_name)); 83 args.Set(0, Value::CreateStringValue(event_name));
59 args.Set(1, Value::CreateStringValue(event_args)); 84 args.Set(1, Value::CreateStringValue(event_args));
60 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, 85 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
61 extension_id, kDispatchEvent, args, event_url)); 86 extension_id, kDispatchEvent, args, event_url));
62 } 87 }
63 88
64 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) 89 ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
65 : profile_(profile), 90 : profile_(profile),
66 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) { 91 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) {
67 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 92 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
68 NotificationService::AllSources()); 93 NotificationService::AllSources());
69 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 94 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
70 NotificationService::AllSources()); 95 NotificationService::AllSources());
96 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
97 Source<Profile>(profile_));
98 // TODO(tessamac): also get notified for background page crash/failure.
71 } 99 }
72 100
73 ExtensionEventRouter::~ExtensionEventRouter() { 101 ExtensionEventRouter::~ExtensionEventRouter() {}
74 }
75 102
76 void ExtensionEventRouter::AddEventListener( 103 void ExtensionEventRouter::AddEventListener(
77 const std::string& event_name, 104 const std::string& event_name,
78 RenderProcessHost* process, 105 RenderProcessHost* process,
79 const std::string& extension_id) { 106 const std::string& extension_id) {
80 EventListener listener(process, extension_id); 107 EventListener listener(process, extension_id);
81 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; 108 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name;
82 listeners_[event_name].insert(listener); 109 listeners_[event_name].insert(listener);
83 110
84 if (extension_devtools_manager_.get()) 111 if (extension_devtools_manager_.get())
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 return true; 162 return true;
136 } 163 }
137 return false; 164 return false;
138 } 165 }
139 166
140 void ExtensionEventRouter::DispatchEventToRenderers( 167 void ExtensionEventRouter::DispatchEventToRenderers(
141 const std::string& event_name, 168 const std::string& event_name,
142 const std::string& event_args, 169 const std::string& event_args,
143 Profile* restrict_to_profile, 170 Profile* restrict_to_profile,
144 const GURL& event_url) { 171 const GURL& event_url) {
145 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "", 172 ExtensionEvent event("", event_name, event_args, event_url,
146 event_url); 173 restrict_to_profile, "");
174 DispatchEventImpl(event, false);
147 } 175 }
148 176
149 void ExtensionEventRouter::DispatchEventToExtension( 177 void ExtensionEventRouter::DispatchEventToExtension(
150 const std::string& extension_id, 178 const std::string& extension_id,
151 const std::string& event_name, 179 const std::string& event_name,
152 const std::string& event_args, 180 const std::string& event_args,
153 Profile* restrict_to_profile, 181 Profile* restrict_to_profile,
154 const GURL& event_url) { 182 const GURL& event_url) {
155 DCHECK(!extension_id.empty()); 183 DCHECK(!extension_id.empty());
156 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, 184 ExtensionEvent event(extension_id, event_name, event_args, event_url,
157 "", event_url); 185 restrict_to_profile, "");
186 DispatchEventImpl(event, false);
158 } 187 }
159 188
160 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( 189 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito(
161 const std::string& event_name, 190 const std::string& event_name,
162 const std::string& event_args, 191 const std::string& event_args,
163 Profile* restrict_to_profile, 192 Profile* restrict_to_profile,
164 const std::string& cross_incognito_args, 193 const std::string& cross_incognito_args,
165 const GURL& event_url) { 194 const GURL& event_url) {
166 DispatchEventImpl("", event_name, event_args, restrict_to_profile, 195 ExtensionEvent event("", event_name, event_args, event_url,
167 cross_incognito_args, event_url); 196 restrict_to_profile, cross_incognito_args);
197 DispatchEventImpl(event, false);
198 }
199
200 bool ExtensionEventRouter::CanDispatchEventNow(
201 const std::string& extension_id) {
202 if (!CommandLine::ForCurrentProcess()->HasSwitch(
203 switches::kEnableLazyBackgroundPages))
204 return true;
205
206 if (extension_id.empty())
207 // TODO(tessamac): Create all background pages. Wait for all to be loaded?
208 // or dispatch event to each extension when it's ready?
209 return true;
210
211 const Extension* extension = profile_->GetExtensionService()->
212 GetExtensionById(extension_id, false); // exclude disabled extensions
213 if (extension && extension->background_url().is_valid()) {
214 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
215 if (!pm->GetBackgroundHostForExtension(extension)) {
216 pm->CreateBackgroundHost(extension, extension->background_url());
217 return false;
218 }
219 }
220
221 return true;
168 } 222 }
169 223
170 void ExtensionEventRouter::DispatchEventImpl( 224 void ExtensionEventRouter::DispatchEventImpl(
171 const std::string& extension_id, 225 const ExtensionEvent& event, bool was_pending) {
172 const std::string& event_name,
173 const std::string& event_args,
174 Profile* restrict_to_profile,
175 const std::string& cross_incognito_args,
176 const GURL& event_url) {
177 if (!profile_) 226 if (!profile_)
178 return; 227 return;
179 228
180 // We don't expect to get events from a completely different profile. 229 // We don't expect to get events from a completely different profile.
181 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile)); 230 DCHECK(!event.restrict_to_profile ||
231 profile_->IsSameProfile(event.restrict_to_profile));
Tessa MacDuff 2011/08/29 19:21:40 When I dispatch the pending event this check fails
182 232
183 ListenerMap::iterator it = listeners_.find(event_name); 233 if (!CanDispatchEventNow(event.extension_id)) {
234 // Events should not be made pending twice. This may happen if the
235 // background page is shutdown before we finish dispatching pending events.
236 CHECK(!was_pending);
237 // TODO(tessamac): make sure Background Page notification doesn't
238 // happen before the event is added to the pending list.
239 AppendEvent(event);
240 return;
241 }
242
243 ListenerMap::iterator it = listeners_.find(event.event_name);
184 if (it == listeners_.end()) 244 if (it == listeners_.end())
185 return; 245 return;
186 246
187 std::set<EventListener>& listeners = it->second; 247 std::set<EventListener>& listeners = it->second;
188 ExtensionService* service = profile_->GetExtensionService(); 248 ExtensionService* service = profile_->GetExtensionService();
189 249
190 // Send the event only to renderers that are listening for it. 250 // Send the event only to renderers that are listening for it.
191 for (std::set<EventListener>::iterator listener = listeners.begin(); 251 for (std::set<EventListener>::iterator listener = listeners.begin();
192 listener != listeners.end(); ++listener) { 252 listener != listeners.end(); ++listener) {
193 if (!ChildProcessSecurityPolicy::GetInstance()-> 253 if (!ChildProcessSecurityPolicy::GetInstance()->
194 HasExtensionBindings(listener->process->id())) { 254 HasExtensionBindings(listener->process->id())) {
195 // Don't send browser-level events to unprivileged processes. 255 // Don't send browser-level events to unprivileged processes.
196 continue; 256 continue;
197 } 257 }
198 258
199 if (!extension_id.empty() && extension_id != listener->extension_id) 259 if (!event.extension_id.empty() &&
260 event.extension_id != listener->extension_id)
200 continue; 261 continue;
201 262
202 // Is this event from a different profile than the renderer (ie, an 263 // Is this event from a different profile than the renderer (ie, an
203 // incognito tab event sent to a normal process, or vice versa). 264 // incognito tab event sent to a normal process, or vice versa).
204 bool cross_incognito = restrict_to_profile && 265 bool cross_incognito = event.restrict_to_profile &&
205 listener->process->browser_context() != restrict_to_profile; 266 listener->process->browser_context() != event.restrict_to_profile;
206 const Extension* extension = service->GetExtensionById( 267 const Extension* extension = service->GetExtensionById(
207 listener->extension_id, false); 268 listener->extension_id, false);
208 // Send the event with different arguments to extensions that can't 269 // Send the event with different arguments to extensions that can't
209 // cross incognito, if necessary. 270 // cross incognito, if necessary.
210 if (cross_incognito && !service->CanCrossIncognito(extension)) { 271 if (cross_incognito && !service->CanCrossIncognito(extension)) {
211 if (!cross_incognito_args.empty()) { 272 if (!event.cross_incognito_args.empty()) {
212 DispatchEvent(listener->process, listener->extension_id, 273 DispatchEvent(listener->process, listener->extension_id,
213 event_name, cross_incognito_args, event_url); 274 event.event_name, event.cross_incognito_args,
275 event.event_url);
214 } 276 }
215 continue; 277 continue;
216 } 278 }
217 279
218 DispatchEvent(listener->process, listener->extension_id, 280 DispatchEvent(listener->process, listener->extension_id,
219 event_name, event_args, event_url); 281 event.event_name, event.event_args, event.event_url);
220 } 282 }
221 } 283 }
222 284
285 void ExtensionEventRouter::AppendEvent(const ExtensionEvent& pending_event) {
286 PendingEventsList* events_list = NULL;
287 PendingEventsPerExtMap::iterator it =
288 pending_events_.find(pending_event.extension_id);
289 if (it == pending_events_.end()) {
290 events_list = new PendingEventsList();
291 pending_events_[pending_event.extension_id] =
292 linked_ptr<PendingEventsList>(events_list);
293 } else {
294 events_list = it->second.get();
295 }
296
297 events_list->push_back(linked_ptr<const ExtensionEvent>(&pending_event));
298 }
299
300 void ExtensionEventRouter::DispatchPendingEvents(
301 const std::string &extension_id) {
302 // Find the list of pending events for this extension.
303 PendingEventsPerExtMap::const_iterator map_it =
304 pending_events_.find(extension_id);
305 if (map_it == pending_events_.end())
306 return;
307
308 PendingEventsList* events_list = map_it->second.get();
309 for (PendingEventsList::const_iterator it = events_list->begin();
310 it != events_list->end(); ++it)
311 DispatchEventImpl(**it, true);
312
313 // Delete list.
314 events_list->clear();
315 pending_events_.erase(extension_id);
316 }
317
223 void ExtensionEventRouter::Observe(int type, 318 void ExtensionEventRouter::Observe(int type,
224 const NotificationSource& source, 319 const NotificationSource& source,
225 const NotificationDetails& details) { 320 const NotificationDetails& details) {
226 switch (type) { 321 switch (type) {
227 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 322 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
228 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 323 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
229 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); 324 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr();
230 // Remove all event listeners associated with this renderer 325 // Remove all event listeners associated with this renderer
231 for (ListenerMap::iterator it = listeners_.begin(); 326 for (ListenerMap::iterator it = listeners_.begin();
232 it != listeners_.end(); ) { 327 it != listeners_.end(); ) {
233 ListenerMap::iterator current_it = it++; 328 ListenerMap::iterator current_it = it++;
234 for (std::set<EventListener>::iterator jt = current_it->second.begin(); 329 for (std::set<EventListener>::iterator jt = current_it->second.begin();
235 jt != current_it->second.end(); ) { 330 jt != current_it->second.end(); ) {
236 std::set<EventListener>::iterator current_jt = jt++; 331 std::set<EventListener>::iterator current_jt = jt++;
237 if (current_jt->process == renderer) { 332 if (current_jt->process == renderer) {
238 RemoveEventListener(current_it->first, 333 RemoveEventListener(current_it->first,
239 current_jt->process, 334 current_jt->process,
240 current_jt->extension_id); 335 current_jt->extension_id);
241 } 336 }
242 } 337 }
243 } 338 }
244 break; 339 break;
245 } 340 }
341 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
342 // TODO: dispatch events in queue. ExtensionHost is in the details.
343 ExtensionHost* eh = Details<ExtensionHost>(details).ptr();
344 DispatchPendingEvents(eh->extension_id());
345 break;
346 }
347 // TODO(tessamac): if background page crashed/failed clear queue.
246 default: 348 default:
247 NOTREACHED(); 349 NOTREACHED();
248 return; 350 return;
249 } 351 }
250 } 352 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698