Improve the auto-update process by also delaying updates to old-style packaged apps while the app is still in use.

BUG=301827

Review URL: https://codereview.chromium.org/45863008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232632 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index a37be367..d9e4b1ce 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/download/download_crx_util.h"
+#include "chrome/browser/extensions/browser_action_test_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
@@ -19,6 +20,7 @@
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/download_manager.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/test/download_test_observer.h"
 #include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/switches.h"
@@ -208,29 +210,6 @@
             mock_prompt->extension_id());
     ASSERT_TRUE(permissions.get());
   }
-
-  // Creates and returns a popup ExtensionHost for an extension and waits
-  // for a url to load in the host's web contents.
-  // The caller is responsible for cleaning up the returned ExtensionHost.
-  ExtensionHost* OpenUrlInExtensionPopupHost(const Extension* extension,
-                                             const GURL& url) {
-    ExtensionSystem* extension_system = extensions::ExtensionSystem::Get(
-        browser()->profile());
-    ExtensionProcessManager* epm = extension_system->process_manager();
-    ExtensionHost* extension_host =
-        epm->CreatePopupHost(extension, url, browser());
-
-    extension_host->CreateRenderViewSoon();
-    if (!extension_host->IsRenderViewLive()) {
-      content::WindowedNotificationObserver observer(
-          content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-          content::Source<content::WebContents>(
-              extension_host->host_contents()));
-      observer.Wait();
-    }
-
-    return extension_host;
-  }
 };
 
 #if defined(OS_CHROMEOS)
@@ -419,10 +398,16 @@
 
   // Make test extension non-idle by opening the extension's browser action
   // popup. This should cause the installation to be delayed.
-  std::string popup_url = std::string("chrome-extension://")
-      + extension_id + std::string("/popup.html");
-  scoped_ptr<ExtensionHost> extension_host = scoped_ptr<ExtensionHost>(
-      OpenUrlInExtensionPopupHost(extension, GURL(popup_url)));
+  content::WindowedNotificationObserver loading_observer(
+      chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
+      content::Source<Profile>(profile()));
+  BrowserActionTestUtil util(browser());
+  // There is only one extension, so just click the first browser action.
+  ASSERT_EQ(1, util.NumberOfBrowserActions());
+  util.Press(0);
+  loading_observer.Wait();
+  ExtensionHost* extension_host =
+      content::Details<ExtensionHost>(loading_observer.details()).ptr();
 
   // Install version 2 of the extension and check that it is indeed delayed.
   ASSERT_TRUE(UpdateExtensionWaitForIdle(
@@ -432,10 +417,14 @@
   extension = service->GetExtensionById(extension_id, false);
   ASSERT_EQ("1.0", extension->version()->GetString());
 
-  // Make the extension idle again by navigating away from the extension's
-  // browser action page. This should not trigger the delayed install.
-  extension_system->process_manager()->UnregisterRenderViewHost(
-      extension_host->render_view_host());
+  // Make the extension idle again by closing the popup. This should not trigger
+  //the delayed install.
+  content::WindowedNotificationObserver terminated_observer(
+      content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+      content::Source<content::RenderProcessHost>(
+          extension_host->render_process_host()));
+  extension_host->render_view_host()->ClosePage();
+  terminated_observer.Wait();
   ASSERT_EQ(1u, service->delayed_installs()->size());
 
   // Install version 3 of the extension. Because the extension is idle,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 2db9801a..8261a3ba 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -355,8 +355,6 @@
                  content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
                  content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
-                 content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
                  content::NotificationService::AllBrowserContextsAndSources());
   pref_change_registrar_.Init(profile->GetPrefs());
@@ -2497,6 +2495,23 @@
       if (!profile_->IsSameProfile(host_profile->GetOriginalProfile()))
           break;
 
+      if (process_map_.Contains(process->GetID())) {
+        // An extension process was terminated, this might have resulted in an
+        // app or extension becoming idle.
+        std::set<std::string> extension_ids =
+            process_map_.GetExtensionsInProcess(process->GetID());
+        for (std::set<std::string>::const_iterator it = extension_ids.begin();
+             it != extension_ids.end(); ++it) {
+          if (delayed_installs_.Contains(*it)) {
+            base::MessageLoop::current()->PostDelayedTask(
+                FROM_HERE,
+                base::Bind(&ExtensionService::MaybeFinishDelayedInstallation,
+                           AsWeakPtr(), *it),
+                base::TimeDelta::FromSeconds(kUpdateIdleDelay));
+          }
+        }
+      }
+
       process_map_.RemoveAllFromProcess(process->GetID());
       BrowserThread::PostTask(
           BrowserThread::IO, FROM_HERE,
@@ -2505,21 +2520,6 @@
                      process->GetID()));
       break;
     }
-    case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
-      extensions::ExtensionHost* host =
-          content::Details<extensions::ExtensionHost>(details).ptr();
-      std::string extension_id = host->extension_id();
-      if (delayed_installs_.Contains(extension_id)) {
-        // We were waiting for this extension to become idle, it now might have,
-        // so maybe finish installation.
-        base::MessageLoop::current()->PostDelayedTask(
-            FROM_HERE,
-            base::Bind(&ExtensionService::MaybeFinishDelayedInstallation,
-                       AsWeakPtr(), extension_id),
-            base::TimeDelta::FromSeconds(kUpdateIdleDelay));
-      }
-      break;
-    }
     case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
       // Notify extensions that chrome update is available.
       extensions::RuntimeEventRouter::DispatchOnBrowserUpdateAvailableEvent(
@@ -2641,6 +2641,13 @@
       process_manager->GetBackgroundHostForExtension(extension_id);
   if (host)
     return false;
+
+  content::SiteInstance* site_instance = process_manager->GetSiteInstanceForURL(
+      Extension::GetBaseURLFromExtensionId(extension_id));
+  if (site_instance && site_instance->HasProcess()) {
+    return false;
+  }
+
   return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
 }