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/constants.h"
16 #include "extensions/common/extension.h"
19 using content::BrowserThread
;
23 // Install predicate used by AddFromExternalUpdateUrl().
24 bool AlwaysInstall(const extensions::Extension
* extension
) {
28 std::string
GetVersionString(const Version
& version
) {
29 return version
.IsValid() ? version
.GetString() : "invalid";
34 namespace extensions
{
36 PendingExtensionManager::PendingExtensionManager(
37 content::BrowserContext
* context
)
38 : context_(context
) {}
40 PendingExtensionManager::~PendingExtensionManager() {}
42 const PendingExtensionInfo
* PendingExtensionManager::GetById(
43 const std::string
& id
) const {
44 PendingExtensionList::const_iterator iter
;
45 for (iter
= pending_extension_list_
.begin();
46 iter
!= pending_extension_list_
.end();
55 bool PendingExtensionManager::Remove(const std::string
& id
) {
56 PendingExtensionList::iterator iter
;
57 for (iter
= pending_extension_list_
.begin();
58 iter
!= pending_extension_list_
.end();
60 if (id
== iter
->id()) {
61 pending_extension_list_
.erase(iter
);
69 bool PendingExtensionManager::IsIdPending(const std::string
& id
) const {
70 return GetById(id
) != NULL
;
73 bool PendingExtensionManager::HasPendingExtensions() const {
74 return !pending_extension_list_
.empty();
77 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
78 PendingExtensionList::const_iterator iter
;
79 for (iter
= pending_extension_list_
.begin();
80 iter
!= pending_extension_list_
.end();
82 if (iter
->is_from_sync())
89 bool PendingExtensionManager::AddFromSync(
90 const std::string
& id
,
91 const GURL
& update_url
,
92 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
,
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
== extensions::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
,
133 bool PendingExtensionManager::AddFromExtensionImport(
134 const std::string
& id
,
135 const GURL
& update_url
,
136 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
) {
137 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
139 if (ExtensionRegistry::Get(context_
)->GetExtensionById(
140 id
, ExtensionRegistry::EVERYTHING
)) {
141 LOG(ERROR
) << "Trying to add pending extension " << id
142 << " which already exists";
146 static const bool kIsFromSync
= false;
147 static const Manifest::Location kManifestLocation
= Manifest::INTERNAL
;
148 static const bool kMarkAcknowledged
= false;
149 static const bool kRemoteInstall
= false;
151 return AddExtensionImpl(id
,
155 should_allow_install
,
163 bool PendingExtensionManager::AddFromExternalUpdateUrl(
164 const std::string
& id
,
165 const std::string
& install_parameter
,
166 const GURL
& update_url
,
167 Manifest::Location location
,
169 bool mark_acknowledged
) {
170 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
172 static const bool kIsFromSync
= false;
173 static const bool kRemoteInstall
= false;
175 const Extension
* extension
= ExtensionRegistry::Get(context_
)
176 ->GetExtensionById(id
, ExtensionRegistry::EVERYTHING
);
177 if (extension
&& location
== Manifest::GetHigherPriorityLocation(
178 location
, extension
->location())) {
179 // If the new location has higher priority than the location of an existing
180 // extension, let the update process overwrite the existing extension.
182 if (ExtensionPrefs::Get(context_
)->IsExternalExtensionUninstalled(id
))
186 LOG(DFATAL
) << "Trying to add extension " << id
187 << " by external update, but it is already installed.";
192 return AddExtensionImpl(id
,
205 bool PendingExtensionManager::AddFromExternalFile(
206 const std::string
& id
,
207 Manifest::Location install_source
,
208 const Version
& version
,
210 bool mark_acknowledged
) {
211 // TODO(skerner): AddFromSync() checks to see if the extension is
212 // installed, but this method assumes that the caller already
213 // made sure it is not installed. Make all AddFrom*() methods
215 const GURL
& kUpdateUrl
= GURL::EmptyGURL();
216 static const bool kIsFromSync
= false;
217 static const bool kRemoteInstall
= false;
219 return AddExtensionImpl(id
,
231 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
232 std::list
<std::string
>* out_ids_for_update_check
) const {
233 PendingExtensionList::const_iterator iter
;
234 for (iter
= pending_extension_list_
.begin();
235 iter
!= pending_extension_list_
.end();
237 Manifest::Location install_source
= iter
->install_source();
239 // Some install sources read a CRX from the filesystem. They can
240 // not be fetched from an update URL, so don't include them in the
242 if (install_source
== Manifest::EXTERNAL_PREF
||
243 install_source
== Manifest::EXTERNAL_REGISTRY
||
244 install_source
== Manifest::EXTERNAL_POLICY
) {
248 out_ids_for_update_check
->push_back(iter
->id());
252 bool PendingExtensionManager::AddExtensionImpl(
253 const std::string
& id
,
254 const std::string
& install_parameter
,
255 const GURL
& update_url
,
256 const Version
& version
,
257 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install
,
259 Manifest::Location install_source
,
261 bool mark_acknowledged
,
262 bool remote_install
) {
263 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
265 PendingExtensionInfo
info(id
,
269 should_allow_install
,
276 if (const PendingExtensionInfo
* pending
= GetById(id
)) {
277 // Bugs in this code will manifest as sporadic incorrect extension
278 // locations in situations where multiple install sources run at the
279 // same time. For example, on first login to a chrome os machine, an
280 // extension may be requested by sync and the default extension set.
281 // The following logging will help diagnose such issues.
282 VLOG(1) << "Extension id " << id
283 << " was entered for update more than once."
284 << " old location: " << pending
->install_source()
285 << " new location: " << install_source
286 << " old version: " << GetVersionString(pending
->version())
287 << " new version: " << GetVersionString(version
);
289 // Never override an existing extension with an older version. Only
290 // extensions from local CRX files have a known version; extensions from an
291 // update URL will get the latest version.
293 // If |pending| has the same or higher precedence than |info| then don't
294 // install |info| over |pending|.
295 if (pending
->CompareTo(info
) >= 0)
298 VLOG(1) << "Overwrite existing record.";
300 std::replace(pending_extension_list_
.begin(),
301 pending_extension_list_
.end(),
305 pending_extension_list_
.push_back(info
);
311 void PendingExtensionManager::AddForTesting(
312 const PendingExtensionInfo
& pending_extension_info
) {
313 pending_extension_list_
.push_back(pending_extension_info
);
316 } // namespace extensions