1 // Copyright 2014 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/common/extensions/extension_constants.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "extensions/browser/extension_prefs.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/common/extension.h"
18 using content::BrowserThread;
22 // Install predicate used by AddFromExternalUpdateUrl().
23 bool AlwaysInstall(const extensions::Extension* extension) {
27 std::string GetVersionString(const Version& version) {
28 return version.IsValid() ? version.GetString() : "invalid";
33 namespace extensions {
35 PendingExtensionManager::PendingExtensionManager(
36 content::BrowserContext* context)
37 : context_(context) {}
39 PendingExtensionManager::~PendingExtensionManager() {}
41 const PendingExtensionInfo* PendingExtensionManager::GetById(
42 const std::string& id) const {
43 PendingExtensionList::const_iterator iter;
44 for (iter = pending_extension_list_.begin();
45 iter != pending_extension_list_.end();
54 bool PendingExtensionManager::Remove(const std::string& id) {
55 PendingExtensionList::iterator iter;
56 for (iter = pending_extension_list_.begin();
57 iter != pending_extension_list_.end();
59 if (id == iter->id()) {
60 pending_extension_list_.erase(iter);
68 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
69 return GetById(id) != NULL;
72 bool PendingExtensionManager::HasPendingExtensions() const {
73 return !pending_extension_list_.empty();
76 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
77 PendingExtensionList::const_iterator iter;
78 for (iter = pending_extension_list_.begin();
79 iter != pending_extension_list_.end();
81 if (iter->is_from_sync())
88 bool PendingExtensionManager::AddFromSync(
89 const std::string& id,
90 const GURL& update_url,
91 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
92 bool install_silently,
94 bool installed_by_custodian) {
95 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97 if (ExtensionRegistry::Get(context_)->GetExtensionById(
98 id, ExtensionRegistry::EVERYTHING)) {
99 LOG(ERROR) << "Trying to add pending extension " << id
100 << " which already exists";
104 // Make sure we don't ever try to install the CWS app, because even though
105 // it is listed as a syncable app (because its values need to be synced) it
106 // should already be installed on every instance.
107 if (id == extension_misc::kWebStoreAppId) {
112 int creation_flags = Extension::NO_FLAGS;
113 if (installed_by_custodian) {
114 creation_flags |= Extension::WAS_INSTALLED_BY_CUSTODIAN;
117 static const bool kIsFromSync = true;
118 static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
119 static const bool kMarkAcknowledged = false;
121 return AddExtensionImpl(id,
125 should_allow_install,
134 bool PendingExtensionManager::AddFromExtensionImport(
135 const std::string& id,
136 const GURL& update_url,
137 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
138 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140 if (ExtensionRegistry::Get(context_)->GetExtensionById(
141 id, ExtensionRegistry::EVERYTHING)) {
142 LOG(ERROR) << "Trying to add pending extension " << id
143 << " which already exists";
147 static const bool kIsFromSync = false;
148 static const bool kInstallSilently = true;
149 static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
150 static const bool kMarkAcknowledged = false;
151 static const bool kRemoteInstall = false;
153 return AddExtensionImpl(id,
157 should_allow_install,
166 bool PendingExtensionManager::AddFromExternalUpdateUrl(
167 const std::string& id,
168 const std::string& install_parameter,
169 const GURL& update_url,
170 Manifest::Location location,
172 bool mark_acknowledged) {
173 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 static const bool kIsFromSync = false;
176 static const bool kInstallSilently = true;
177 static const bool kRemoteInstall = false;
179 const Extension* extension = ExtensionRegistry::Get(context_)
180 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
181 if (extension && location == Manifest::GetHigherPriorityLocation(
182 location, extension->location())) {
183 // If the new location has higher priority than the location of an existing
184 // extension, let the update process overwrite the existing extension.
186 if (ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id))
190 LOG(DFATAL) << "Trying to add extension " << id
191 << " by external update, but it is already installed.";
196 return AddExtensionImpl(id,
210 bool PendingExtensionManager::AddFromExternalFile(
211 const std::string& id,
212 Manifest::Location install_source,
213 const Version& version,
215 bool mark_acknowledged) {
216 // TODO(skerner): AddFromSync() checks to see if the extension is
217 // installed, but this method assumes that the caller already
218 // made sure it is not installed. Make all AddFrom*() methods
220 const GURL& kUpdateUrl = GURL::EmptyGURL();
221 static const bool kIsFromSync = false;
222 static const bool kInstallSilently = true;
223 static const bool kRemoteInstall = false;
225 return AddExtensionImpl(id,
238 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
239 std::list<std::string>* out_ids_for_update_check) const {
240 PendingExtensionList::const_iterator iter;
241 for (iter = pending_extension_list_.begin();
242 iter != pending_extension_list_.end();
244 Manifest::Location install_source = iter->install_source();
246 // Some install sources read a CRX from the filesystem. They can
247 // not be fetched from an update URL, so don't include them in the
249 if (install_source == Manifest::EXTERNAL_PREF ||
250 install_source == Manifest::EXTERNAL_REGISTRY)
253 out_ids_for_update_check->push_back(iter->id());
257 bool PendingExtensionManager::AddExtensionImpl(
258 const std::string& id,
259 const std::string& install_parameter,
260 const GURL& update_url,
261 const Version& version,
262 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
264 bool install_silently,
265 Manifest::Location install_source,
267 bool mark_acknowledged,
268 bool remote_install) {
269 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 PendingExtensionInfo info(id,
275 should_allow_install,
283 if (const PendingExtensionInfo* pending = GetById(id)) {
284 // Bugs in this code will manifest as sporadic incorrect extension
285 // locations in situations where multiple install sources run at the
286 // same time. For example, on first login to a chrome os machine, an
287 // extension may be requested by sync and the default extension set.
288 // The following logging will help diagnose such issues.
289 VLOG(1) << "Extension id " << id
290 << " was entered for update more than once."
291 << " old location: " << pending->install_source()
292 << " new location: " << install_source
293 << " old version: " << GetVersionString(pending->version())
294 << " new version: " << GetVersionString(version);
296 // Never override an existing extension with an older version. Only
297 // extensions from local CRX files have a known version; extensions from an
298 // update URL will get the latest version.
300 // If |pending| has the same or higher precedence than |info| then don't
301 // install |info| over |pending|.
302 if (pending->CompareTo(info) >= 0)
305 VLOG(1) << "Overwrite existing record.";
307 std::replace(pending_extension_list_.begin(),
308 pending_extension_list_.end(),
312 pending_extension_list_.push_back(info);
318 void PendingExtensionManager::AddForTesting(
319 const PendingExtensionInfo& pending_extension_info) {
320 pending_extension_list_.push_back(pending_extension_info);
323 } // namespace extensions