Prevent duplicate concurrent installs of the same extension

This patch stores the state of active installs in the InstallTracker
for global access. This allows various install initiators to check for
duplicate installs before proceeding.

Install progress bars in the app launcher can be initialized with the
state of an active install.

BUG=393854
TEST=unit_tests, browser_tests
For manual testing steps, please see bug.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284014 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/install_tracker.h b/chrome/browser/extensions/install_tracker.h
index 9624000..88397af 100644
--- a/chrome/browser/extensions/install_tracker.h
+++ b/chrome/browser/extensions/install_tracker.h
@@ -5,12 +5,17 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_INSTALL_TRACKER_H_
 #define CHROME_BROWSER_EXTENSIONS_INSTALL_TRACKER_H_
 
+#include <map>
+
 #include "base/observer_list.h"
 #include "base/prefs/pref_change_registrar.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/extensions/active_install_data.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/extension_registry_observer.h"
 
 class Profile;
 
@@ -21,9 +26,11 @@
 namespace extensions {
 
 class ExtensionPrefs;
+class ExtensionRegistry;
 
 class InstallTracker : public KeyedService,
-                       public content::NotificationObserver {
+                       public content::NotificationObserver,
+                       public ExtensionRegistryObserver {
  public:
   InstallTracker(Profile* profile,
                  extensions::ExtensionPrefs* prefs);
@@ -34,6 +41,22 @@
   void AddObserver(InstallObserver* observer);
   void RemoveObserver(InstallObserver* observer);
 
+  // If an install is currently in progress for |extension_id|, returns details
+  // of the installation. This instance retains ownership of the returned
+  // pointer. Returns NULL if the extension is not currently being installed.
+  const ActiveInstallData* GetActiveInstall(
+      const std::string& extension_id) const;
+
+  // Registers an install initiated by the user to allow checking of duplicate
+  // installs. Download of the extension has not necessarily started.
+  // RemoveActiveInstall() must be called when install is complete regardless of
+  // success or failure. Consider using ScopedActiveInstall rather than calling
+  // this directly.
+  void AddActiveInstall(const ActiveInstallData& install_data);
+
+  // Deregisters an active install.
+  void RemoveActiveInstall(const std::string& extension_id);
+
   void OnBeginExtensionInstall(
       const InstallObserver::ExtensionInstallParams& params);
   void OnBeginExtensionDownload(const std::string& extension_id);
@@ -57,9 +80,20 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // ExtensionRegistryObserver implementation.
+  virtual void OnExtensionInstalled(content::BrowserContext* browser_context,
+                                    const Extension* extension,
+                                    bool is_update) OVERRIDE;
+
+  // Maps extension id to the details of an active install.
+  typedef std::map<std::string, ActiveInstallData> ActiveInstallsMap;
+  ActiveInstallsMap active_installs_;
+
   ObserverList<InstallObserver> observers_;
   content::NotificationRegistrar registrar_;
   PrefChangeRegistrar pref_change_registrar_;
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+      extension_registry_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(InstallTracker);
 };