| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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_process_manager.h" | 5 #include "chrome/browser/extensions/extension_process_manager.h" |
| 6 | 6 |
| 7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
| 8 #include "chrome/browser/browser_window.h" | 8 #include "chrome/browser/browser_window.h" |
| 9 #include "chrome/browser/browsing_instance.h" | 9 #include "chrome/browser/browsing_instance.h" |
| 10 #if defined(OS_MACOSX) | 10 #if defined(OS_MACOSX) |
| 11 #include "chrome/browser/extensions/extension_host_mac.h" | 11 #include "chrome/browser/extensions/extension_host_mac.h" |
| 12 #endif | 12 #endif |
| 13 #include "chrome/browser/extensions/extension_host.h" | 13 #include "chrome/browser/extensions/extension_host.h" |
| 14 #include "chrome/browser/extensions/extensions_service.h" | 14 #include "chrome/browser/extensions/extensions_service.h" |
| 15 #include "chrome/browser/profile.h" | 15 #include "chrome/browser/profile.h" |
| 16 #include "chrome/browser/renderer_host/site_instance.h" | 16 #include "chrome/browser/renderer_host/site_instance.h" |
| 17 #include "chrome/browser/renderer_host/render_view_host.h" | 17 #include "chrome/browser/renderer_host/render_view_host.h" |
| 18 #include "chrome/browser/tab_contents/tab_contents.h" | 18 #include "chrome/browser/tab_contents/tab_contents.h" |
| 19 #include "chrome/common/extensions/extension.h" | 19 #include "chrome/common/extensions/extension.h" |
| 20 #include "chrome/common/extensions/extension_action.h" | 20 #include "chrome/common/extensions/extension_action.h" |
| 21 #include "chrome/common/notification_service.h" | 21 #include "chrome/common/notification_service.h" |
| 22 #include "chrome/common/notification_type.h" | 22 #include "chrome/common/notification_type.h" |
| 23 #include "chrome/common/render_messages.h" | 23 #include "chrome/common/render_messages.h" |
| 24 #include "chrome/common/url_constants.h" |
| 25 |
| 26 namespace { |
| 27 |
| 28 // Incognito profiles use this process manager. It is mostly a shim that decides |
| 29 // whether to fall back on the original profile's ExtensionProcessManager based |
| 30 // on whether a given extension uses "split" or "spanning" incognito behavior. |
| 31 class IncognitoExtensionProcessManager : public ExtensionProcessManager { |
| 32 public: |
| 33 explicit IncognitoExtensionProcessManager(Profile* profile); |
| 34 virtual ~IncognitoExtensionProcessManager() {} |
| 35 virtual ExtensionHost* CreateView(Extension* extension, |
| 36 const GURL& url, |
| 37 Browser* browser, |
| 38 ViewType::Type view_type); |
| 39 virtual void CreateBackgroundHost(Extension* extension, const GURL& url); |
| 40 virtual SiteInstance* GetSiteInstanceForURL(const GURL& url); |
| 41 virtual RenderProcessHost* GetExtensionProcess(const GURL& url); |
| 42 |
| 43 private: |
| 44 // NotificationObserver: |
| 45 virtual void Observe(NotificationType type, |
| 46 const NotificationSource& source, |
| 47 const NotificationDetails& details); |
| 48 |
| 49 // Returns the extension for an URL, which can either be a chrome-extension |
| 50 // URL or a web app URL. |
| 51 Extension* GetExtensionOrAppByURL(const GURL& url); |
| 52 |
| 53 ExtensionProcessManager* original_manager_; |
| 54 }; |
| 24 | 55 |
| 25 static void CreateBackgroundHost( | 56 static void CreateBackgroundHost( |
| 26 ExtensionProcessManager* manager, Extension* extension) { | 57 ExtensionProcessManager* manager, Extension* extension) { |
| 27 // Start the process for the master page, if it exists. | 58 // Start the process for the master page, if it exists. |
| 28 if (extension->background_url().is_valid()) | 59 if (extension->background_url().is_valid()) |
| 29 manager->CreateBackgroundHost(extension, extension->background_url()); | 60 manager->CreateBackgroundHost(extension, extension->background_url()); |
| 30 } | 61 } |
| 31 | 62 |
| 32 static void CreateBackgroundHosts( | 63 static void CreateBackgroundHosts( |
| 33 ExtensionProcessManager* manager, const ExtensionList* extensions) { | 64 ExtensionProcessManager* manager, const ExtensionList* extensions) { |
| 34 for (ExtensionList::const_iterator extension = extensions->begin(); | 65 for (ExtensionList::const_iterator extension = extensions->begin(); |
| 35 extension != extensions->end(); ++extension) { | 66 extension != extensions->end(); ++extension) { |
| 36 CreateBackgroundHost(manager, *extension); | 67 CreateBackgroundHost(manager, *extension); |
| 37 } | 68 } |
| 38 } | 69 } |
| 39 | 70 |
| 71 } // namespace |
| 72 |
| 73 // |
| 74 // ExtensionProcessManager |
| 75 // |
| 76 |
| 77 // static |
| 78 ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) { |
| 79 return (profile->IsOffTheRecord()) ? |
| 80 new IncognitoExtensionProcessManager(profile) : |
| 81 new ExtensionProcessManager(profile); |
| 82 } |
| 83 |
| 40 ExtensionProcessManager::ExtensionProcessManager(Profile* profile) | 84 ExtensionProcessManager::ExtensionProcessManager(Profile* profile) |
| 41 : browsing_instance_(new BrowsingInstance(profile)) { | 85 : browsing_instance_(new BrowsingInstance(profile)) { |
| 42 registrar_.Add(this, NotificationType::EXTENSIONS_READY, | 86 registrar_.Add(this, NotificationType::EXTENSIONS_READY, |
| 43 NotificationService::AllSources()); | 87 NotificationService::AllSources()); |
| 44 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | 88 registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
| 45 NotificationService::AllSources()); | 89 NotificationService::AllSources()); |
| 46 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 90 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
| 47 NotificationService::AllSources()); | 91 NotificationService::AllSources()); |
| 48 registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED, | 92 registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED, |
| 49 Source<Profile>(profile)); | 93 Source<Profile>(profile)); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 78 OnExtensionHostCreated(host, false); | 122 OnExtensionHostCreated(host, false); |
| 79 return host; | 123 return host; |
| 80 } | 124 } |
| 81 | 125 |
| 82 ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, | 126 ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, |
| 83 Browser* browser, | 127 Browser* browser, |
| 84 ViewType::Type view_type) { | 128 ViewType::Type view_type) { |
| 85 // A NULL browser may only be given for pop-up views. | 129 // A NULL browser may only be given for pop-up views. |
| 86 DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); | 130 DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); |
| 87 ExtensionsService* service = | 131 ExtensionsService* service = |
| 88 browsing_instance_->profile()->GetExtensionsService(); | 132 browsing_instance_->profile()->GetExtensionsService(); |
| 89 if (service) { | 133 if (service) { |
| 90 Extension* extension = service->GetExtensionByURL(url); | 134 Extension* extension = service->GetExtensionByURL(url); |
| 91 if (extension) | 135 if (extension) |
| 92 return CreateView(extension, url, browser, view_type); | 136 return CreateView(extension, url, browser, view_type); |
| 93 } | 137 } |
| 94 return NULL; | 138 return NULL; |
| 95 } | 139 } |
| 96 | 140 |
| 97 ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension, | 141 ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension, |
| 98 const GURL& url, | 142 const GURL& url, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 109 const GURL& url, | 153 const GURL& url, |
| 110 Browser* browser) { | 154 Browser* browser) { |
| 111 return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR); | 155 return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR); |
| 112 } | 156 } |
| 113 | 157 |
| 114 ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url, | 158 ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url, |
| 115 Browser* browser) { | 159 Browser* browser) { |
| 116 return CreateView(url, browser, ViewType::EXTENSION_INFOBAR); | 160 return CreateView(url, browser, ViewType::EXTENSION_INFOBAR); |
| 117 } | 161 } |
| 118 | 162 |
| 119 ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( | 163 void ExtensionProcessManager::CreateBackgroundHost( |
| 120 Extension* extension, const GURL& url) { | 164 Extension* extension, const GURL& url) { |
| 165 // Don't create multiple background hosts for an extension. |
| 166 if (GetBackgroundHostForExtension(extension)) |
| 167 return; |
| 168 |
| 121 ExtensionHost* host = | 169 ExtensionHost* host = |
| 122 #if defined(OS_MACOSX) | 170 #if defined(OS_MACOSX) |
| 123 new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url, | 171 new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url, |
| 124 ViewType::EXTENSION_BACKGROUND_PAGE); | 172 ViewType::EXTENSION_BACKGROUND_PAGE); |
| 125 #else | 173 #else |
| 126 new ExtensionHost(extension, GetSiteInstanceForURL(url), url, | 174 new ExtensionHost(extension, GetSiteInstanceForURL(url), url, |
| 127 ViewType::EXTENSION_BACKGROUND_PAGE); | 175 ViewType::EXTENSION_BACKGROUND_PAGE); |
| 128 #endif | 176 #endif |
| 129 | 177 |
| 130 host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view | 178 host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view |
| 131 OnExtensionHostCreated(host, true); | 179 OnExtensionHostCreated(host, true); |
| 132 return host; | |
| 133 } | 180 } |
| 134 | 181 |
| 135 void ExtensionProcessManager::OpenOptionsPage(Extension* extension, | 182 void ExtensionProcessManager::OpenOptionsPage(Extension* extension, |
| 136 Browser* browser) { | 183 Browser* browser) { |
| 137 DCHECK(!extension->options_url().is_empty()); | 184 DCHECK(!extension->options_url().is_empty()); |
| 138 | 185 |
| 139 // We can't open extensions URLs in incognito windows. | 186 // We can't open extensions URLs in incognito windows, unless the extension |
| 140 if (!browser || browser->profile()->IsOffTheRecord()) | 187 // uses "split" incognito mode. |
| 141 browser = Browser::GetOrCreateTabbedBrowser(browsing_instance_->profile()); | 188 if (!browser || (browser->profile()->IsOffTheRecord() && |
| 189 !extension->incognito_split_mode())) { |
| 190 browser = Browser::GetOrCreateTabbedBrowser( |
| 191 browsing_instance_->profile()->GetOriginalProfile()); |
| 192 } |
| 142 | 193 |
| 143 browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB, | 194 browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB, |
| 144 PageTransition::LINK); | 195 PageTransition::LINK); |
| 145 browser->window()->Show(); | 196 browser->window()->Show(); |
| 146 browser->GetSelectedTabContents()->Activate(); | 197 browser->GetSelectedTabContents()->Activate(); |
| 147 } | 198 } |
| 148 | 199 |
| 149 ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( | 200 ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( |
| 150 Extension* extension) { | 201 Extension* extension) { |
| 151 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); | 202 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); |
| 152 iter != background_hosts_.end(); ++iter) { | 203 iter != background_hosts_.end(); ++iter) { |
| 153 ExtensionHost* host = *iter; | 204 ExtensionHost* host = *iter; |
| 154 if (host->extension() == extension) | 205 if (host->extension() == extension) |
| 155 return host; | 206 return host; |
| 156 } | 207 } |
| 157 return NULL; | 208 return NULL; |
| 158 } | 209 } |
| 159 | 210 |
| 160 void ExtensionProcessManager::RegisterExtensionProcess( | 211 void ExtensionProcessManager::RegisterExtensionProcess( |
| 161 const std::string& extension_id, int process_id) { | 212 const std::string& extension_id, int process_id) { |
| 213 // TODO(mpcomplete): This is the only place we actually read process_ids_. |
| 214 // Is it necessary? |
| 162 ProcessIDMap::const_iterator it = process_ids_.find(extension_id); | 215 ProcessIDMap::const_iterator it = process_ids_.find(extension_id); |
| 163 if (it != process_ids_.end() && (*it).second == process_id) | 216 if (it != process_ids_.end() && (*it).second == process_id) |
| 164 return; | 217 return; |
| 165 | 218 |
| 166 // Extension ids should get removed from the map before the process ids get | 219 // Extension ids should get removed from the map before the process ids get |
| 167 // reused from a dead renderer. | 220 // reused from a dead renderer. |
| 168 DCHECK(it == process_ids_.end()); | 221 DCHECK(it == process_ids_.end()); |
| 169 process_ids_[extension_id] = process_id; | 222 process_ids_[extension_id] = process_id; |
| 170 | 223 |
| 171 ExtensionsService* extension_service = | 224 ExtensionsService* extension_service = |
| (...skipping 18 matching lines...) Expand all Loading... |
| 190 else | 243 else |
| 191 ++it; | 244 ++it; |
| 192 } | 245 } |
| 193 } | 246 } |
| 194 | 247 |
| 195 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( | 248 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( |
| 196 const GURL& url) { | 249 const GURL& url) { |
| 197 if (!browsing_instance_->HasSiteInstance(url)) | 250 if (!browsing_instance_->HasSiteInstance(url)) |
| 198 return NULL; | 251 return NULL; |
| 199 scoped_refptr<SiteInstance> site = | 252 scoped_refptr<SiteInstance> site = |
| 200 browsing_instance_->GetSiteInstanceForURL(url); | 253 browsing_instance_->GetSiteInstanceForURL(url); |
| 201 if (site->HasProcess()) | 254 if (site->HasProcess()) |
| 202 return site->GetProcess(); | 255 return site->GetProcess(); |
| 203 return NULL; | 256 return NULL; |
| 204 } | 257 } |
| 205 | 258 |
| 206 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( | 259 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( |
| 207 const std::string& extension_id) { | 260 const std::string& extension_id) { |
| 208 ProcessIDMap::const_iterator it = process_ids_.find(extension_id); | 261 return GetExtensionProcess( |
| 209 if (it == process_ids_.end()) | 262 Extension::GetBaseURLFromExtensionId(extension_id)); |
| 210 return NULL; | |
| 211 | |
| 212 RenderProcessHost* rph = RenderProcessHost::FromID(it->second); | |
| 213 DCHECK(rph) << "We should have unregistered this host."; | |
| 214 return rph; | |
| 215 } | 263 } |
| 216 | 264 |
| 217 SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { | 265 SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { |
| 218 return browsing_instance_->GetSiteInstanceForURL(url); | 266 return browsing_instance_->GetSiteInstanceForURL(url); |
| 219 } | 267 } |
| 220 | 268 |
| 221 bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const { | 269 bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const { |
| 222 return all_hosts_.find(host) != all_hosts_.end(); | 270 return all_hosts_.find(host) != all_hosts_.end(); |
| 223 } | 271 } |
| 224 | 272 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 break; | 326 break; |
| 279 } | 327 } |
| 280 | 328 |
| 281 default: | 329 default: |
| 282 NOTREACHED(); | 330 NOTREACHED(); |
| 283 } | 331 } |
| 284 } | 332 } |
| 285 | 333 |
| 286 void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, | 334 void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, |
| 287 bool is_background) { | 335 bool is_background) { |
| 336 DCHECK_EQ(browsing_instance_->profile(), host->profile()); |
| 337 |
| 288 all_hosts_.insert(host); | 338 all_hosts_.insert(host); |
| 289 if (is_background) | 339 if (is_background) |
| 290 background_hosts_.insert(host); | 340 background_hosts_.insert(host); |
| 291 NotificationService::current()->Notify( | 341 NotificationService::current()->Notify( |
| 292 NotificationType::EXTENSION_HOST_CREATED, | 342 NotificationType::EXTENSION_HOST_CREATED, |
| 293 Source<ExtensionProcessManager>(this), | 343 Source<ExtensionProcessManager>(this), |
| 294 Details<ExtensionHost>(host)); | 344 Details<ExtensionHost>(host)); |
| 295 } | 345 } |
| 296 | 346 |
| 297 void ExtensionProcessManager::CloseBackgroundHosts() { | 347 void ExtensionProcessManager::CloseBackgroundHosts() { |
| 298 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); | 348 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); |
| 299 iter != background_hosts_.end(); ) { | 349 iter != background_hosts_.end(); ) { |
| 300 ExtensionHostSet::iterator current = iter++; | 350 ExtensionHostSet::iterator current = iter++; |
| 301 delete *current; | 351 delete *current; |
| 302 } | 352 } |
| 303 } | 353 } |
| 354 |
| 355 // |
| 356 // IncognitoExtensionProcessManager |
| 357 // |
| 358 |
| 359 IncognitoExtensionProcessManager::IncognitoExtensionProcessManager( |
| 360 Profile* profile) |
| 361 : ExtensionProcessManager(profile), |
| 362 original_manager_(profile->GetOriginalProfile()-> |
| 363 GetExtensionProcessManager()) { |
| 364 DCHECK(profile->IsOffTheRecord()); |
| 365 |
| 366 registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY, |
| 367 NotificationService::AllSources()); |
| 368 } |
| 369 |
| 370 ExtensionHost* IncognitoExtensionProcessManager::CreateView( |
| 371 Extension* extension, |
| 372 const GURL& url, |
| 373 Browser* browser, |
| 374 ViewType::Type view_type) { |
| 375 if (extension->incognito_split_mode()) { |
| 376 return ExtensionProcessManager::CreateView(extension, url, |
| 377 browser, view_type); |
| 378 } else { |
| 379 return original_manager_->CreateView(extension, url, browser, view_type); |
| 380 } |
| 381 } |
| 382 |
| 383 void IncognitoExtensionProcessManager::CreateBackgroundHost( |
| 384 Extension* extension, const GURL& url) { |
| 385 if (extension->incognito_split_mode()) { |
| 386 ExtensionProcessManager::CreateBackgroundHost(extension, url); |
| 387 } else { |
| 388 // Do nothing. If an extension is spanning, then its original-profile |
| 389 // background page is shared with incognito, so we don't create another. |
| 390 } |
| 391 } |
| 392 |
| 393 SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL( |
| 394 const GURL& url) { |
| 395 Extension* extension = GetExtensionOrAppByURL(url); |
| 396 if (!extension || extension->incognito_split_mode()) { |
| 397 return ExtensionProcessManager::GetSiteInstanceForURL(url); |
| 398 } else { |
| 399 return original_manager_->GetSiteInstanceForURL(url); |
| 400 } |
| 401 } |
| 402 |
| 403 RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess( |
| 404 const GURL& url) { |
| 405 Extension* extension = GetExtensionOrAppByURL(url); |
| 406 if (!extension || extension->incognito_split_mode()) { |
| 407 return ExtensionProcessManager::GetExtensionProcess(url); |
| 408 } else { |
| 409 return original_manager_->GetExtensionProcess(url); |
| 410 } |
| 411 } |
| 412 |
| 413 Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL( |
| 414 const GURL& url) { |
| 415 ExtensionsService* service = |
| 416 browsing_instance_->profile()->GetExtensionsService(); |
| 417 return (url.SchemeIs(chrome::kExtensionScheme)) ? |
| 418 service->GetExtensionByURL(url) : service->GetExtensionByWebExtent(url); |
| 419 } |
| 420 |
| 421 void IncognitoExtensionProcessManager::Observe( |
| 422 NotificationType type, |
| 423 const NotificationSource& source, |
| 424 const NotificationDetails& details) { |
| 425 switch (type.value) { |
| 426 case NotificationType::BROWSER_WINDOW_READY: { |
| 427 // We want to spawn our background hosts as soon as the user opens an |
| 428 // incognito window. Watch for new browsers and create the hosts if |
| 429 // it matches our profile. |
| 430 Browser* browser = Source<Browser>(source).ptr(); |
| 431 if (browser->profile() == browsing_instance_->profile()) { |
| 432 ExtensionsService* service = |
| 433 browsing_instance_->profile()->GetExtensionsService(); |
| 434 if (service && service->is_ready()) |
| 435 CreateBackgroundHosts(this, service->extensions()); |
| 436 } |
| 437 break; |
| 438 } |
| 439 default: |
| 440 ExtensionProcessManager::Observe(type, source, details); |
| 441 break; |
| 442 } |
| 443 } |
| OLD | NEW |