1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/pending_extension_manager.h"
9 #include "base/logging.h"
10 #include "base/version.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "content/public/browser/browser_thread.h"
15 using content::BrowserThread;
19 // Install predicate used by AddFromExternalUpdateUrl().
20 bool AlwaysInstall(const extensions::Extension* extension) {
24 std::string GetVersionString(const Version& version) {
25 return version.IsValid() ? version.GetString() : "invalid";
30 namespace extensions {
32 PendingExtensionManager::PendingExtensionManager(
33 const ExtensionServiceInterface& service)
37 PendingExtensionManager::~PendingExtensionManager() {}
39 const PendingExtensionInfo* PendingExtensionManager::GetById(
40 const std::string& id) const {
41 PendingExtensionList::const_iterator iter;
42 for (iter = pending_extension_list_.begin();
43 iter != pending_extension_list_.end();
52 bool PendingExtensionManager::Remove(const std::string& id) {
53 PendingExtensionList::iterator iter;
54 for (iter = pending_extension_list_.begin();
55 iter != pending_extension_list_.end();
57 if (id == iter->id()) {
58 pending_extension_list_.erase(iter);
66 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
67 PendingExtensionList::const_iterator iter;
68 for (iter = pending_extension_list_.begin();
69 iter != pending_extension_list_.end();
78 bool PendingExtensionManager::HasPendingExtensions() const {
79 return !pending_extension_list_.empty();
82 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
83 PendingExtensionList::const_iterator iter;
84 for (iter = pending_extension_list_.begin();
85 iter != pending_extension_list_.end();
87 if (iter->is_from_sync())
94 bool PendingExtensionManager::AddFromSync(
95 const std::string& id,
96 const GURL& update_url,
97 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
98 bool install_silently) {
99 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101 if (service_.GetInstalledExtension(id)) {
102 LOG(ERROR) << "Trying to add pending extension " << id
103 << " which already exists";
107 // Make sure we don't ever try to install the CWS app, because even though
108 // it is listed as a syncable app (because its values need to be synced) it
109 // should already be installed on every instance.
110 if (id == extension_misc::kWebStoreAppId) {
115 const bool kIsFromSync = true;
116 const Manifest::Location kSyncLocation = Manifest::INTERNAL;
117 const bool kMarkAcknowledged = false;
119 return AddExtensionImpl(id, update_url, Version(), should_allow_install,
120 kIsFromSync, install_silently, kSyncLocation,
121 Extension::NO_FLAGS, kMarkAcknowledged);
124 bool PendingExtensionManager::AddFromExtensionImport(
125 const std::string& id,
126 const GURL& update_url,
127 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
128 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
130 if (service_.GetInstalledExtension(id)) {
131 LOG(ERROR) << "Trying to add pending extension " << id
132 << " which already exists";
136 const bool kIsFromSync = false;
137 const bool kInstallSilently = true;
138 const Manifest::Location kManifestLocation = Manifest::INTERNAL;
139 const bool kMarkAcknowledged = false;
141 return AddExtensionImpl(id, update_url, Version(), should_allow_install,
142 kIsFromSync, kInstallSilently, kManifestLocation,
143 Extension::NO_FLAGS, kMarkAcknowledged);
146 bool PendingExtensionManager::AddFromExternalUpdateUrl(
147 const std::string& id,
148 const GURL& update_url,
149 Manifest::Location location,
151 bool mark_acknowledged) {
152 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
154 const bool kIsFromSync = false;
155 const bool kInstallSilently = true;
157 const Extension* extension = service_.GetInstalledExtension(id);
159 location == Manifest::GetHigherPriorityLocation(location,
160 extension->location())) {
161 // If the new location has higher priority than the location of an existing
162 // extension, let the update process overwrite the existing extension.
164 if (service_.IsExternalExtensionUninstalled(id))
168 LOG(DFATAL) << "Trying to add extension " << id
169 << " by external update, but it is already installed.";
174 return AddExtensionImpl(id, update_url, Version(), &AlwaysInstall,
175 kIsFromSync, kInstallSilently,
176 location, creation_flags, mark_acknowledged);
180 bool PendingExtensionManager::AddFromExternalFile(
181 const std::string& id,
182 Manifest::Location install_source,
183 const Version& version,
185 bool mark_acknowledged) {
186 // TODO(skerner): AddFromSync() checks to see if the extension is
187 // installed, but this method assumes that the caller already
188 // made sure it is not installed. Make all AddFrom*() methods
190 GURL kUpdateUrl = GURL();
191 bool kIsFromSync = false;
192 bool kInstallSilently = true;
194 return AddExtensionImpl(
206 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
207 std::list<std::string>* out_ids_for_update_check) const {
208 PendingExtensionList::const_iterator iter;
209 for (iter = pending_extension_list_.begin();
210 iter != pending_extension_list_.end();
212 Manifest::Location install_source = iter->install_source();
214 // Some install sources read a CRX from the filesystem. They can
215 // not be fetched from an update URL, so don't include them in the
217 if (install_source == Manifest::EXTERNAL_PREF ||
218 install_source == Manifest::EXTERNAL_REGISTRY)
221 out_ids_for_update_check->push_back(iter->id());
225 bool PendingExtensionManager::AddExtensionImpl(
226 const std::string& id,
227 const GURL& update_url,
228 const Version& version,
229 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
231 bool install_silently,
232 Manifest::Location install_source,
234 bool mark_acknowledged) {
235 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 PendingExtensionInfo info(id,
240 should_allow_install,
247 if (const PendingExtensionInfo* pending = GetById(id)) {
248 // Bugs in this code will manifest as sporadic incorrect extension
249 // locations in situations where multiple install sources run at the
250 // same time. For example, on first login to a chrome os machine, an
251 // extension may be requested by sync and the default extension set.
252 // The following logging will help diagnose such issues.
253 VLOG(1) << "Extension id " << id
254 << " was entered for update more than once."
255 << " old location: " << pending->install_source()
256 << " new location: " << install_source
257 << " old version: " << GetVersionString(pending->version())
258 << " new version: " << GetVersionString(version);
260 // Never override an existing extension with an older version. Only
261 // extensions from local CRX files have a known version; extensions from an
262 // update URL will get the latest version.
264 // If |pending| has the same or higher precedence than |info| then don't
265 // install |info| over |pending|.
266 if (pending->CompareTo(info) >= 0)
269 VLOG(1) << "Overwrite existing record.";
271 std::replace(pending_extension_list_.begin(),
272 pending_extension_list_.end(),
276 pending_extension_list_.push_back(info);
282 void PendingExtensionManager::AddForTesting(
283 const PendingExtensionInfo& pending_extension_info) {
284 pending_extension_list_.push_back(pending_extension_info);
287 } // namespace extensions