| 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/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/extension_webrequest_api.h" | 17 #include "chrome/browser/extensions/extension_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_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
| 21 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
| 22 #include "chrome/common/extensions/extension_messages.h" | 22 #include "chrome/common/extensions/extension_messages.h" |
| 23 #include "chrome/common/extensions/api/extension_api.h" | 23 #include "chrome/common/extensions/api/extension_api.h" |
| 24 #include "content/browser/child_process_security_policy.h" | 24 #include "content/browser/child_process_security_policy.h" |
| 25 #include "content/browser/renderer_host/render_process_host.h" | |
| 26 #include "content/public/browser/notification_service.h" | 25 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/render_process_host.h" |
| 27 | 27 |
| 28 using content::BrowserThread; | 28 using content::BrowserThread; |
| 29 using extensions::ExtensionAPI; | 29 using extensions::ExtensionAPI; |
| 30 | 30 |
| 31 namespace { | 31 namespace { |
| 32 | 32 |
| 33 const char kDispatchEvent[] = "Event.dispatchJSON"; | 33 const char kDispatchEvent[] = "Event.dispatchJSON"; |
| 34 | 34 |
| 35 void NotifyEventListenerRemovedOnIOThread( | 35 void NotifyEventListenerRemovedOnIOThread( |
| 36 void* profile, | 36 void* profile, |
| 37 const std::string& extension_id, | 37 const std::string& extension_id, |
| 38 const std::string& sub_event_name) { | 38 const std::string& sub_event_name) { |
| 39 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( | 39 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener( |
| 40 profile, extension_id, sub_event_name); | 40 profile, extension_id, sub_event_name); |
| 41 } | 41 } |
| 42 | 42 |
| 43 } // namespace | 43 } // namespace |
| 44 | 44 |
| 45 struct ExtensionEventRouter::EventListener { | 45 struct ExtensionEventRouter::EventListener { |
| 46 RenderProcessHost* process; | 46 content::RenderProcessHost* process; |
| 47 std::string extension_id; | 47 std::string extension_id; |
| 48 | 48 |
| 49 EventListener(RenderProcessHost* process, const std::string& extension_id) | 49 EventListener(content::RenderProcessHost* process, |
| 50 const std::string& extension_id) |
| 50 : process(process), extension_id(extension_id) {} | 51 : process(process), extension_id(extension_id) {} |
| 51 | 52 |
| 52 bool operator<(const EventListener& that) const { | 53 bool operator<(const EventListener& that) const { |
| 53 if (process < that.process) | 54 if (process < that.process) |
| 54 return true; | 55 return true; |
| 55 if (process == that.process && extension_id < that.extension_id) | 56 if (process == that.process && extension_id < that.extension_id) |
| 56 return true; | 57 return true; |
| 57 return false; | 58 return false; |
| 58 } | 59 } |
| 59 }; | 60 }; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 content::NotificationService::AllSources()); | 103 content::NotificationService::AllSources()); |
| 103 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, | 104 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, |
| 104 content::Source<Profile>(profile_)); | 105 content::Source<Profile>(profile_)); |
| 105 // TODO(tessamac): also get notified for background page crash/failure. | 106 // TODO(tessamac): also get notified for background page crash/failure. |
| 106 } | 107 } |
| 107 | 108 |
| 108 ExtensionEventRouter::~ExtensionEventRouter() {} | 109 ExtensionEventRouter::~ExtensionEventRouter() {} |
| 109 | 110 |
| 110 void ExtensionEventRouter::AddEventListener( | 111 void ExtensionEventRouter::AddEventListener( |
| 111 const std::string& event_name, | 112 const std::string& event_name, |
| 112 RenderProcessHost* process, | 113 content::RenderProcessHost* process, |
| 113 const std::string& extension_id) { | 114 const std::string& extension_id) { |
| 114 EventListener listener(process, extension_id); | 115 EventListener listener(process, extension_id); |
| 115 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; | 116 DCHECK_EQ(listeners_[event_name].count(listener), 0u) << event_name; |
| 116 listeners_[event_name].insert(listener); | 117 listeners_[event_name].insert(listener); |
| 117 | 118 |
| 118 if (extension_devtools_manager_.get()) | 119 if (extension_devtools_manager_.get()) |
| 119 extension_devtools_manager_->AddEventListener(event_name, process->id()); | 120 extension_devtools_manager_->AddEventListener(event_name, |
| 121 process->GetID()); |
| 120 | 122 |
| 121 // We lazily tell the TaskManager to start updating when listeners to the | 123 // We lazily tell the TaskManager to start updating when listeners to the |
| 122 // processes.onUpdated event arrive. | 124 // processes.onUpdated event arrive. |
| 123 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) | 125 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) |
| 124 ExtensionProcessesEventRouter::GetInstance()->ListenerAdded(); | 126 ExtensionProcessesEventRouter::GetInstance()->ListenerAdded(); |
| 125 } | 127 } |
| 126 | 128 |
| 127 void ExtensionEventRouter::RemoveEventListener( | 129 void ExtensionEventRouter::RemoveEventListener( |
| 128 const std::string& event_name, | 130 const std::string& event_name, |
| 129 RenderProcessHost* process, | 131 content::RenderProcessHost* process, |
| 130 const std::string& extension_id) { | 132 const std::string& extension_id) { |
| 131 EventListener listener(process, extension_id); | 133 EventListener listener(process, extension_id); |
| 132 DCHECK_EQ(listeners_[event_name].count(listener), 1u) << | 134 DCHECK_EQ(listeners_[event_name].count(listener), 1u) << |
| 133 " PID=" << process->id() << " extension=" << extension_id << | 135 " PID=" << process->GetID() << " extension=" << extension_id << |
| 134 " event=" << event_name; | 136 " event=" << event_name; |
| 135 listeners_[event_name].erase(listener); | 137 listeners_[event_name].erase(listener); |
| 136 // Note: extension_id may point to data in the now-deleted listeners_ object. | 138 // Note: extension_id may point to data in the now-deleted listeners_ object. |
| 137 // Do not use. | 139 // Do not use. |
| 138 | 140 |
| 139 if (extension_devtools_manager_.get()) | 141 if (extension_devtools_manager_.get()) |
| 140 extension_devtools_manager_->RemoveEventListener(event_name, process->id()); | 142 extension_devtools_manager_->RemoveEventListener(event_name, |
| 143 process->GetID()); |
| 141 | 144 |
| 142 // If a processes.onUpdated event listener is removed (or a process with one | 145 // If a processes.onUpdated event listener is removed (or a process with one |
| 143 // exits), then we let the TaskManager know that it has one fewer listener. | 146 // exits), then we let the TaskManager know that it has one fewer listener. |
| 144 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) | 147 if (event_name.compare(extension_processes_api_constants::kOnUpdated) == 0) |
| 145 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved(); | 148 ExtensionProcessesEventRouter::GetInstance()->ListenerRemoved(); |
| 146 | 149 |
| 147 BrowserThread::PostTask( | 150 BrowserThread::PostTask( |
| 148 BrowserThread::IO, FROM_HERE, | 151 BrowserThread::IO, FROM_HERE, |
| 149 base::Bind( | 152 base::Bind( |
| 150 &NotifyEventListenerRemovedOnIOThread, | 153 &NotifyEventListenerRemovedOnIOThread, |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 | 269 |
| 267 const Extension* extension = service->GetExtensionById( | 270 const Extension* extension = service->GetExtensionById( |
| 268 listener->extension_id, false); | 271 listener->extension_id, false); |
| 269 | 272 |
| 270 // The extension could have been removed, but we do not unregister it until | 273 // The extension could have been removed, but we do not unregister it until |
| 271 // the extension process is unloaded. | 274 // the extension process is unloaded. |
| 272 if (!extension) | 275 if (!extension) |
| 273 continue; | 276 continue; |
| 274 | 277 |
| 275 Profile* listener_profile = Profile::FromBrowserContext( | 278 Profile* listener_profile = Profile::FromBrowserContext( |
| 276 listener->process->browser_context()); | 279 listener->process->GetBrowserContext()); |
| 277 extensions::ProcessMap* process_map = | 280 extensions::ProcessMap* process_map = |
| 278 listener_profile->GetExtensionService()->process_map(); | 281 listener_profile->GetExtensionService()->process_map(); |
| 279 | |
| 280 // If the event is privileged, only send to extension processes. Otherwise, | 282 // If the event is privileged, only send to extension processes. Otherwise, |
| 281 // it's OK to send to normal renderers (e.g., for content scripts). | 283 // it's OK to send to normal renderers (e.g., for content scripts). |
| 282 if (ExtensionAPI::GetInstance()->IsPrivileged(event->event_name) && | 284 if (ExtensionAPI::GetInstance()->IsPrivileged(event->event_name) && |
| 283 !process_map->Contains(extension->id(), listener->process->id())) { | 285 !process_map->Contains(extension->id(), listener->process->GetID())) { |
| 284 continue; | 286 continue; |
| 285 } | 287 } |
| 286 | 288 |
| 287 // Is this event from a different profile than the renderer (ie, an | 289 // Is this event from a different profile than the renderer (ie, an |
| 288 // incognito tab event sent to a normal process, or vice versa). | 290 // incognito tab event sent to a normal process, or vice versa). |
| 289 bool cross_incognito = event->restrict_to_profile && | 291 bool cross_incognito = event->restrict_to_profile && |
| 290 listener_profile != event->restrict_to_profile; | 292 listener_profile != event->restrict_to_profile; |
| 291 // Send the event with different arguments to extensions that can't | 293 // Send the event with different arguments to extensions that can't |
| 292 // cross incognito, if necessary. | 294 // cross incognito, if necessary. |
| 293 if (cross_incognito && !service->CanCrossIncognito(extension)) { | 295 if (cross_incognito && !service->CanCrossIncognito(extension)) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 pending_events_.erase(extension_id); | 361 pending_events_.erase(extension_id); |
| 360 } | 362 } |
| 361 | 363 |
| 362 void ExtensionEventRouter::Observe( | 364 void ExtensionEventRouter::Observe( |
| 363 int type, | 365 int type, |
| 364 const content::NotificationSource& source, | 366 const content::NotificationSource& source, |
| 365 const content::NotificationDetails& details) { | 367 const content::NotificationDetails& details) { |
| 366 switch (type) { | 368 switch (type) { |
| 367 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: | 369 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: |
| 368 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 370 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
| 369 RenderProcessHost* renderer = | 371 content::RenderProcessHost* renderer = |
| 370 content::Source<RenderProcessHost>(source).ptr(); | 372 content::Source<content::RenderProcessHost>(source).ptr(); |
| 371 // Remove all event listeners associated with this renderer | 373 // Remove all event listeners associated with this renderer |
| 372 for (ListenerMap::iterator it = listeners_.begin(); | 374 for (ListenerMap::iterator it = listeners_.begin(); |
| 373 it != listeners_.end(); ) { | 375 it != listeners_.end(); ) { |
| 374 ListenerMap::iterator current_it = it++; | 376 ListenerMap::iterator current_it = it++; |
| 375 for (std::set<EventListener>::iterator jt = current_it->second.begin(); | 377 for (std::set<EventListener>::iterator jt = current_it->second.begin(); |
| 376 jt != current_it->second.end(); ) { | 378 jt != current_it->second.end(); ) { |
| 377 std::set<EventListener>::iterator current_jt = jt++; | 379 std::set<EventListener>::iterator current_jt = jt++; |
| 378 if (current_jt->process == renderer) { | 380 if (current_jt->process == renderer) { |
| 379 RemoveEventListener(current_it->first, | 381 RemoveEventListener(current_it->first, |
| 380 current_jt->process, | 382 current_jt->process, |
| 381 current_jt->extension_id); | 383 current_jt->extension_id); |
| 382 } | 384 } |
| 383 } | 385 } |
| 384 } | 386 } |
| 385 break; | 387 break; |
| 386 } | 388 } |
| 387 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { | 389 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { |
| 388 // TODO: dispatch events in queue. ExtensionHost is in the details. | 390 // TODO: dispatch events in queue. ExtensionHost is in the details. |
| 389 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr(); | 391 ExtensionHost* eh = content::Details<ExtensionHost>(details).ptr(); |
| 390 DispatchPendingEvents(eh->extension_id()); | 392 DispatchPendingEvents(eh->extension_id()); |
| 391 break; | 393 break; |
| 392 } | 394 } |
| 393 // TODO(tessamac): if background page crashed/failed clear queue. | 395 // TODO(tessamac): if background page crashed/failed clear queue. |
| 394 default: | 396 default: |
| 395 NOTREACHED(); | 397 NOTREACHED(); |
| 396 return; | 398 return; |
| 397 } | 399 } |
| 398 } | 400 } |
| OLD | NEW |