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();
       }