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

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: fix memory leak 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 linked_ptr<ExtensionEvent> event(
146 event_url); 173 new ExtensionEvent("", event_name, event_args, event_url,
174 restrict_to_profile, ""));
175 DispatchEventImpl(event, false);
147 } 176 }
148 177
149 void ExtensionEventRouter::DispatchEventToExtension( 178 void ExtensionEventRouter::DispatchEventToExtension(
150 const std::string& extension_id, 179 const std::string& extension_id,
151 const std::string& event_name, 180 const std::string& event_name,
152 const std::string& event_args, 181 const std::string& event_args,
153 Profile* restrict_to_profile, 182 Profile* restrict_to_profile,
154 const GURL& event_url) { 183 const GURL& event_url) {
155 DCHECK(!extension_id.empty()); 184 DCHECK(!extension_id.empty());
156 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, 185 linked_ptr<ExtensionEvent> event(
157 "", event_url); 186 new ExtensionEvent(extension_id, event_name, event_args, event_url,
187 restrict_to_profile, ""));
188 DispatchEventImpl(event, false);
158 } 189 }
159 190
160 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( 191 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito(
161 const std::string& event_name, 192 const std::string& event_name,
162 const std::string& event_args, 193 const std::string& event_args,
163 Profile* restrict_to_profile, 194 Profile* restrict_to_profile,
164 const std::string& cross_incognito_args, 195 const std::string& cross_incognito_args,
165 const GURL& event_url) { 196 const GURL& event_url) {
166 DispatchEventImpl("", event_name, event_args, restrict_to_profile, 197 linked_ptr<ExtensionEvent> event(
167 cross_incognito_args, event_url); 198 new ExtensionEvent("", event_name, event_args, event_url,
199 restrict_to_profile, cross_incognito_args));
200 DispatchEventImpl(event, false);
201 }
202
203 bool ExtensionEventRouter::CanDispatchEventNow(
204 const std::string& extension_id) {
205 if (!CommandLine::ForCurrentProcess()->HasSwitch(
206 switches::kEnableLazyBackgroundPages))
207 return true;
208
209 if (extension_id.empty())
210 // TODO(tessamac): Create all background pages. Wait for all to be loaded?
211 // or dispatch event to each extension when it's ready?
212 return true;
213
214 const Extension* extension = profile_->GetExtensionService()->
215 GetExtensionById(extension_id, false); // exclude disabled extensions
216 if (extension && extension->background_url().is_valid()) {
217 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
218 if (!pm->GetBackgroundHostForExtension(extension)) {
219 pm->CreateBackgroundHost(extension, extension->background_url());
220 return false;
221 }
222 }
223
224 return true;
168 } 225 }
169 226
170 void ExtensionEventRouter::DispatchEventImpl( 227 void ExtensionEventRouter::DispatchEventImpl(
171 const std::string& extension_id, 228 const linked_ptr<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_) 229 if (!profile_)
178 return; 230 return;
179 231
180 // We don't expect to get events from a completely different profile. 232 // We don't expect to get events from a completely different profile.
181 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile)); 233 DCHECK(!event->restrict_to_profile ||
234 profile_->IsSameProfile(event->restrict_to_profile));
182 235
183 ListenerMap::iterator it = listeners_.find(event_name); 236 if (!CanDispatchEventNow(event->extension_id)) {
237 // Events should not be made pending twice. This may happen if the
238 // background page is shutdown before we finish dispatching pending events.
239 CHECK(!was_pending);
240 // TODO(tessamac): make sure Background Page notification doesn't
241 // happen before the event is added to the pending list.
242 AppendEvent(event);
243 return;
244 }
245
246 ListenerMap::iterator it = listeners_.find(event->event_name);
184 if (it == listeners_.end()) 247 if (it == listeners_.end())
185 return; 248 return;
186 249
187 std::set<EventListener>& listeners = it->second; 250 std::set<EventListener>& listeners = it->second;
188 ExtensionService* service = profile_->GetExtensionService(); 251 ExtensionService* service = profile_->GetExtensionService();
189 252
190 // Send the event only to renderers that are listening for it. 253 // Send the event only to renderers that are listening for it.
191 for (std::set<EventListener>::iterator listener = listeners.begin(); 254 for (std::set<EventListener>::iterator listener = listeners.begin();
192 listener != listeners.end(); ++listener) { 255 listener != listeners.end(); ++listener) {
193 if (!ChildProcessSecurityPolicy::GetInstance()-> 256 if (!ChildProcessSecurityPolicy::GetInstance()->
194 HasExtensionBindings(listener->process->id())) { 257 HasExtensionBindings(listener->process->id())) {
195 // Don't send browser-level events to unprivileged processes. 258 // Don't send browser-level events to unprivileged processes.
196 continue; 259 continue;
197 } 260 }
198 261
199 if (!extension_id.empty() && extension_id != listener->extension_id) 262 if (!event->extension_id.empty() &&
263 event->extension_id != listener->extension_id)
200 continue; 264 continue;
201 265
202 // Is this event from a different profile than the renderer (ie, an 266 // Is this event from a different profile than the renderer (ie, an
203 // incognito tab event sent to a normal process, or vice versa). 267 // incognito tab event sent to a normal process, or vice versa).
204 bool cross_incognito = restrict_to_profile && 268 bool cross_incognito = event->restrict_to_profile &&
205 listener->process->browser_context() != restrict_to_profile; 269 listener->process->browser_context() != event->restrict_to_profile;
206 const Extension* extension = service->GetExtensionById( 270 const Extension* extension = service->GetExtensionById(
207 listener->extension_id, false); 271 listener->extension_id, false);
208 // Send the event with different arguments to extensions that can't 272 // Send the event with different arguments to extensions that can't
209 // cross incognito, if necessary. 273 // cross incognito, if necessary.
210 if (cross_incognito && !service->CanCrossIncognito(extension)) { 274 if (cross_incognito && !service->CanCrossIncognito(extension)) {
211 if (!cross_incognito_args.empty()) { 275 if (!event->cross_incognito_args.empty()) {
212 DispatchEvent(listener->process, listener->extension_id, 276 DispatchEvent(listener->process, listener->extension_id,
213 event_name, cross_incognito_args, event_url); 277 event->event_name, event->cross_incognito_args,
278 event->event_url);
214 } 279 }
215 continue; 280 continue;
216 } 281 }
217 282
218 DispatchEvent(listener->process, listener->extension_id, 283 DispatchEvent(listener->process, listener->extension_id,
219 event_name, event_args, event_url); 284 event->event_name, event->event_args, event->event_url);
220 } 285 }
221 } 286 }
222 287
288 void ExtensionEventRouter::AppendEvent(
289 const linked_ptr<ExtensionEvent>& event) {
290 PendingEventsList* events_list = NULL;
291 PendingEventsPerExtMap::iterator it =
292 pending_events_.find(event->extension_id);
293 if (it == pending_events_.end()) {
294 events_list = new PendingEventsList();
295 pending_events_[event->extension_id] =
296 linked_ptr<PendingEventsList>(events_list);
297 } else {
298 events_list = it->second.get();
299 }
300
301 events_list->push_back(event);
302 }
303
304 void ExtensionEventRouter::DispatchPendingEvents(
305 const std::string &extension_id) {
306 // Find the list of pending events for this extension.
307 PendingEventsPerExtMap::const_iterator map_it =
308 pending_events_.find(extension_id);
309 if (map_it == pending_events_.end())
310 return;
311
312 PendingEventsList* events_list = map_it->second.get();
313 for (PendingEventsList::const_iterator it = events_list->begin();
314 it != events_list->end(); ++it)
315 DispatchEventImpl(*it, true);
316
317 // Delete list.
318 events_list->clear();
319 pending_events_.erase(extension_id);
320 }
321
223 void ExtensionEventRouter::Observe(int type, 322 void ExtensionEventRouter::Observe(int type,
224 const NotificationSource& source, 323 const NotificationSource& source,
225 const NotificationDetails& details) { 324 const NotificationDetails& details) {
226 switch (type) { 325 switch (type) {
227 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 326 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
228 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 327 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
229 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); 328 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr();
230 // Remove all event listeners associated with this renderer 329 // Remove all event listeners associated with this renderer
231 for (ListenerMap::iterator it = listeners_.begin(); 330 for (ListenerMap::iterator it = listeners_.begin();
232 it != listeners_.end(); ) { 331 it != listeners_.end(); ) {
233 ListenerMap::iterator current_it = it++; 332 ListenerMap::iterator current_it = it++;
234 for (std::set<EventListener>::iterator jt = current_it->second.begin(); 333 for (std::set<EventListener>::iterator jt = current_it->second.begin();
235 jt != current_it->second.end(); ) { 334 jt != current_it->second.end(); ) {
236 std::set<EventListener>::iterator current_jt = jt++; 335 std::set<EventListener>::iterator current_jt = jt++;
237 if (current_jt->process == renderer) { 336 if (current_jt->process == renderer) {
238 RemoveEventListener(current_it->first, 337 RemoveEventListener(current_it->first,
239 current_jt->process, 338 current_jt->process,
240 current_jt->extension_id); 339 current_jt->extension_id);
241 } 340 }
242 } 341 }
243 } 342 }
244 break; 343 break;
245 } 344 }
345 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
346 // TODO: dispatch events in queue. ExtensionHost is in the details.
347 ExtensionHost* eh = Details<ExtensionHost>(details).ptr();
348 DispatchPendingEvents(eh->extension_id());
349 break;
350 }
351 // TODO(tessamac): if background page crashed/failed clear queue.
246 default: 352 default:
247 NOTREACHED(); 353 NOTREACHED();
248 return; 354 return;
249 } 355 }
250 } 356 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_event_router.h ('k') | chrome/browser/extensions/extension_menu_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698