diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 18:40:32 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 18:40:32 +0000 |
commit | bc535ee5bb4eece29f5d88bcc688613b3b208b27 (patch) | |
tree | 37b90c6bbbe98732c81515b35f02f8b835ac5df7 /chrome/browser/extensions/extension_process_manager.cc | |
parent | 7566dbf757617f9e77f4a7f9f031402eb7818b04 (diff) | |
download | chromium_src-bc535ee5bb4eece29f5d88bcc688613b3b208b27.zip chromium_src-bc535ee5bb4eece29f5d88bcc688613b3b208b27.tar.gz chromium_src-bc535ee5bb4eece29f5d88bcc688613b3b208b27.tar.bz2 |
Add support for a "split" incognito behavior for extensions.
- On by default for apps, off by default for extensions.
- Split mode means "run incognito extensions in a separate process if the user
says OK, and the two processes can only see their own profile."
- Spanning mode is what we have now, and means "run a single extension process,
but allow it to access both profiles if the user says OK."
BUG=49232
BUG=49114
TEST=extensions still work in incognito when you check "Allow in Incognito".
Review URL: http://codereview.chromium.org/3210007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58033 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/extension_process_manager.cc')
-rw-r--r-- | chrome/browser/extensions/extension_process_manager.cc | 168 |
1 files changed, 154 insertions, 14 deletions
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 49205cd..1fff690 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -21,6 +21,37 @@ #include "chrome/common/notification_service.h" #include "chrome/common/notification_type.h" #include "chrome/common/render_messages.h" +#include "chrome/common/url_constants.h" + +namespace { + +// Incognito profiles use this process manager. It is mostly a shim that decides +// whether to fall back on the original profile's ExtensionProcessManager based +// on whether a given extension uses "split" or "spanning" incognito behavior. +class IncognitoExtensionProcessManager : public ExtensionProcessManager { + public: + explicit IncognitoExtensionProcessManager(Profile* profile); + virtual ~IncognitoExtensionProcessManager() {} + virtual ExtensionHost* CreateView(Extension* extension, + const GURL& url, + Browser* browser, + ViewType::Type view_type); + virtual void CreateBackgroundHost(Extension* extension, const GURL& url); + virtual SiteInstance* GetSiteInstanceForURL(const GURL& url); + virtual RenderProcessHost* GetExtensionProcess(const GURL& url); + + private: + // NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Returns the extension for an URL, which can either be a chrome-extension + // URL or a web app URL. + Extension* GetExtensionOrAppByURL(const GURL& url); + + ExtensionProcessManager* original_manager_; +}; static void CreateBackgroundHost( ExtensionProcessManager* manager, Extension* extension) { @@ -37,6 +68,19 @@ static void CreateBackgroundHosts( } } +} // namespace + +// +// ExtensionProcessManager +// + +// static +ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) { + return (profile->IsOffTheRecord()) ? + new IncognitoExtensionProcessManager(profile) : + new ExtensionProcessManager(profile); +} + ExtensionProcessManager::ExtensionProcessManager(Profile* profile) : browsing_instance_(new BrowsingInstance(profile)) { registrar_.Add(this, NotificationType::EXTENSIONS_READY, @@ -85,7 +129,7 @@ ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, // A NULL browser may only be given for pop-up views. DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); ExtensionsService* service = - browsing_instance_->profile()->GetExtensionsService(); + browsing_instance_->profile()->GetExtensionsService(); if (service) { Extension* extension = service->GetExtensionByURL(url); if (extension) @@ -116,8 +160,12 @@ ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url, return CreateView(url, browser, ViewType::EXTENSION_INFOBAR); } -ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( +void ExtensionProcessManager::CreateBackgroundHost( Extension* extension, const GURL& url) { + // Don't create multiple background hosts for an extension. + if (GetBackgroundHostForExtension(extension)) + return; + ExtensionHost* host = #if defined(OS_MACOSX) new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url, @@ -129,16 +177,19 @@ ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view OnExtensionHostCreated(host, true); - return host; } void ExtensionProcessManager::OpenOptionsPage(Extension* extension, Browser* browser) { DCHECK(!extension->options_url().is_empty()); - // We can't open extensions URLs in incognito windows. - if (!browser || browser->profile()->IsOffTheRecord()) - browser = Browser::GetOrCreateTabbedBrowser(browsing_instance_->profile()); + // We can't open extensions URLs in incognito windows, unless the extension + // uses "split" incognito mode. + if (!browser || (browser->profile()->IsOffTheRecord() && + !extension->incognito_split_mode())) { + browser = Browser::GetOrCreateTabbedBrowser( + browsing_instance_->profile()->GetOriginalProfile()); + } browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB, PageTransition::LINK); @@ -159,6 +210,8 @@ ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( void ExtensionProcessManager::RegisterExtensionProcess( const std::string& extension_id, int process_id) { + // TODO(mpcomplete): This is the only place we actually read process_ids_. + // Is it necessary? ProcessIDMap::const_iterator it = process_ids_.find(extension_id); if (it != process_ids_.end() && (*it).second == process_id) return; @@ -197,7 +250,7 @@ RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( if (!browsing_instance_->HasSiteInstance(url)) return NULL; scoped_refptr<SiteInstance> site = - browsing_instance_->GetSiteInstanceForURL(url); + browsing_instance_->GetSiteInstanceForURL(url); if (site->HasProcess()) return site->GetProcess(); return NULL; @@ -205,13 +258,8 @@ RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( const std::string& extension_id) { - ProcessIDMap::const_iterator it = process_ids_.find(extension_id); - if (it == process_ids_.end()) - return NULL; - - RenderProcessHost* rph = RenderProcessHost::FromID(it->second); - DCHECK(rph) << "We should have unregistered this host."; - return rph; + return GetExtensionProcess( + Extension::GetBaseURLFromExtensionId(extension_id)); } SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { @@ -285,6 +333,8 @@ void ExtensionProcessManager::Observe(NotificationType type, void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, bool is_background) { + DCHECK_EQ(browsing_instance_->profile(), host->profile()); + all_hosts_.insert(host); if (is_background) background_hosts_.insert(host); @@ -301,3 +351,93 @@ void ExtensionProcessManager::CloseBackgroundHosts() { delete *current; } } + +// +// IncognitoExtensionProcessManager +// + +IncognitoExtensionProcessManager::IncognitoExtensionProcessManager( + Profile* profile) + : ExtensionProcessManager(profile), + original_manager_(profile->GetOriginalProfile()-> + GetExtensionProcessManager()) { + DCHECK(profile->IsOffTheRecord()); + + registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY, + NotificationService::AllSources()); +} + +ExtensionHost* IncognitoExtensionProcessManager::CreateView( + Extension* extension, + const GURL& url, + Browser* browser, + ViewType::Type view_type) { + if (extension->incognito_split_mode()) { + return ExtensionProcessManager::CreateView(extension, url, + browser, view_type); + } else { + return original_manager_->CreateView(extension, url, browser, view_type); + } +} + +void IncognitoExtensionProcessManager::CreateBackgroundHost( + Extension* extension, const GURL& url) { + if (extension->incognito_split_mode()) { + ExtensionProcessManager::CreateBackgroundHost(extension, url); + } else { + // Do nothing. If an extension is spanning, then its original-profile + // background page is shared with incognito, so we don't create another. + } +} + +SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL( + const GURL& url) { + Extension* extension = GetExtensionOrAppByURL(url); + if (!extension || extension->incognito_split_mode()) { + return ExtensionProcessManager::GetSiteInstanceForURL(url); + } else { + return original_manager_->GetSiteInstanceForURL(url); + } +} + +RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess( + const GURL& url) { + Extension* extension = GetExtensionOrAppByURL(url); + if (!extension || extension->incognito_split_mode()) { + return ExtensionProcessManager::GetExtensionProcess(url); + } else { + return original_manager_->GetExtensionProcess(url); + } +} + +Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL( + const GURL& url) { + ExtensionsService* service = + browsing_instance_->profile()->GetExtensionsService(); + return (url.SchemeIs(chrome::kExtensionScheme)) ? + service->GetExtensionByURL(url) : service->GetExtensionByWebExtent(url); +} + +void IncognitoExtensionProcessManager::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::BROWSER_WINDOW_READY: { + // We want to spawn our background hosts as soon as the user opens an + // incognito window. Watch for new browsers and create the hosts if + // it matches our profile. + Browser* browser = Source<Browser>(source).ptr(); + if (browser->profile() == browsing_instance_->profile()) { + ExtensionsService* service = + browsing_instance_->profile()->GetExtensionsService(); + if (service && service->is_ready()) + CreateBackgroundHosts(this, service->extensions()); + } + break; + } + default: + ExtensionProcessManager::Observe(type, source, details); + break; + } +} |