1 // Copyright 2013 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 "extensions/browser/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"
13 #include "extensions/common/extension.h"
16 using content::BrowserThread
;
20 // Install predicate used by AddFromExternalUpdateUrl().
21 bool AlwaysInstall(const extensions::Extension
* extension
) {
25 std::string
GetVersionString(const Version
& version
) {
26 return version
.IsValid() ? version
.GetString() : "invalid";
31 namespace extensions
{
33 PendingExtensionManager::PendingExtensionManager(
34 const ExtensionServiceInterface
& service
)
38 PendingExtensionManager::~PendingExtensionManager() {}
40 const PendingExtensionInfo
* PendingExtensionManager::GetById(
41 const std::string
& id
) const {
42 PendingExtensionList::const_iterator iter
;
43 for (iter
= pending_extension_list_
.begin();
44 iter
!= pending_extension_list_
.end();
53 bool PendingExtensionManager::Remove(const std::string
& id
) {
54 PendingExtensionList::iterator iter
;
55 for (iter
= pending_extension_list_
.begin();
56 iter
!= pending_extension_list_
.end();
58 if (id
== iter
->id()) {
59 pending_extension_list_
.erase(iter
);
67 bool PendingExtensionManager::IsIdPending(const std::string
& id
) const {
68 return GetById(id
) != NULL
;
71 bool PendingExtensionManager::HasPendingExtensions() const {
72 return !pending_extension_list_
.empty();
75 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
76 PendingExtensionList::const_iterator iter
;
77 for (iter
= pending_extension_list_
.begin();
78 iter
!= pending_extension_list_
.end();
80 if (iter
->is_from_sync())
87 bool PendingExtensionManager::AddFromSync(
88 const std::string
& id
,
89 const GURL
& update_url
,
90 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
,
91 bool install_silently
) {
92 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
94 if (service_
.GetInstalledExtension(id
)) {
95 LOG(ERROR
) << "Trying to add pending extension " << id
96 << " which already exists";
100 // Make sure we don't ever try to install the CWS app, because even though
101 // it is listed as a syncable app (because its values need to be synced) it
102 // should already be installed on every instance.
103 if (id
== extension_misc::kWebStoreAppId
) {
108 const bool kIsFromSync
= true;
109 const Manifest::Location kSyncLocation
= Manifest::INTERNAL
;
110 const bool kMarkAcknowledged
= false;
112 return AddExtensionImpl(id
, update_url
, Version(), should_allow_install
,
113 kIsFromSync
, install_silently
, kSyncLocation
,
114 Extension::NO_FLAGS
, kMarkAcknowledged
);
117 bool PendingExtensionManager::AddFromExtensionImport(
118 const std::string
& id
,
119 const GURL
& update_url
,
120 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
) {
121 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
123 if (service_
.GetInstalledExtension(id
)) {
124 LOG(ERROR
) << "Trying to add pending extension " << id
125 << " which already exists";
129 const bool kIsFromSync
= false;
130 const bool kInstallSilently
= true;
131 const Manifest::Location kManifestLocation
= Manifest::INTERNAL
;
132 const bool kMarkAcknowledged
= false;
134 return AddExtensionImpl(id
, update_url
, Version(), should_allow_install
,
135 kIsFromSync
, kInstallSilently
, kManifestLocation
,
136 Extension::NO_FLAGS
, kMarkAcknowledged
);
139 bool PendingExtensionManager::AddFromExternalUpdateUrl(
140 const std::string
& id
,
141 const GURL
& update_url
,
142 Manifest::Location location
,
144 bool mark_acknowledged
) {
145 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
147 const bool kIsFromSync
= false;
148 const bool kInstallSilently
= true;
150 const Extension
* extension
= service_
.GetInstalledExtension(id
);
152 location
== Manifest::GetHigherPriorityLocation(location
,
153 extension
->location())) {
154 // If the new location has higher priority than the location of an existing
155 // extension, let the update process overwrite the existing extension.
157 if (service_
.IsExternalExtensionUninstalled(id
))
161 LOG(DFATAL
) << "Trying to add extension " << id
162 << " by external update, but it is already installed.";
167 return AddExtensionImpl(id
, update_url
, Version(), &AlwaysInstall
,
168 kIsFromSync
, kInstallSilently
,
169 location
, creation_flags
, mark_acknowledged
);
173 bool PendingExtensionManager::AddFromExternalFile(
174 const std::string
& id
,
175 Manifest::Location install_source
,
176 const Version
& version
,
178 bool mark_acknowledged
) {
179 // TODO(skerner): AddFromSync() checks to see if the extension is
180 // installed, but this method assumes that the caller already
181 // made sure it is not installed. Make all AddFrom*() methods
183 GURL kUpdateUrl
= GURL();
184 bool kIsFromSync
= false;
185 bool kInstallSilently
= true;
187 return AddExtensionImpl(
199 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
200 std::list
<std::string
>* out_ids_for_update_check
) const {
201 PendingExtensionList::const_iterator iter
;
202 for (iter
= pending_extension_list_
.begin();
203 iter
!= pending_extension_list_
.end();
205 Manifest::Location install_source
= iter
->install_source();
207 // Some install sources read a CRX from the filesystem. They can
208 // not be fetched from an update URL, so don't include them in the
210 if (install_source
== Manifest::EXTERNAL_PREF
||
211 install_source
== Manifest::EXTERNAL_REGISTRY
)
214 out_ids_for_update_check
->push_back(iter
->id());
218 bool PendingExtensionManager::AddExtensionImpl(
219 const std::string
& id
,
220 const GURL
& update_url
,
221 const Version
& version
,
222 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
,
224 bool install_silently
,
225 Manifest::Location install_source
,
227 bool mark_acknowledged
) {
228 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
230 PendingExtensionInfo
info(id
,
233 should_allow_install
,
240 if (const PendingExtensionInfo
* pending
= GetById(id
)) {
241 // Bugs in this code will manifest as sporadic incorrect extension
242 // locations in situations where multiple install sources run at the
243 // same time. For example, on first login to a chrome os machine, an
244 // extension may be requested by sync and the default extension set.
245 // The following logging will help diagnose such issues.
246 VLOG(1) << "Extension id " << id
247 << " was entered for update more than once."
248 << " old location: " << pending
->install_source()
249 << " new location: " << install_source
250 << " old version: " << GetVersionString(pending
->version())
251 << " new version: " << GetVersionString(version
);
253 // Never override an existing extension with an older version. Only
254 // extensions from local CRX files have a known version; extensions from an
255 // update URL will get the latest version.
257 // If |pending| has the same or higher precedence than |info| then don't
258 // install |info| over |pending|.
259 if (pending
->CompareTo(info
) >= 0)
262 VLOG(1) << "Overwrite existing record.";
264 std::replace(pending_extension_list_
.begin(),
265 pending_extension_list_
.end(),
269 pending_extension_list_
.push_back(info
);
275 void PendingExtensionManager::AddForTesting(
276 const PendingExtensionInfo
& pending_extension_info
) {
277 pending_extension_list_
.push_back(pending_extension_info
);
280 } // namespace extensions