Fix double install and incorrect uninstall of external extensions.

BUG=chromium-os:7037
TEST=ExtensionsserviceTest.External*,ExtensionManagementTest.ExternalUrlUpdate

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=63733

Review URL: http://codereview.chromium.org/3966001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63738 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 33fade0..feb12941 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -185,16 +185,14 @@
   // For the extension in |version_path| with |id|, check to see if it's an
   // externally managed extension.  If so, tell the frontend to uninstall it.
   void CheckExternalUninstall(scoped_refptr<ExtensionsService> frontend,
-                              const std::string& id,
-                              Extension::Location location);
+                              const std::string& id);
 
   // Clear all ExternalExtensionProviders.
   void ClearProvidersForTesting();
 
-  // Sets an ExternalExtensionProvider for the service to use during testing.
-  // |location| specifies what type of provider should be added.
-  void SetProviderForTesting(Extension::Location location,
-                             ExternalExtensionProvider* test_provider);
+  // Adds an ExternalExtensionProvider for the service to use during testing.
+  // Takes ownership of |test_provider|.
+  void AddProviderForTesting(ExternalExtensionProvider* test_provider);
 
   // ExternalExtensionProvider::Visitor implementation.
   virtual void OnExternalExtensionFileFound(const std::string& id,
@@ -233,16 +231,6 @@
   void ReportExtensionLoadError(const FilePath& extension_path,
                                 const std::string& error);
 
-  // Lookup an external extension by |id| by going through all registered
-  // external extension providers until we find a provider that contains an
-  // extension that matches. If |version| is not NULL, the extension version
-  // will be returned (caller is responsible for deleting that pointer).
-  // |location| can also be null, if not needed. Returns true if extension is
-  // found, false otherwise.
-  bool LookupExternalExtension(const std::string& id,
-                               Version** version,
-                               Extension::Location* location);
-
   // This is a naked pointer which is set by each entry point.
   // The entry point is responsible for ensuring lifetime.
   ExtensionsService* frontend_;
@@ -253,12 +241,12 @@
   // Whether errors result in noisy alerts.
   bool alert_on_error_;
 
-  // A map from external extension type to the external extension provider
-  // for that type.  Because a single provider may handle more than one
-  // external extension type, more than one key may map to the same object.
-  typedef std::map<Extension::Location,
-                   linked_ptr<ExternalExtensionProvider> > ProviderMap;
-  ProviderMap external_extension_providers_;
+  // A collection of external extension providers.  Each provider reads
+  // a source of external extension information.  Examples include the
+  // windows registry and external_extensions.json.
+  typedef std::vector<linked_ptr<ExternalExtensionProvider> >
+      ProviderCollection;
+  ProviderCollection external_extension_providers_;
 
   // Set to true by OnExternalExtensionUpdateUrlFound() when an external
   // extension URL is found.  Used in CheckForExternalUpdates() to see
@@ -281,17 +269,13 @@
   // TODO(aa): This ends up doing blocking IO on the UI thread because it reads
   // pref data in the ctor and that is called on the UI thread. Would be better
   // to re-read data each time we list external extensions, anyway.
-  external_extension_providers_[Extension::EXTERNAL_PREF] =
+  external_extension_providers_.push_back(
       linked_ptr<ExternalExtensionProvider>(
-          new ExternalPrefExtensionProvider());
-  // EXTERNAL_PREF_DOWNLOAD and EXTERNAL_PREF extensions are handled by the
-  // same object.
-  external_extension_providers_[Extension::EXTERNAL_PREF_DOWNLOAD] =
-      external_extension_providers_[Extension::EXTERNAL_PREF];
+          new ExternalPrefExtensionProvider()));
 #if defined(OS_WIN)
-  external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
+  external_extension_providers_.push_back(
       linked_ptr<ExternalExtensionProvider>(
-          new ExternalRegistryExtensionProvider());
+          new ExternalRegistryExtensionProvider()));
 #endif
 }
 
@@ -338,22 +322,6 @@
           error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
 }
 
-bool ExtensionsServiceBackend::LookupExternalExtension(
-    const std::string& id, Version** version, Extension::Location* location) {
-  scoped_ptr<Version> extension_version;
-  for (ProviderMap::const_iterator i = external_extension_providers_.begin();
-       i != external_extension_providers_.end(); ++i) {
-    const ExternalExtensionProvider* provider = i->second.get();
-    extension_version.reset(provider->RegisteredVersion(id, location));
-    if (extension_version.get()) {
-      if (version)
-        *version = extension_version.release();
-      return true;
-    }
-  }
-  return false;
-}
-
 // Some extensions will autoupdate themselves externally from Chrome.  These
 // are typically part of some larger client application package.  To support
 // these, the extension will register its location in the the preferences file
@@ -374,10 +342,10 @@
 
   // Ask each external extension provider to give us a call back for each
   // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
-
-  for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+  ProviderCollection::const_iterator i;
+  for (i = external_extension_providers_.begin();
        i != external_extension_providers_.end(); ++i) {
-    ExternalExtensionProvider* provider = i->second.get();
+    ExternalExtensionProvider* provider = i->get();
     provider->VisitRegisteredExtension(this, ids_to_ignore);
   }
 
@@ -390,21 +358,15 @@
 }
 
 void ExtensionsServiceBackend::CheckExternalUninstall(
-    scoped_refptr<ExtensionsService> frontend, const std::string& id,
-    Extension::Location location) {
+    scoped_refptr<ExtensionsService> frontend, const std::string& id) {
   // Check if the providers know about this extension.
-  ProviderMap::const_iterator i = external_extension_providers_.find(location);
-  if (i == external_extension_providers_.end()) {
-    NOTREACHED() << "CheckExternalUninstall called for non-external extension "
-                 << location;
-    return;
+  ProviderCollection::const_iterator i;
+  for (i = external_extension_providers_.begin();
+       i != external_extension_providers_.end(); ++i) {
+    if (i->get()->HasExtension(id))
+      return;  // Yup, known extension, don't uninstall.
   }
 
-  scoped_ptr<Version> version;
-  version.reset(i->second->RegisteredVersion(id, NULL));
-  if (version.get())
-    return;  // Yup, known extension, don't uninstall.
-
   // This is an external extension that we don't have registered.  Uninstall.
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -416,12 +378,11 @@
   external_extension_providers_.clear();
 }
 
-void ExtensionsServiceBackend::SetProviderForTesting(
-    Extension::Location location,
+void ExtensionsServiceBackend::AddProviderForTesting(
     ExternalExtensionProvider* test_provider) {
   DCHECK(test_provider);
-  external_extension_providers_[location] =
-      linked_ptr<ExternalExtensionProvider>(test_provider);
+  external_extension_providers_.push_back(
+      linked_ptr<ExternalExtensionProvider>(test_provider));
 }
 
 void ExtensionsServiceBackend::OnExternalExtensionFileFound(
@@ -1108,8 +1069,7 @@
             backend_.get(),
             &ExtensionsServiceBackend::CheckExternalUninstall,
             scoped_refptr<ExtensionsService>(this),
-            info.extension_id,
-            info.extension_location));
+            info.extension_id));
   }
 }
 
@@ -1749,13 +1709,13 @@
           backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting));
 }
 
-void ExtensionsService::SetProviderForTesting(
-    Extension::Location location, ExternalExtensionProvider* test_provider) {
+void ExtensionsService::AddProviderForTesting(
+    ExternalExtensionProvider* test_provider) {
   BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
       NewRunnableMethod(
-          backend_.get(), &ExtensionsServiceBackend::SetProviderForTesting,
-          location, test_provider));
+          backend_.get(), &ExtensionsServiceBackend::AddProviderForTesting,
+          test_provider));
 }
 
 void ExtensionsService::OnExternalExtensionFileFound(