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

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 broken test Created 9 years, 4 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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 const GURL& event_url) { 59 const GURL& event_url) {
57 ListValue args; 60 ListValue args;
58 args.Set(0, Value::CreateStringValue(event_name)); 61 args.Set(0, Value::CreateStringValue(event_name));
59 args.Set(1, Value::CreateStringValue(event_args)); 62 args.Set(1, Value::CreateStringValue(event_args));
60 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, 63 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
61 extension_id, kDispatchEvent, args, event_url)); 64 extension_id, kDispatchEvent, args, event_url));
62 } 65 }
63 66
64 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) 67 ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
65 : profile_(profile), 68 : profile_(profile),
66 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) { 69 extension_devtools_manager_(profile->GetExtensionDevToolsManager()),
70 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
67 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 71 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
68 NotificationService::AllSources()); 72 NotificationService::AllSources());
69 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 73 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
70 NotificationService::AllSources()); 74 NotificationService::AllSources());
75 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
76 Source<Profile>(profile_));
77 // TODO(tessamac): also get notified for background page crash/failure.
71 } 78 }
72 79
73 ExtensionEventRouter::~ExtensionEventRouter() { 80 ExtensionEventRouter::~ExtensionEventRouter() {
81 // May not be necessary...
82 task_factory_.RevokeAll();
Aaron Boodman 2011/08/23 22:41:16 Not necessary -- this happens automatically when t
Tessa MacDuff 2011/08/24 00:34:23 Done.
74 } 83 }
75 84
76 void ExtensionEventRouter::AddEventListener( 85 void ExtensionEventRouter::AddEventListener(
77 const std::string& event_name, 86 const std::string& event_name,
78 RenderProcessHost* process, 87 RenderProcessHost* process,
79 const std::string& extension_id) { 88 const std::string& extension_id) {
80 EventListener listener(process, extension_id); 89 EventListener listener(process, extension_id);
81 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; 90 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name;
82 listeners_[event_name].insert(listener); 91 listeners_[event_name].insert(listener);
83 92
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 145 }
137 return false; 146 return false;
138 } 147 }
139 148
140 void ExtensionEventRouter::DispatchEventToRenderers( 149 void ExtensionEventRouter::DispatchEventToRenderers(
141 const std::string& event_name, 150 const std::string& event_name,
142 const std::string& event_args, 151 const std::string& event_args,
143 Profile* restrict_to_profile, 152 Profile* restrict_to_profile,
144 const GURL& event_url) { 153 const GURL& event_url) {
145 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "", 154 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "",
146 event_url); 155 event_url, false);
147 } 156 }
148 157
149 void ExtensionEventRouter::DispatchEventToExtension( 158 void ExtensionEventRouter::DispatchEventToExtension(
150 const std::string& extension_id, 159 const std::string& extension_id,
151 const std::string& event_name, 160 const std::string& event_name,
152 const std::string& event_args, 161 const std::string& event_args,
153 Profile* restrict_to_profile, 162 Profile* restrict_to_profile,
154 const GURL& event_url) { 163 const GURL& event_url) {
155 DCHECK(!extension_id.empty()); 164 DCHECK(!extension_id.empty());
156 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, 165 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile,
157 "", event_url); 166 "", event_url, false);
158 } 167 }
159 168
160 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( 169 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito(
161 const std::string& event_name, 170 const std::string& event_name,
162 const std::string& event_args, 171 const std::string& event_args,
163 Profile* restrict_to_profile, 172 Profile* restrict_to_profile,
164 const std::string& cross_incognito_args, 173 const std::string& cross_incognito_args,
165 const GURL& event_url) { 174 const GURL& event_url) {
166 DispatchEventImpl("", event_name, event_args, restrict_to_profile, 175 DispatchEventImpl("", event_name, event_args, restrict_to_profile,
167 cross_incognito_args, event_url); 176 cross_incognito_args, event_url, false);
177 }
178
179 bool ExtensionEventRouter::CanDispatchEventNow(
180 const std::string& extension_id, bool was_pending) {
181 if (CommandLine::ForCurrentProcess()->HasSwitch(
182 switches::kEnableLazyBackgroundPages)) {
Aaron Boodman 2011/08/23 22:41:16 Invert test and return early to reduce indenting.
Tessa MacDuff 2011/08/24 00:34:23 Done.
183 if (extension_id.empty())
184 // TODO(tessamac): Create all background pages. Wait for all to be loaded?
185 // or dispatch event to each extension when it's ready?
186 return true;
187 const Extension* extension = profile_->GetExtensionService()->
188 GetExtensionById(extension_id, false); // exclude disabled extensions
189 if (extension && extension->background_url().is_valid()) {
190 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager();
191 if (!pm->GetBackgroundHostForExtension(extension)) {
192 // Pending events are dispatched when the background page is done
193 // loading. Maybe it was then shutdown too soon?
194 DCHECK(!was_pending);
Aaron Boodman 2011/08/23 22:41:16 Can you move this to the call site? if (!CanDispa
Tessa MacDuff 2011/08/24 00:34:23 Done. But why does this mean I don't have to mess
Aaron Boodman 2011/08/24 18:49:32 Whoops, you're right. I suspect the owner of base/
195 pm->CreateBackgroundHost(extension, extension->background_url());
196 return false;
197 }
198 }
199 }
200 return true;
168 } 201 }
169 202
170 void ExtensionEventRouter::DispatchEventImpl( 203 void ExtensionEventRouter::DispatchEventImpl(
171 const std::string& extension_id, 204 const std::string& extension_id,
172 const std::string& event_name, 205 const std::string& event_name,
173 const std::string& event_args, 206 const std::string& event_args,
174 Profile* restrict_to_profile, 207 Profile* restrict_to_profile,
175 const std::string& cross_incognito_args, 208 const std::string& cross_incognito_args,
176 const GURL& event_url) { 209 const GURL& event_url,
210 bool was_pending) {
177 if (!profile_) 211 if (!profile_)
178 return; 212 return;
179 213
180 // We don't expect to get events from a completely different profile. 214 // We don't expect to get events from a completely different profile.
181 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile)); 215 DCHECK(!restrict_to_profile || profile_->IsSameProfile(restrict_to_profile));
182 216
217 if (!CanDispatchEventNow(extension_id, was_pending)) {
218 // TODO(tessamac): make sure Background Page notification doesn't
219 // happen before the event is added to the pending list.
220 AppendEvent(extension_id, event_name, event_args, restrict_to_profile,
221 cross_incognito_args, event_url);
222 return;
223 }
224
183 ListenerMap::iterator it = listeners_.find(event_name); 225 ListenerMap::iterator it = listeners_.find(event_name);
184 if (it == listeners_.end()) 226 if (it == listeners_.end())
185 return; 227 return;
186 228
187 std::set<EventListener>& listeners = it->second; 229 std::set<EventListener>& listeners = it->second;
188 ExtensionService* service = profile_->GetExtensionService(); 230 ExtensionService* service = profile_->GetExtensionService();
189 231
190 // Send the event only to renderers that are listening for it. 232 // Send the event only to renderers that are listening for it.
191 for (std::set<EventListener>::iterator listener = listeners.begin(); 233 for (std::set<EventListener>::iterator listener = listeners.begin();
192 listener != listeners.end(); ++listener) { 234 listener != listeners.end(); ++listener) {
(...skipping 20 matching lines...) Expand all
213 event_name, cross_incognito_args, event_url); 255 event_name, cross_incognito_args, event_url);
214 } 256 }
215 continue; 257 continue;
216 } 258 }
217 259
218 DispatchEvent(listener->process, listener->extension_id, 260 DispatchEvent(listener->process, listener->extension_id,
219 event_name, event_args, event_url); 261 event_name, event_args, event_url);
220 } 262 }
221 } 263 }
222 264
265 void ExtensionEventRouter::AppendEvent(const std::string &extension_id,
266 const std::string& event_name,
267 const std::string& event_args,
268 Profile* restrict_to_profile,
269 const std::string& cross_incognito_args,
270 const GURL& event_url) {
271 // Put a new list of pending tasks into the map (more common) or get a
272 // pointer to the list that is already there (less common).
273 PendingTasksList* tasks_list = new PendingTasksList();
274 PendingTasksPerExtMap::const_iterator it = pending_tasks_.find(extension_id);
Aaron Boodman 2011/08/23 22:41:16 You do the find(), then always end up trying to in
Tessa MacDuff 2011/08/24 00:34:23 Oops I just forgot to remove that line. 'it' is ne
275 std::pair<PendingTasksPerExtMap::iterator, bool> ret = pending_tasks_.insert(
276 std::make_pair(extension_id, linked_ptr<PendingTasksList>(tasks_list)));
277 if (!ret.second) { // Insert failed.
278 // First part of return value is a pointer to what was already there.
279 tasks_list = ret.first->second.get();
280 }
281
282 // Append the new task.
283 tasks_list->push_back(linked_ptr<Task>(
284 task_factory_.NewRunnableMethod(&ExtensionEventRouter::DispatchEventImpl,
285 extension_id, event_name, event_args,
286 restrict_to_profile, cross_incognito_args,
287 event_url, true)));
288 }
289
290 void ExtensionEventRouter::DispatchPendingEvents(
291 const std::string &extension_id) {
292 // Find the list of pending tasks for this extension.
293 PendingTasksPerExtMap::const_iterator map_it =
294 pending_tasks_.find(extension_id);
295 if (map_it == pending_tasks_.end())
296 return;
297
298 // The second element is the list of tasks (the first is the key/ext id).
Aaron Boodman 2011/08/23 22:41:16 Nit: You don't have to explain this since it is cl
Tessa MacDuff 2011/08/24 00:34:23 Done.
299 PendingTasksList* tasks_list = map_it->second.get();
300 for (PendingTasksList::const_iterator it = tasks_list->begin();
301 it != tasks_list->end(); ++it)
302 it->get()->Run();
303
304 // Delete list.
305 tasks_list->clear();
306 pending_tasks_.erase(extension_id);
307 }
308
223 void ExtensionEventRouter::Observe(int type, 309 void ExtensionEventRouter::Observe(int type,
224 const NotificationSource& source, 310 const NotificationSource& source,
225 const NotificationDetails& details) { 311 const NotificationDetails& details) {
226 switch (type) { 312 switch (type) {
227 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 313 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
228 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 314 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
229 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); 315 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr();
230 // Remove all event listeners associated with this renderer 316 // Remove all event listeners associated with this renderer
231 for (ListenerMap::iterator it = listeners_.begin(); 317 for (ListenerMap::iterator it = listeners_.begin();
232 it != listeners_.end(); ) { 318 it != listeners_.end(); ) {
233 ListenerMap::iterator current_it = it++; 319 ListenerMap::iterator current_it = it++;
234 for (std::set<EventListener>::iterator jt = current_it->second.begin(); 320 for (std::set<EventListener>::iterator jt = current_it->second.begin();
235 jt != current_it->second.end(); ) { 321 jt != current_it->second.end(); ) {
236 std::set<EventListener>::iterator current_jt = jt++; 322 std::set<EventListener>::iterator current_jt = jt++;
237 if (current_jt->process == renderer) { 323 if (current_jt->process == renderer) {
238 RemoveEventListener(current_it->first, 324 RemoveEventListener(current_it->first,
239 current_jt->process, 325 current_jt->process,
240 current_jt->extension_id); 326 current_jt->extension_id);
241 } 327 }
242 } 328 }
243 } 329 }
244 break; 330 break;
245 } 331 }
332 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: {
333 // TODO: dispatch events in queue. ExtensionHost is in the details.
334 ExtensionHost* eh = Details<ExtensionHost>(details).ptr();
335 DispatchPendingEvents(eh->extension_id());
336 break;
337 }
338 // TODO(tessamac): if background page crashed/failed clear queue.
246 default: 339 default:
247 NOTREACHED(); 340 NOTREACHED();
248 return; 341 return;
249 } 342 }
250 } 343 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698