Reland: Convert ExtensionProcessManager to BrowserContext, part 1
Reland of https://codereview.chromium.org/52983004/ which failed due to
timeouts on Windows XP.
Part of moving ExtensionProcessManager to src/extensions.
* Introduce more test coverage
* Convert most usage of Profile to BrowserContext
* Separate out "master" vs. incognito profiles/contexts
* Move switches into extensions/common/switches.h
BUG=313481
TEST=unit_tests ExtensionProcessManager* and browser_tests ExtensionProcessManager*
[email protected]
Review URL: https://codereview.chromium.org/57813003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232904 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index a4b2374..bb44539 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -13,7 +13,6 @@
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/extension_host.h"
@@ -22,10 +21,7 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
@@ -44,12 +40,15 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/renderer_preferences.h"
+#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/switches.h"
#if defined(OS_MACOSX)
#include "chrome/browser/extensions/extension_host_mac.h"
#endif
+using content::BrowserContext;
using content::RenderViewHost;
using content::SiteInstance;
using content::WebContents;
@@ -57,6 +56,8 @@
using extensions::BackgroundManifestHandler;
using extensions::Extension;
using extensions::ExtensionHost;
+using extensions::ExtensionsBrowserClient;
+using extensions::ExtensionSystem;
class RenderViewHostDestructionObserver;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(RenderViewHostDestructionObserver);
@@ -72,11 +73,11 @@
return render_view_host->GetSiteInstance()->GetSiteURL().host();
}
-void OnRenderViewHostUnregistered(Profile* profile,
+void OnRenderViewHostUnregistered(BrowserContext* context,
RenderViewHost* render_view_host) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
- content::Source<Profile>(profile),
+ content::Source<BrowserContext>(context),
content::Details<RenderViewHost>(render_view_host));
}
@@ -85,7 +86,8 @@
// on whether a given extension uses "split" or "spanning" incognito behavior.
class IncognitoExtensionProcessManager : public ExtensionProcessManager {
public:
- explicit IncognitoExtensionProcessManager(Profile* profile);
+ IncognitoExtensionProcessManager(BrowserContext* incognito_context,
+ BrowserContext* original_context);
virtual ~IncognitoExtensionProcessManager();
virtual ExtensionHost* CreateViewHost(
const Extension* extension,
@@ -110,6 +112,7 @@
static void CreateBackgroundHostForExtensionLoad(
ExtensionProcessManager* manager, const Extension* extension) {
+ DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
if (BackgroundInfo::HasPersistentBackgroundPage(extension))
manager->CreateBackgroundHost(extension,
BackgroundInfo::GetBackgroundURL(extension));
@@ -170,57 +173,63 @@
//
// static
-ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) {
- return (profile->IsOffTheRecord()) ?
- new IncognitoExtensionProcessManager(profile) :
- new ExtensionProcessManager(profile);
+ExtensionProcessManager* ExtensionProcessManager::Create(
+ BrowserContext* context) {
+ if (context->IsOffTheRecord()) {
+ BrowserContext* original_context =
+ ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+ return new IncognitoExtensionProcessManager(context, original_context);
+ }
+ return new ExtensionProcessManager(context, context);
}
-ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
- : site_instance_(SiteInstance::Create(profile)),
+ExtensionProcessManager::ExtensionProcessManager(
+ BrowserContext* context,
+ BrowserContext* original_context)
+ : site_instance_(SiteInstance::Create(context)),
defer_background_host_creation_(false),
- weak_ptr_factory_(this),
devtools_callback_(base::Bind(
&ExtensionProcessManager::OnDevToolsStateChanged,
- base::Unretained(this))) {
- Profile* original_profile = profile->GetOriginalProfile();
+ base::Unretained(this))),
+ weak_ptr_factory_(this) {
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
- content::Source<Profile>(original_profile));
+ content::Source<BrowserContext>(original_context));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
- content::Source<Profile>(original_profile));
+ content::Source<BrowserContext>(original_context));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
- content::Source<Profile>(original_profile));
+ content::Source<BrowserContext>(original_context));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
- content::Source<Profile>(profile));
+ content::Source<BrowserContext>(context));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- content::Source<Profile>(profile));
+ content::Source<BrowserContext>(context));
registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
- content::Source<Profile>(original_profile));
+ content::Source<BrowserContext>(original_context));
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
- content::Source<Profile>(profile));
- if (profile->IsOffTheRecord()) {
+ content::Source<BrowserContext>(context));
+ if (context->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
- content::Source<Profile>(original_profile));
+ content::Source<BrowserContext>(original_context));
}
event_page_idle_time_ = base::TimeDelta::FromSeconds(10);
unsigned idle_time_sec = 0;
if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kEventPageIdleTime), &idle_time_sec)) {
+ extensions::switches::kEventPageIdleTime), &idle_time_sec)) {
event_page_idle_time_ = base::TimeDelta::FromSeconds(idle_time_sec);
}
event_page_suspending_time_ = base::TimeDelta::FromSeconds(5);
unsigned suspending_time_sec = 0;
if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kEventPageSuspendingTime), &suspending_time_sec)) {
- event_page_suspending_time_ = base::TimeDelta::FromSeconds(
- suspending_time_sec);
+ extensions::switches::kEventPageSuspendingTime),
+ &suspending_time_sec)) {
+ event_page_suspending_time_ =
+ base::TimeDelta::FromSeconds(suspending_time_sec);
}
content::DevToolsManager::GetInstance()->AddAgentStateCallback(
@@ -249,17 +258,9 @@
Browser* browser,
extensions::ViewType view_type) {
if (!browser) {
-#if defined (OS_CHROMEOS)
- // On ChromeOS we'll only use ExtensionView, which
- // does not use the browser parameter.
- // TODO(rkc): Remove all this once we create a new host for
- // screensaver extensions (crosbug.com/28211).
- DCHECK(view_type == extensions::VIEW_TYPE_EXTENSION_POPUP ||
- view_type == extensions::VIEW_TYPE_EXTENSION_DIALOG);
-#else
- // A NULL browser may only be given for pop-up views.
- DCHECK(view_type == extensions::VIEW_TYPE_EXTENSION_POPUP);
-#endif
+ // A NULL browser may only be given for pop-up views and dialogs.
+ DCHECK(view_type == extensions::VIEW_TYPE_EXTENSION_POPUP ||
+ view_type == extensions::VIEW_TYPE_EXTENSION_DIALOG);
}
}
@@ -268,6 +269,7 @@
const GURL& url,
Browser* browser,
extensions::ViewType view_type) {
+ DVLOG(1) << "CreateViewHost";
DCHECK(extension);
EnsureBrowserWhenRequired(browser, view_type);
ExtensionHost* host =
@@ -285,7 +287,8 @@
ExtensionHost* ExtensionProcessManager::CreateViewHost(
const GURL& url, Browser* browser, extensions::ViewType view_type) {
EnsureBrowserWhenRequired(browser, view_type);
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (service) {
std::string extension_id = url.host();
if (url.SchemeIs(chrome::kChromeUIScheme) &&
@@ -327,6 +330,7 @@
ExtensionHost* ExtensionProcessManager::CreateBackgroundHost(
const Extension* extension, const GURL& url) {
+ DVLOG(1) << "CreateBackgroundHost " << url.spec();
// Hosted apps are taken care of from BackgroundContentsService. Ignore them
// here.
if (extension->is_hosted_app())
@@ -387,8 +391,8 @@
if (!render_view_host->GetSiteInstance())
return NULL;
- ExtensionService* service =
- extensions::ExtensionSystem::Get(GetProfile())->extension_service();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (!service)
return NULL;
@@ -402,7 +406,7 @@
if (view == all_extension_views_.end())
return;
- OnRenderViewHostUnregistered(GetProfile(), render_view_host);
+ OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host);
extensions::ViewType view_type = view->second;
all_extension_views_.erase(view);
@@ -613,7 +617,8 @@
browser->profile() == GetProfile()->GetOffTheRecordProfile()))
break;
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (!service || !service->is_ready())
break;
@@ -680,7 +685,7 @@
// unregister the old RVH so it doesn't count as an active view that would
// keep the event page alive.
WebContents* contents = content::Source<WebContents>(source).ptr();
- if (contents->GetBrowserContext() != GetProfile())
+ if (contents->GetBrowserContext() != GetBrowserContext())
break;
typedef std::pair<RenderViewHost*, RenderViewHost*> RVHPair;
@@ -698,7 +703,7 @@
case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
WebContents* contents = content::Source<WebContents>(source).ptr();
- if (contents->GetBrowserContext() != GetProfile())
+ if (contents->GetBrowserContext() != GetBrowserContext())
break;
const Extension* extension = GetExtensionForRenderViewHost(
contents->GetRenderViewHost());
@@ -709,7 +714,7 @@
// available), so we need to wait until now to notify.
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
- content::Source<Profile>(GetProfile()),
+ content::Source<BrowserContext>(GetBrowserContext()),
content::Details<RenderViewHost>(contents->GetRenderViewHost()));
break;
}
@@ -732,7 +737,8 @@
RenderViewHost* rvh = agent_host->GetRenderViewHost();
// Ignore unrelated notifications.
if (!rvh ||
- rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != GetProfile())
+ rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() !=
+ GetBrowserContext())
return;
if (extensions::GetViewType(WebContents::FromRenderViewHost(rvh)) !=
extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
@@ -750,6 +756,7 @@
}
void ExtensionProcessManager::CreateBackgroundHostsForProfileStartup() {
+ DVLOG(1) << "CreateBackgroundHostsForProfileStartup";
// Don't load background hosts now if the loading should be deferred.
// Instead they will be loaded when a browser window for this profile
// (or an incognito profile from this profile) is ready, or when
@@ -757,37 +764,52 @@
if (DeferLoadingBackgroundHosts())
return;
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
+ DCHECK(service);
for (ExtensionSet::const_iterator extension = service->extensions()->begin();
extension != service->extensions()->end(); ++extension) {
CreateBackgroundHostForExtensionLoad(this, extension->get());
extensions::RuntimeEventRouter::DispatchOnStartupEvent(
- GetProfile(), (*extension)->id());
+ GetBrowserContext(), (*extension)->id());
}
// Background pages should only be loaded once. To prevent any further loads
// occurring, we remove the notification listeners.
- Profile* original_profile = GetProfile()->GetOriginalProfile();
+ BrowserContext* original_context =
+ ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
content::NotificationService::AllSources());
- if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PROFILE_CREATED,
- content::Source<Profile>(original_profile)))
- registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED,
- content::Source<Profile>(original_profile));
- if (registrar_.IsRegistered(this, chrome::NOTIFICATION_EXTENSIONS_READY,
- content::Source<Profile>(original_profile)))
- registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
- content::Source<Profile>(original_profile));
+ if (registrar_.IsRegistered(
+ this,
+ chrome::NOTIFICATION_PROFILE_CREATED,
+ content::Source<BrowserContext>(original_context))) {
+ registrar_.Remove(this,
+ chrome::NOTIFICATION_PROFILE_CREATED,
+ content::Source<BrowserContext>(original_context));
+ }
+ if (registrar_.IsRegistered(
+ this,
+ chrome::NOTIFICATION_EXTENSIONS_READY,
+ content::Source<BrowserContext>(original_context))) {
+ registrar_.Remove(this,
+ chrome::NOTIFICATION_EXTENSIONS_READY,
+ content::Source<BrowserContext>(original_context));
+ }
}
Profile* ExtensionProcessManager::GetProfile() const {
return Profile::FromBrowserContext(site_instance_->GetBrowserContext());
}
+content::BrowserContext* ExtensionProcessManager::GetBrowserContext() const {
+ return site_instance_->GetBrowserContext();
+}
+
void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host,
bool is_background) {
- DCHECK_EQ(site_instance_->GetBrowserContext(), host->profile());
+ DCHECK_EQ(site_instance_->GetBrowserContext(), host->browser_context());
if (is_background) {
background_hosts_.insert(host);
@@ -826,11 +848,11 @@
// decrement the lazy_keepalive_count to negative for the new extension
// instance when they are destroyed. Since we are erasing the background page
// data for the unloaded extension, unregister the RenderViewHosts too.
- Profile* profile = GetProfile();
+ BrowserContext* context = GetBrowserContext();
for (ExtensionRenderViews::iterator it = all_extension_views_.begin();
it != all_extension_views_.end(); ) {
if (GetExtensionID(it->first) == extension_id) {
- OnRenderViewHostUnregistered(profile, it->first);
+ OnRenderViewHostUnregistered(context, it->first);
all_extension_views_.erase(it++);
} else {
++it;
@@ -859,18 +881,9 @@
if (defer_background_host_creation_)
return true;
- // The profile may not be valid yet if it is still being initialized.
- // In that case, defer loading, since it depends on an initialized profile.
- // http://crbug.com/222473
- if (!g_browser_process->profile_manager()->IsValidProfile(GetProfile()))
- return true;
-
-#if defined(OS_ANDROID)
- return false;
-#else
- return chrome::GetTotalBrowserCountForProfile(GetProfile()) == 0 &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowAppList);
-#endif
+ // The extensions embedder may have special rules about background hosts.
+ return ExtensionsBrowserClient::Get()->DeferLoadingBackgroundHosts(
+ GetBrowserContext());
}
//
@@ -878,27 +891,28 @@
//
IncognitoExtensionProcessManager::IncognitoExtensionProcessManager(
- Profile* profile)
- : ExtensionProcessManager(profile),
- original_manager_(extensions::ExtensionSystem::Get(
- profile->GetOriginalProfile())->process_manager()) {
- DCHECK(profile->IsOffTheRecord());
+ BrowserContext* incognito_context,
+ BrowserContext* original_context)
+ : ExtensionProcessManager(incognito_context, original_context),
+ original_manager_(extensions::ExtensionSystem::GetForBrowserContext(
+ original_context)->process_manager()) {
+ DCHECK(incognito_context->IsOffTheRecord());
// The original profile will have its own ExtensionProcessManager to
// load the background pages of the spanning extensions. This process
// manager need only worry about the split mode extensions, which is handled
// in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
- content::Source<Profile>(profile->GetOriginalProfile()));
+ content::Source<BrowserContext>(original_context));
registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED,
- content::Source<Profile>(profile->GetOriginalProfile()));
+ content::Source<BrowserContext>(original_context));
}
IncognitoExtensionProcessManager::~IncognitoExtensionProcessManager() {
// TODO(yoz): This cleanup code belongs in the MenuManager.
// Remove "incognito" "split" mode context menu items.
- ExtensionService* service =
- extensions::ExtensionSystem::Get(GetProfile())->extension_service();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (service)
service->menu_manager()->RemoveAllIncognitoContextItems();
}
@@ -938,7 +952,8 @@
SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
const GURL& url) {
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (service) {
const Extension* extension =
service->extensions()->GetExtensionOrAppByURL(url);
@@ -953,7 +968,8 @@
bool IncognitoExtensionProcessManager::IsIncognitoEnabled(
const Extension* extension) {
// Keep in sync with duplicate in extension_info_map.cc.
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
return extension_util::IsIncognitoEnabled(extension->id(), service);
}
@@ -973,7 +989,8 @@
// On Chrome OS, a login screen is implemented as a browser.
// This browser has no extension service. In this case,
// service will be NULL.
- ExtensionService* service = GetProfile()->GetExtensionService();
+ ExtensionService* service = ExtensionSystem::GetForBrowserContext(
+ GetBrowserContext())->extension_service();
if (service && service->is_ready())
CreateBackgroundHostsForProfileStartup();
}