Added support for pending extensions to ExtensionsService and
ExtensionUpdater. This is needed for theme syncing.
Basically a pending extension is an (id, update_url) pair. This change
makes it so that one can pass pending extensions to the extension service
and they will be installed if necessary on the next auto-update cycle.
BUG=32414
TEST=unittests, trybots, in-progress theme syncing change
Review URL: http://codereview.chromium.org/1232003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42711 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 28ba10c..6807f6a 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -12,6 +12,7 @@
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
+#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/debugger/devtools_manager.h"
@@ -97,6 +98,21 @@
} // namespace
+PendingExtensionInfo::PendingExtensionInfo(const GURL& update_url,
+ const Version& version,
+ bool is_theme,
+ bool install_silently)
+ : update_url(update_url),
+ version(version),
+ is_theme(is_theme),
+ install_silently(install_silently) {}
+
+PendingExtensionInfo::PendingExtensionInfo()
+ : update_url(),
+ version(),
+ is_theme(false),
+ install_silently(false) {}
+
// ExtensionsService.
const char* ExtensionsService::kInstallDirectoryName = "Extensions";
@@ -203,19 +219,41 @@
installer->InstallCrx(extension_path);
}
+namespace {
+ // TODO(akalin): Put this somewhere where both crx_installer.cc and
+ // this file can use it.
+ void DeleteFileHelper(const FilePath& path, bool recursive) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ file_util::Delete(path, recursive);
+ }
+} // namespace
+
void ExtensionsService::UpdateExtension(const std::string& id,
const FilePath& extension_path,
const GURL& download_url) {
- if (!GetExtensionByIdInternal(id, true, true)) {
- LOG(WARNING) << "Will not update extension " << id << " because it is not "
- << "installed";
+ PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
+ if ((it == pending_extensions_.end()) &&
+ !GetExtensionByIdInternal(id, true, true)) {
+ LOG(WARNING) << "Will not update extension " << id
+ << " because it is not installed or pending";
+ // Delete extension_path since we're not creating a CrxInstaller
+ // that would do it for us.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&DeleteFileHelper, extension_path, false));
return;
}
+ // We want a silent install only for non-pending extensions and
+ // pending extensions that have install_silently set.
+ ExtensionInstallUI* client =
+ ((it == pending_extensions_.end()) || it->second.install_silently) ?
+ NULL : new ExtensionInstallUI(profile_);
+
scoped_refptr<CrxInstaller> installer(
new CrxInstaller(install_directory_,
this, // frontend
- NULL)); // no client (silent install)
+ client));
installer->set_expected_id(id);
installer->set_delete_source(true);
installer->set_force_web_origin_to_download_url(true);
@@ -223,6 +261,23 @@
installer->InstallCrx(extension_path);
}
+void ExtensionsService::AddPendingExtension(
+ const std::string& id, const GURL& update_url,
+ const Version& version, bool is_theme, bool install_silently) {
+ if (GetExtensionByIdInternal(id, true, true)) {
+ return;
+ }
+ AddPendingExtensionInternal(id, update_url, version,
+ is_theme, install_silently);
+}
+
+void ExtensionsService::AddPendingExtensionInternal(
+ const std::string& id, const GURL& update_url,
+ const Version& version, bool is_theme, bool install_silently) {
+ pending_extensions_[id] =
+ PendingExtensionInfo(update_url, version, is_theme, install_silently);
+}
+
void ExtensionsService::ReloadExtension(const std::string& extension_id) {
FilePath path;
Extension* current_extension = GetExtensionById(extension_id, false);
@@ -823,6 +878,22 @@
void ExtensionsService::OnExtensionInstalled(Extension* extension,
bool allow_privilege_increase) {
+ PendingExtensionMap::iterator it =
+ pending_extensions_.find(extension->id());
+ if (it != pending_extensions_.end() &&
+ (it->second.is_theme != extension->IsTheme())) {
+ LOG(WARNING) << "Not installing pending extension " << extension->id()
+ << " with is_theme = " << extension->IsTheme()
+ << "; expected is_theme = " << it->second.is_theme;
+ // Delete the extension directory since we're not going to load
+ // it.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
+ delete extension;
+ return;
+ }
+
extension_prefs_->OnExtensionInstalled(extension);
// If the extension is a theme, tell the profile (and therefore ThemeProvider)
@@ -841,6 +912,11 @@
// Also load the extension.
OnExtensionLoaded(extension, allow_privilege_increase);
+
+ // Erase any pending extension.
+ if (it != pending_extensions_.end()) {
+ pending_extensions_.erase(it);
+ }
}
void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {