Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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::PendingEvent { | |
| 55 std::string name; | |
| 56 std::string args; | |
| 57 Profile* restrict_to_profile; | |
| 58 std::string cross_incognito_args; | |
| 59 GURL url; | |
| 60 | |
| 61 PendingEvent(const std::string& name, const std::string& args, | |
| 62 Profile* restrict_to_profile, | |
| 63 const std::string& cross_incognito_args, const GURL& url) | |
| 64 : name(name), args(args), restrict_to_profile(restrict_to_profile), | |
| 65 cross_incognito_args(cross_incognito_args), url(url) {} | |
| 66 }; | |
| 67 | |
| 51 // static | 68 // static |
| 52 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, | 69 void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender, |
| 53 const std::string& extension_id, | 70 const std::string& extension_id, |
| 54 const std::string& event_name, | 71 const std::string& event_name, |
| 55 const std::string& event_args, | 72 const std::string& event_args, |
| 56 const GURL& event_url) { | 73 const GURL& event_url) { |
| 57 ListValue args; | 74 ListValue args; |
| 58 args.Set(0, Value::CreateStringValue(event_name)); | 75 args.Set(0, Value::CreateStringValue(event_name)); |
| 59 args.Set(1, Value::CreateStringValue(event_args)); | 76 args.Set(1, Value::CreateStringValue(event_args)); |
| 60 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, | 77 ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL, |
| 61 extension_id, kDispatchEvent, args, event_url)); | 78 extension_id, kDispatchEvent, args, event_url)); |
| 62 } | 79 } |
| 63 | 80 |
| 64 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) | 81 ExtensionEventRouter::ExtensionEventRouter(Profile* profile) |
| 65 : profile_(profile), | 82 : profile_(profile), |
| 66 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) { | 83 extension_devtools_manager_(profile->GetExtensionDevToolsManager()) { |
| 67 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 84 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 68 NotificationService::AllSources()); | 85 NotificationService::AllSources()); |
| 69 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 86 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| 70 NotificationService::AllSources()); | 87 NotificationService::AllSources()); |
| 88 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, | |
| 89 Source<Profile>(profile_)); | |
| 90 // TODO(tessamac): also get notified for background page crash/failure. | |
| 71 } | 91 } |
| 72 | 92 |
| 73 ExtensionEventRouter::~ExtensionEventRouter() { | 93 ExtensionEventRouter::~ExtensionEventRouter() { |
| 74 } | 94 } |
| 75 | 95 |
| 76 void ExtensionEventRouter::AddEventListener( | 96 void ExtensionEventRouter::AddEventListener( |
| 77 const std::string& event_name, | 97 const std::string& event_name, |
| 78 RenderProcessHost* process, | 98 RenderProcessHost* process, |
| 79 const std::string& extension_id) { | 99 const std::string& extension_id) { |
| 80 EventListener listener(process, extension_id); | 100 EventListener listener(process, extension_id); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 return true; | 155 return true; |
| 136 } | 156 } |
| 137 return false; | 157 return false; |
| 138 } | 158 } |
| 139 | 159 |
| 140 void ExtensionEventRouter::DispatchEventToRenderers( | 160 void ExtensionEventRouter::DispatchEventToRenderers( |
| 141 const std::string& event_name, | 161 const std::string& event_name, |
| 142 const std::string& event_args, | 162 const std::string& event_args, |
| 143 Profile* restrict_to_profile, | 163 Profile* restrict_to_profile, |
| 144 const GURL& event_url) { | 164 const GURL& event_url) { |
| 145 DispatchEventImpl("", event_name, event_args, restrict_to_profile, "", | 165 MaybeDispatchEventImpl("", event_name, event_args, restrict_to_profile, "", |
| 146 event_url); | 166 event_url); |
| 147 } | 167 } |
| 148 | 168 |
| 149 void ExtensionEventRouter::DispatchEventToExtension( | 169 void ExtensionEventRouter::DispatchEventToExtension( |
| 150 const std::string& extension_id, | 170 const std::string& extension_id, |
| 151 const std::string& event_name, | 171 const std::string& event_name, |
| 152 const std::string& event_args, | 172 const std::string& event_args, |
| 153 Profile* restrict_to_profile, | 173 Profile* restrict_to_profile, |
| 154 const GURL& event_url) { | 174 const GURL& event_url) { |
| 155 DCHECK(!extension_id.empty()); | 175 DCHECK(!extension_id.empty()); |
| 156 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, | 176 MaybeDispatchEventImpl(extension_id, event_name, event_args, |
| 157 "", event_url); | 177 restrict_to_profile, "", event_url); |
| 158 } | 178 } |
| 159 | 179 |
| 160 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( | 180 void ExtensionEventRouter::DispatchEventsToRenderersAcrossIncognito( |
| 161 const std::string& event_name, | 181 const std::string& event_name, |
| 162 const std::string& event_args, | 182 const std::string& event_args, |
| 163 Profile* restrict_to_profile, | 183 Profile* restrict_to_profile, |
| 164 const std::string& cross_incognito_args, | 184 const std::string& cross_incognito_args, |
| 165 const GURL& event_url) { | 185 const GURL& event_url) { |
| 166 DispatchEventImpl("", event_name, event_args, restrict_to_profile, | 186 MaybeDispatchEventImpl("", event_name, event_args, restrict_to_profile, |
| 187 cross_incognito_args, event_url); | |
| 188 } | |
| 189 | |
| 190 void ExtensionEventRouter::MaybeDispatchEventImpl( | |
|
Aaron Boodman
2011/08/18 19:25:55
Another 'maybe' function. You could eliminate this
Tessa MacDuff
2011/08/23 18:18:42
Done.
| |
| 191 const std::string& extension_id, | |
| 192 const std::string& event_name, | |
| 193 const std::string& event_args, | |
| 194 Profile* restrict_to_profile, | |
| 195 const std::string& cross_incognito_args, | |
| 196 const GURL& event_url) { | |
| 197 if (!profile_) | |
| 198 return; | |
| 199 | |
| 200 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 201 switches::kEnableLazyBackgroundPages) && | |
| 202 !extension_id.empty()) { | |
| 203 // TODO(tessamac): Decide what to when there's no extension id. | |
| 204 // Create all background pages? | |
|
Aaron Boodman
2011/08/18 19:25:55
I think creating all background pages is the right
Tessa MacDuff
2011/08/23 18:18:42
I think I'll do this in a separate CL as since it
| |
| 205 const Extension* extension = profile_->GetExtensionService()-> | |
| 206 GetExtensionById(extension_id, false); // exclude disable extensions | |
| 207 if (extension && extension->background_url().is_valid()) { | |
| 208 ExtensionProcessManager* pm = profile_->GetExtensionProcessManager(); | |
| 209 if (pm->GetBackgroundHostForExtension(extension) == NULL) { | |
| 210 EnqueueEvent(extension_id, event_name, event_args, restrict_to_profile, | |
| 211 cross_incognito_args, event_url); | |
| 212 pm->CreateBackgroundHost(extension, extension->background_url()); | |
| 213 return; | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 } | |
| 218 | |
| 219 DispatchEventImpl(extension_id, event_name, event_args, restrict_to_profile, | |
| 167 cross_incognito_args, event_url); | 220 cross_incognito_args, event_url); |
| 168 } | 221 } |
| 169 | 222 |
| 170 void ExtensionEventRouter::DispatchEventImpl( | 223 void ExtensionEventRouter::DispatchEventImpl( |
| 171 const std::string& extension_id, | 224 const std::string& extension_id, |
| 172 const std::string& event_name, | 225 const std::string& event_name, |
| 173 const std::string& event_args, | 226 const std::string& event_args, |
| 174 Profile* restrict_to_profile, | 227 Profile* restrict_to_profile, |
| 175 const std::string& cross_incognito_args, | 228 const std::string& cross_incognito_args, |
| 176 const GURL& event_url) { | 229 const GURL& event_url) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 event_name, cross_incognito_args, event_url); | 266 event_name, cross_incognito_args, event_url); |
| 214 } | 267 } |
| 215 continue; | 268 continue; |
| 216 } | 269 } |
| 217 | 270 |
| 218 DispatchEvent(listener->process, listener->extension_id, | 271 DispatchEvent(listener->process, listener->extension_id, |
| 219 event_name, event_args, event_url); | 272 event_name, event_args, event_url); |
| 220 } | 273 } |
| 221 } | 274 } |
| 222 | 275 |
| 276 void ExtensionEventRouter::EnqueueEvent(const std::string &extension_id, | |
| 277 const std::string& event_name, | |
| 278 const std::string& event_args, | |
| 279 Profile* restrict_to_profile, | |
| 280 const std::string& cross_incognito_args, | |
| 281 const GURL& event_url) { | |
| 282 PendingEvent event(event_name, event_args, restrict_to_profile, | |
| 283 cross_incognito_args, event_url); | |
| 284 // TODO: use insert instead of []. | |
| 285 pending_events_[extension_id].push_back(event); | |
|
Aaron Boodman
2011/08/18 19:25:55
I'm fine with this for now, but just so you know t
Tessa MacDuff
2011/08/23 18:18:42
Done.
| |
| 286 } | |
| 287 | |
| 288 void ExtensionEventRouter::ClearPendingEvents(const std::string &extension_id) { | |
| 289 pending_events_[extension_id].clear(); | |
|
Aaron Boodman
2011/08/18 19:29:06
Little nit: If these one-liner methods aren't call
Tessa MacDuff
2011/08/23 18:18:42
Done.
I had to add an additional NewRunnableMetho
| |
| 290 } | |
| 291 | |
| 292 void ExtensionEventRouter::DispatchPendingEvents( | |
| 293 const std::string &extension_id) { | |
| 294 const PendingEventsQueue& queue = pending_events_[extension_id]; | |
| 295 for (PendingEventsQueue::const_iterator it = queue.begin(); | |
| 296 it != queue.end(); ++it) { | |
| 297 // Don't call MaybeDispatchEventImpl() to guard against these events | |
| 298 // being re-enqueued if the Background Page still isn't all set. | |
|
Aaron Boodman
2011/08/18 19:29:06
Oh, I see. I don't think it's a big deal if they g
Tessa MacDuff
2011/08/18 20:49:39
I was worried about what would happen if we were a
Aaron Boodman
2011/08/18 21:19:23
ok (to extra arg).
Tessa MacDuff
2011/08/23 18:18:42
Done.
| |
| 299 DispatchEventImpl(extension_id, it->name, it->args, it->restrict_to_profile, | |
| 300 it->cross_incognito_args, it->url); | |
| 301 } | |
| 302 ClearPendingEvents(extension_id); | |
| 303 } | |
| 304 | |
| 223 void ExtensionEventRouter::Observe(int type, | 305 void ExtensionEventRouter::Observe(int type, |
| 224 const NotificationSource& source, | 306 const NotificationSource& source, |
| 225 const NotificationDetails& details) { | 307 const NotificationDetails& details) { |
| 226 switch (type) { | 308 switch (type) { |
| 227 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: | 309 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: |
| 228 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 310 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
| 229 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); | 311 RenderProcessHost* renderer = Source<RenderProcessHost>(source).ptr(); |
| 230 // Remove all event listeners associated with this renderer | 312 // Remove all event listeners associated with this renderer |
| 231 for (ListenerMap::iterator it = listeners_.begin(); | 313 for (ListenerMap::iterator it = listeners_.begin(); |
| 232 it != listeners_.end(); ) { | 314 it != listeners_.end(); ) { |
| 233 ListenerMap::iterator current_it = it++; | 315 ListenerMap::iterator current_it = it++; |
| 234 for (std::set<EventListener>::iterator jt = current_it->second.begin(); | 316 for (std::set<EventListener>::iterator jt = current_it->second.begin(); |
| 235 jt != current_it->second.end(); ) { | 317 jt != current_it->second.end(); ) { |
| 236 std::set<EventListener>::iterator current_jt = jt++; | 318 std::set<EventListener>::iterator current_jt = jt++; |
| 237 if (current_jt->process == renderer) { | 319 if (current_jt->process == renderer) { |
| 238 RemoveEventListener(current_it->first, | 320 RemoveEventListener(current_it->first, |
| 239 current_jt->process, | 321 current_jt->process, |
| 240 current_jt->extension_id); | 322 current_jt->extension_id); |
| 241 } | 323 } |
| 242 } | 324 } |
| 243 } | 325 } |
| 244 break; | 326 break; |
| 245 } | 327 } |
| 328 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { | |
| 329 // TODO: dispatch events in queue. ExtensionHost is in the details. | |
| 330 ExtensionHost* eh = Details<ExtensionHost>(details).ptr(); | |
| 331 DispatchPendingEvents(eh->extension_id()); | |
| 332 break; | |
| 333 } | |
| 334 // TODO(tessamac): if background page crashed/failed clear queue. | |
| 246 default: | 335 default: |
| 247 NOTREACHED(); | 336 NOTREACHED(); |
| 248 return; | 337 return; |
| 249 } | 338 } |
| 250 } | 339 } |
| OLD | NEW |