summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_process_manager.cc
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 18:40:32 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 18:40:32 +0000
commitbc535ee5bb4eece29f5d88bcc688613b3b208b27 (patch)
tree37b90c6bbbe98732c81515b35f02f8b835ac5df7 /chrome/browser/extensions/extension_process_manager.cc
parent7566dbf757617f9e77f4a7f9f031402eb7818b04 (diff)
downloadchromium_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.cc168
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;
+ }
+}