summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/pending_extension_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/pending_extension_manager.cc')
-rw-r--r--chrome/browser/extensions/pending_extension_manager.cc280
1 files changed, 280 insertions, 0 deletions
diff --git a/chrome/browser/extensions/pending_extension_manager.cc b/chrome/browser/extensions/pending_extension_manager.cc
new file mode 100644
index 0000000..e2a636d
--- /dev/null
+++ b/chrome/browser/extensions/pending_extension_manager.cc
@@ -0,0 +1,280 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/pending_extension_manager.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/version.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/common/extension.h"
+#include "url/gurl.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// Install predicate used by AddFromExternalUpdateUrl().
+bool AlwaysInstall(const extensions::Extension* extension) {
+ return true;
+}
+
+std::string GetVersionString(const Version& version) {
+ return version.IsValid() ? version.GetString() : "invalid";
+}
+
+} // namespace
+
+namespace extensions {
+
+PendingExtensionManager::PendingExtensionManager(
+ const ExtensionServiceInterface& service)
+ : service_(service) {
+}
+
+PendingExtensionManager::~PendingExtensionManager() {}
+
+const PendingExtensionInfo* PendingExtensionManager::GetById(
+ const std::string& id) const {
+ PendingExtensionList::const_iterator iter;
+ for (iter = pending_extension_list_.begin();
+ iter != pending_extension_list_.end();
+ ++iter) {
+ if (id == iter->id())
+ return &(*iter);
+ }
+
+ return NULL;
+}
+
+bool PendingExtensionManager::Remove(const std::string& id) {
+ PendingExtensionList::iterator iter;
+ for (iter = pending_extension_list_.begin();
+ iter != pending_extension_list_.end();
+ ++iter) {
+ if (id == iter->id()) {
+ pending_extension_list_.erase(iter);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PendingExtensionManager::IsIdPending(const std::string& id) const {
+ return GetById(id) != NULL;
+}
+
+bool PendingExtensionManager::HasPendingExtensions() const {
+ return !pending_extension_list_.empty();
+}
+
+bool PendingExtensionManager::HasPendingExtensionFromSync() const {
+ PendingExtensionList::const_iterator iter;
+ for (iter = pending_extension_list_.begin();
+ iter != pending_extension_list_.end();
+ ++iter) {
+ if (iter->is_from_sync())
+ return true;
+ }
+
+ return false;
+}
+
+bool PendingExtensionManager::AddFromSync(
+ const std::string& id,
+ const GURL& update_url,
+ PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
+ bool install_silently) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (service_.GetInstalledExtension(id)) {
+ LOG(ERROR) << "Trying to add pending extension " << id
+ << " which already exists";
+ return false;
+ }
+
+ // Make sure we don't ever try to install the CWS app, because even though
+ // it is listed as a syncable app (because its values need to be synced) it
+ // should already be installed on every instance.
+ if (id == extension_misc::kWebStoreAppId) {
+ NOTREACHED();
+ return false;
+ }
+
+ const bool kIsFromSync = true;
+ const Manifest::Location kSyncLocation = Manifest::INTERNAL;
+ const bool kMarkAcknowledged = false;
+
+ return AddExtensionImpl(id, update_url, Version(), should_allow_install,
+ kIsFromSync, install_silently, kSyncLocation,
+ Extension::NO_FLAGS, kMarkAcknowledged);
+}
+
+bool PendingExtensionManager::AddFromExtensionImport(
+ const std::string& id,
+ const GURL& update_url,
+ PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (service_.GetInstalledExtension(id)) {
+ LOG(ERROR) << "Trying to add pending extension " << id
+ << " which already exists";
+ return false;
+ }
+
+ const bool kIsFromSync = false;
+ const bool kInstallSilently = true;
+ const Manifest::Location kManifestLocation = Manifest::INTERNAL;
+ const bool kMarkAcknowledged = false;
+
+ return AddExtensionImpl(id, update_url, Version(), should_allow_install,
+ kIsFromSync, kInstallSilently, kManifestLocation,
+ Extension::NO_FLAGS, kMarkAcknowledged);
+}
+
+bool PendingExtensionManager::AddFromExternalUpdateUrl(
+ const std::string& id,
+ const GURL& update_url,
+ Manifest::Location location,
+ int creation_flags,
+ bool mark_acknowledged) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const bool kIsFromSync = false;
+ const bool kInstallSilently = true;
+
+ const Extension* extension = service_.GetInstalledExtension(id);
+ if (extension &&
+ location == Manifest::GetHigherPriorityLocation(location,
+ extension->location())) {
+ // If the new location has higher priority than the location of an existing
+ // extension, let the update process overwrite the existing extension.
+ } else {
+ if (service_.IsExternalExtensionUninstalled(id))
+ return false;
+
+ if (extension) {
+ LOG(DFATAL) << "Trying to add extension " << id
+ << " by external update, but it is already installed.";
+ return false;
+ }
+ }
+
+ return AddExtensionImpl(id, update_url, Version(), &AlwaysInstall,
+ kIsFromSync, kInstallSilently,
+ location, creation_flags, mark_acknowledged);
+}
+
+
+bool PendingExtensionManager::AddFromExternalFile(
+ const std::string& id,
+ Manifest::Location install_source,
+ const Version& version,
+ int creation_flags,
+ bool mark_acknowledged) {
+ // TODO(skerner): AddFromSync() checks to see if the extension is
+ // installed, but this method assumes that the caller already
+ // made sure it is not installed. Make all AddFrom*() methods
+ // consistent.
+ GURL kUpdateUrl = GURL();
+ bool kIsFromSync = false;
+ bool kInstallSilently = true;
+
+ return AddExtensionImpl(
+ id,
+ kUpdateUrl,
+ version,
+ &AlwaysInstall,
+ kIsFromSync,
+ kInstallSilently,
+ install_source,
+ creation_flags,
+ mark_acknowledged);
+}
+
+void PendingExtensionManager::GetPendingIdsForUpdateCheck(
+ std::list<std::string>* out_ids_for_update_check) const {
+ PendingExtensionList::const_iterator iter;
+ for (iter = pending_extension_list_.begin();
+ iter != pending_extension_list_.end();
+ ++iter) {
+ Manifest::Location install_source = iter->install_source();
+
+ // Some install sources read a CRX from the filesystem. They can
+ // not be fetched from an update URL, so don't include them in the
+ // set of ids.
+ if (install_source == Manifest::EXTERNAL_PREF ||
+ install_source == Manifest::EXTERNAL_REGISTRY)
+ continue;
+
+ out_ids_for_update_check->push_back(iter->id());
+ }
+}
+
+bool PendingExtensionManager::AddExtensionImpl(
+ const std::string& id,
+ const GURL& update_url,
+ const Version& version,
+ PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
+ bool is_from_sync,
+ bool install_silently,
+ Manifest::Location install_source,
+ int creation_flags,
+ bool mark_acknowledged) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ PendingExtensionInfo info(id,
+ update_url,
+ version,
+ should_allow_install,
+ is_from_sync,
+ install_silently,
+ install_source,
+ creation_flags,
+ mark_acknowledged);
+
+ if (const PendingExtensionInfo* pending = GetById(id)) {
+ // Bugs in this code will manifest as sporadic incorrect extension
+ // locations in situations where multiple install sources run at the
+ // same time. For example, on first login to a chrome os machine, an
+ // extension may be requested by sync and the default extension set.
+ // The following logging will help diagnose such issues.
+ VLOG(1) << "Extension id " << id
+ << " was entered for update more than once."
+ << " old location: " << pending->install_source()
+ << " new location: " << install_source
+ << " old version: " << GetVersionString(pending->version())
+ << " new version: " << GetVersionString(version);
+
+ // Never override an existing extension with an older version. Only
+ // extensions from local CRX files have a known version; extensions from an
+ // update URL will get the latest version.
+
+ // If |pending| has the same or higher precedence than |info| then don't
+ // install |info| over |pending|.
+ if (pending->CompareTo(info) >= 0)
+ return false;
+
+ VLOG(1) << "Overwrite existing record.";
+
+ std::replace(pending_extension_list_.begin(),
+ pending_extension_list_.end(),
+ *pending,
+ info);
+ } else {
+ pending_extension_list_.push_back(info);
+ }
+
+ return true;
+}
+
+void PendingExtensionManager::AddForTesting(
+ const PendingExtensionInfo& pending_extension_info) {
+ pending_extension_list_.push_back(pending_extension_info);
+}
+
+} // namespace extensions