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/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
,
116 should_allow_install
,
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
,
145 should_allow_install
,
153 bool PendingExtensionManager::AddFromExternalUpdateUrl(
154 const std::string
& id
,
155 const std::string
& install_parameter
,
156 const GURL
& update_url
,
157 Manifest::Location location
,
159 bool mark_acknowledged
) {
160 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
162 const bool kIsFromSync
= false;
163 const bool kInstallSilently
= true;
165 const Extension
* extension
= service_
.GetInstalledExtension(id
);
166 if (extension
&& location
== Manifest::GetHigherPriorityLocation(
167 location
, extension
->location())) {
168 // If the new location has higher priority than the location of an existing
169 // extension, let the update process overwrite the existing extension.
171 if (service_
.IsExternalExtensionUninstalled(id
))
175 LOG(DFATAL
) << "Trying to add extension " << id
176 << " by external update, but it is already installed.";
181 return AddExtensionImpl(id
,
194 bool PendingExtensionManager::AddFromExternalFile(
195 const std::string
& id
,
196 Manifest::Location install_source
,
197 const Version
& version
,
199 bool mark_acknowledged
) {
200 // TODO(skerner): AddFromSync() checks to see if the extension is
201 // installed, but this method assumes that the caller already
202 // made sure it is not installed. Make all AddFrom*() methods
204 GURL kUpdateUrl
= GURL();
205 bool kIsFromSync
= false;
206 bool kInstallSilently
= true;
208 return AddExtensionImpl(id
,
220 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
221 std::list
<std::string
>* out_ids_for_update_check
) const {
222 PendingExtensionList::const_iterator iter
;
223 for (iter
= pending_extension_list_
.begin();
224 iter
!= pending_extension_list_
.end();
226 Manifest::Location install_source
= iter
->install_source();
228 // Some install sources read a CRX from the filesystem. They can
229 // not be fetched from an update URL, so don't include them in the
231 if (install_source
== Manifest::EXTERNAL_PREF
||
232 install_source
== Manifest::EXTERNAL_REGISTRY
)
235 out_ids_for_update_check
->push_back(iter
->id());
239 bool PendingExtensionManager::AddExtensionImpl(
240 const std::string
& id
,
241 const std::string
& install_parameter
,
242 const GURL
& update_url
,
243 const Version
& version
,
244 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
,
246 bool install_silently
,
247 Manifest::Location install_source
,
249 bool mark_acknowledged
) {
250 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
252 PendingExtensionInfo
info(id
,
256 should_allow_install
,
263 if (const PendingExtensionInfo
* pending
= GetById(id
)) {
264 // Bugs in this code will manifest as sporadic incorrect extension
265 // locations in situations where multiple install sources run at the
266 // same time. For example, on first login to a chrome os machine, an
267 // extension may be requested by sync and the default extension set.
268 // The following logging will help diagnose such issues.
269 VLOG(1) << "Extension id " << id
270 << " was entered for update more than once."
271 << " old location: " << pending
->install_source()
272 << " new location: " << install_source
273 << " old version: " << GetVersionString(pending
->version())
274 << " new version: " << GetVersionString(version
);
276 // Never override an existing extension with an older version. Only
277 // extensions from local CRX files have a known version; extensions from an
278 // update URL will get the latest version.
280 // If |pending| has the same or higher precedence than |info| then don't
281 // install |info| over |pending|.
282 if (pending
->CompareTo(info
) >= 0)
285 VLOG(1) << "Overwrite existing record.";
287 std::replace(pending_extension_list_
.begin(),
288 pending_extension_list_
.end(),
292 pending_extension_list_
.push_back(info
);
298 void PendingExtensionManager::AddForTesting(
299 const PendingExtensionInfo
& pending_extension_info
) {
300 pending_extension_list_
.push_back(pending_extension_info
);
303 } // namespace extensions