blob: c3145203850376ad171491d072f706d2371c98ec [file] [log] [blame]
[email protected]f3d3b382014-03-14 21:19:281// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]b2907fd2011-03-25 16:43:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]f3d3b382014-03-14 21:19:285#include "chrome/browser/extensions/pending_extension_manager.h"
[email protected]51a3bf8b2012-06-08 22:53:066
[email protected]d31e19e2012-08-22 00:19:047#include <algorithm>
8
[email protected]b2907fd2011-03-25 16:43:379#include "base/logging.h"
asvitkinef5d4ee562016-11-07 18:57:0810#include "base/metrics/histogram_macros.h"
asargent56282ab72016-09-09 16:58:0311#include "base/stl_util.h"
[email protected]e3987852012-05-04 10:06:3012#include "base/version.h"
[email protected]6c9bedf2014-05-21 03:55:5113#include "chrome/common/extensions/extension_constants.h"
[email protected]c38831a12011-10-28 12:44:4914#include "content/public/browser/browser_thread.h"
[email protected]46f3e102014-03-25 01:22:4515#include "extensions/browser/extension_prefs.h"
[email protected]6c9bedf2014-05-21 03:55:5116#include "extensions/browser/extension_registry.h"
hanxia3182da2014-09-02 22:51:1917#include "extensions/common/constants.h"
[email protected]b52f8ca2013-11-28 08:25:2218#include "extensions/common/extension.h"
[email protected]a6483d22013-07-03 22:11:0019#include "url/gurl.h"
[email protected]b2907fd2011-03-25 16:43:3720
[email protected]631bb742011-11-02 11:29:3921using content::BrowserThread;
22
[email protected]b2907fd2011-03-25 16:43:3723namespace {
24
[email protected]b2907fd2011-03-25 16:43:3725// Install predicate used by AddFromExternalUpdateUrl().
[email protected]8f3bcbd2013-06-05 08:42:4026bool AlwaysInstall(const extensions::Extension* extension) {
[email protected]b2907fd2011-03-25 16:43:3727 return true;
28}
29
pwnallcbd73192016-08-22 18:59:1730std::string GetVersionString(const base::Version& version) {
[email protected]4ec0f4b2012-12-07 09:41:4631 return version.IsValid() ? version.GetString() : "invalid";
32}
33
[email protected]b2907fd2011-03-25 16:43:3734} // namespace
35
[email protected]3f213ad2012-07-26 23:39:4136namespace extensions {
37
[email protected]b2907fd2011-03-25 16:43:3738PendingExtensionManager::PendingExtensionManager(
[email protected]46f3e102014-03-25 01:22:4539 content::BrowserContext* context)
[email protected]6c9bedf2014-05-21 03:55:5140 : context_(context) {}
[email protected]b2907fd2011-03-25 16:43:3741
42PendingExtensionManager::~PendingExtensionManager() {}
43
[email protected]51a3bf8b2012-06-08 22:53:0644const PendingExtensionInfo* PendingExtensionManager::GetById(
45 const std::string& id) const {
46 PendingExtensionList::const_iterator iter;
47 for (iter = pending_extension_list_.begin();
48 iter != pending_extension_list_.end();
49 ++iter) {
50 if (id == iter->id())
51 return &(*iter);
52 }
[email protected]b2907fd2011-03-25 16:43:3753
[email protected]51a3bf8b2012-06-08 22:53:0654 return NULL;
55}
56
57bool PendingExtensionManager::Remove(const std::string& id) {
Jan Wilken Dörrieade79222019-06-06 19:01:1258 if (base::Contains(expected_policy_reinstalls_, id)) {
asargent56282ab72016-09-09 16:58:0359 base::TimeDelta latency =
60 base::TimeTicks::Now() - expected_policy_reinstalls_[id];
61 UMA_HISTOGRAM_LONG_TIMES("Extensions.CorruptPolicyExtensionResolved",
62 latency);
63 expected_policy_reinstalls_.erase(id);
64 }
[email protected]51a3bf8b2012-06-08 22:53:0665 PendingExtensionList::iterator iter;
66 for (iter = pending_extension_list_.begin();
67 iter != pending_extension_list_.end();
68 ++iter) {
69 if (id == iter->id()) {
70 pending_extension_list_.erase(iter);
71 return true;
72 }
[email protected]b2907fd2011-03-25 16:43:3773 }
74
75 return false;
76}
77
[email protected]b2907fd2011-03-25 16:43:3778bool PendingExtensionManager::IsIdPending(const std::string& id) const {
[email protected]870f5572013-12-19 12:30:1579 return GetById(id) != NULL;
[email protected]b2907fd2011-03-25 16:43:3780}
81
[email protected]9bd9a6862012-11-29 09:24:2282bool PendingExtensionManager::HasPendingExtensions() const {
83 return !pending_extension_list_.empty();
84}
85
[email protected]d31e19e2012-08-22 00:19:0486bool PendingExtensionManager::HasPendingExtensionFromSync() const {
87 PendingExtensionList::const_iterator iter;
88 for (iter = pending_extension_list_.begin();
89 iter != pending_extension_list_.end();
90 ++iter) {
91 if (iter->is_from_sync())
92 return true;
93 }
94
95 return false;
96}
97
Devlin Cronin2b3acda2019-05-30 19:11:3798bool PendingExtensionManager::HasHighPriorityPendingExtension() const {
99 return std::find_if(
100 pending_extension_list_.begin(), pending_extension_list_.end(),
101 [](const PendingExtensionInfo& info) {
102 return info.install_source() ==
103 Manifest::EXTERNAL_POLICY_DOWNLOAD ||
104 info.install_source() == Manifest::EXTERNAL_COMPONENT;
105 }) != pending_extension_list_.end();
Oleg Davydov6541a64f2019-04-17 13:17:33106}
107
asargent56282ab72016-09-09 16:58:03108void PendingExtensionManager::ExpectPolicyReinstallForCorruption(
109 const ExtensionId& id) {
Jan Wilken Dörrieade79222019-06-06 19:01:12110 if (base::Contains(expected_policy_reinstalls_, id))
Sergey Poromov6d050352018-11-27 18:57:02111 return;
asargent56282ab72016-09-09 16:58:03112 expected_policy_reinstalls_[id] = base::TimeTicks::Now();
Sergey Poromov6d050352018-11-27 18:57:02113 UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptPolicyExtensionDetected2", true);
asargent56282ab72016-09-09 16:58:03114}
115
116bool PendingExtensionManager::IsPolicyReinstallForCorruptionExpected(
117 const ExtensionId& id) const {
Jan Wilken Dörrieade79222019-06-06 19:01:12118 return base::Contains(expected_policy_reinstalls_, id);
asargent56282ab72016-09-09 16:58:03119}
120
lazyboy77214d3c2017-04-04 16:46:12121bool PendingExtensionManager::HasAnyPolicyReinstallForCorruption() const {
122 return !expected_policy_reinstalls_.empty();
123}
124
[email protected]145a317b2011-04-12 16:03:46125bool PendingExtensionManager::AddFromSync(
[email protected]b2907fd2011-03-25 16:43:37126 const std::string& id,
127 const GURL& update_url,
treibe960e282015-09-11 10:38:08128 const base::Version& version,
[email protected]b2907fd2011-03-25 16:43:37129 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
mamir192d7882016-06-22 17:10:16130 bool remote_install) {
[email protected]b2907fd2011-03-25 16:43:37131 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
132
[email protected]6c9bedf2014-05-21 03:55:51133 if (ExtensionRegistry::Get(context_)->GetExtensionById(
134 id, ExtensionRegistry::EVERYTHING)) {
[email protected]145a317b2011-04-12 16:03:46135 LOG(ERROR) << "Trying to add pending extension " << id
136 << " which already exists";
137 return false;
[email protected]b2907fd2011-03-25 16:43:37138 }
139
[email protected]b873cd92012-02-09 21:51:48140 // Make sure we don't ever try to install the CWS app, because even though
141 // it is listed as a syncable app (because its values need to be synced) it
142 // should already be installed on every instance.
hanxia3182da2014-09-02 22:51:19143 if (id == extensions::kWebStoreAppId) {
[email protected]b873cd92012-02-09 21:51:48144 NOTREACHED();
145 return false;
146 }
147
[email protected]6c9bedf2014-05-21 03:55:51148 static const bool kIsFromSync = true;
149 static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
150 static const bool kMarkAcknowledged = false;
[email protected]145a317b2011-04-12 16:03:46151
[email protected]d8fd0fd2014-03-24 13:16:06152 return AddExtensionImpl(id,
153 std::string(),
154 update_url,
treibe960e282015-09-11 10:38:08155 version,
[email protected]d8fd0fd2014-03-24 13:16:06156 should_allow_install,
157 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06158 kSyncLocation,
mamir0128d5a2016-07-15 20:55:48159 Extension::NO_FLAGS,
[email protected]21db9ef2014-05-16 02:06:27160 kMarkAcknowledged,
161 remote_install);
[email protected]b2907fd2011-03-25 16:43:37162}
163
[email protected]9f4e4f082013-06-21 07:11:19164bool PendingExtensionManager::AddFromExtensionImport(
165 const std::string& id,
166 const GURL& update_url,
167 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
168 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169
[email protected]6c9bedf2014-05-21 03:55:51170 if (ExtensionRegistry::Get(context_)->GetExtensionById(
171 id, ExtensionRegistry::EVERYTHING)) {
[email protected]9f4e4f082013-06-21 07:11:19172 LOG(ERROR) << "Trying to add pending extension " << id
173 << " which already exists";
174 return false;
175 }
176
[email protected]6c9bedf2014-05-21 03:55:51177 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51178 static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
179 static const bool kMarkAcknowledged = false;
180 static const bool kRemoteInstall = false;
[email protected]9f4e4f082013-06-21 07:11:19181
[email protected]d8fd0fd2014-03-24 13:16:06182 return AddExtensionImpl(id,
183 std::string(),
184 update_url,
pwnallcbd73192016-08-22 18:59:17185 base::Version(),
[email protected]d8fd0fd2014-03-24 13:16:06186 should_allow_install,
187 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06188 kManifestLocation,
mamir0128d5a2016-07-15 20:55:48189 Extension::NO_FLAGS,
[email protected]21db9ef2014-05-16 02:06:27190 kMarkAcknowledged,
191 kRemoteInstall);
[email protected]9f4e4f082013-06-21 07:11:19192}
193
[email protected]9060d8b02012-01-13 02:14:30194bool PendingExtensionManager::AddFromExternalUpdateUrl(
[email protected]612a1cb12012-10-17 13:18:03195 const std::string& id,
[email protected]d8fd0fd2014-03-24 13:16:06196 const std::string& install_parameter,
[email protected]612a1cb12012-10-17 13:18:03197 const GURL& update_url,
[email protected]464213a2013-10-15 01:06:48198 Manifest::Location location,
199 int creation_flags,
200 bool mark_acknowledged) {
[email protected]b2907fd2011-03-25 16:43:37201 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202
[email protected]6c9bedf2014-05-21 03:55:51203 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51204 static const bool kRemoteInstall = false;
[email protected]b2907fd2011-03-25 16:43:37205
[email protected]6c9bedf2014-05-21 03:55:51206 const Extension* extension = ExtensionRegistry::Get(context_)
207 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]d8fd0fd2014-03-24 13:16:06208 if (extension && location == Manifest::GetHigherPriorityLocation(
209 location, extension->location())) {
[email protected]8a87a5332011-08-11 17:54:59210 // If the new location has higher priority than the location of an existing
211 // extension, let the update process overwrite the existing extension.
212 } else {
emaxx6699afb682016-10-10 21:22:13213 // Skip the installation if the extension was removed by the user and it's
214 // not specified to be force-installed through the policy.
215 if (!Manifest::IsPolicyLocation(location) &&
216 ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id)) {
[email protected]9060d8b02012-01-13 02:14:30217 return false;
emaxx6699afb682016-10-10 21:22:13218 }
[email protected]9060d8b02012-01-13 02:14:30219
[email protected]8a87a5332011-08-11 17:54:59220 if (extension) {
221 LOG(DFATAL) << "Trying to add extension " << id
222 << " by external update, but it is already installed.";
[email protected]9060d8b02012-01-13 02:14:30223 return false;
[email protected]8a87a5332011-08-11 17:54:59224 }
[email protected]b2907fd2011-03-25 16:43:37225 }
226
[email protected]d8fd0fd2014-03-24 13:16:06227 return AddExtensionImpl(id,
228 install_parameter,
229 update_url,
pwnallcbd73192016-08-22 18:59:17230 base::Version(),
[email protected]d8fd0fd2014-03-24 13:16:06231 &AlwaysInstall,
232 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06233 location,
mamir0128d5a2016-07-15 20:55:48234 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27235 mark_acknowledged,
236 kRemoteInstall);
[email protected]b2907fd2011-03-25 16:43:37237}
238
thakis37be69c2015-08-19 03:26:57239
[email protected]9060d8b02012-01-13 02:14:30240bool PendingExtensionManager::AddFromExternalFile(
[email protected]b2907fd2011-03-25 16:43:37241 const std::string& id,
[email protected]1d5e58b2013-01-31 08:41:40242 Manifest::Location install_source,
pwnallcbd73192016-08-22 18:59:17243 const base::Version& version,
[email protected]464213a2013-10-15 01:06:48244 int creation_flags,
245 bool mark_acknowledged) {
[email protected]9060d8b02012-01-13 02:14:30246 // TODO(skerner): AddFromSync() checks to see if the extension is
247 // installed, but this method assumes that the caller already
248 // made sure it is not installed. Make all AddFrom*() methods
249 // consistent.
[email protected]6c9bedf2014-05-21 03:55:51250 const GURL& kUpdateUrl = GURL::EmptyGURL();
251 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51252 static const bool kRemoteInstall = false;
[email protected]b2907fd2011-03-25 16:43:37253
[email protected]d8fd0fd2014-03-24 13:16:06254 return AddExtensionImpl(id,
255 std::string(),
256 kUpdateUrl,
257 version,
258 &AlwaysInstall,
259 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06260 install_source,
mamir0128d5a2016-07-15 20:55:48261 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27262 mark_acknowledged,
263 kRemoteInstall);
[email protected]9060d8b02012-01-13 02:14:30264}
265
266void PendingExtensionManager::GetPendingIdsForUpdateCheck(
[email protected]51a3bf8b2012-06-08 22:53:06267 std::list<std::string>* out_ids_for_update_check) const {
268 PendingExtensionList::const_iterator iter;
269 for (iter = pending_extension_list_.begin();
270 iter != pending_extension_list_.end();
[email protected]9060d8b02012-01-13 02:14:30271 ++iter) {
[email protected]1d5e58b2013-01-31 08:41:40272 Manifest::Location install_source = iter->install_source();
[email protected]9060d8b02012-01-13 02:14:30273
274 // Some install sources read a CRX from the filesystem. They can
275 // not be fetched from an update URL, so don't include them in the
276 // set of ids.
[email protected]1d5e58b2013-01-31 08:41:40277 if (install_source == Manifest::EXTERNAL_PREF ||
binjin52eb40412015-08-18 06:29:30278 install_source == Manifest::EXTERNAL_REGISTRY ||
279 install_source == Manifest::EXTERNAL_POLICY) {
[email protected]9060d8b02012-01-13 02:14:30280 continue;
binjin52eb40412015-08-18 06:29:30281 }
[email protected]9060d8b02012-01-13 02:14:30282
[email protected]51a3bf8b2012-06-08 22:53:06283 out_ids_for_update_check->push_back(iter->id());
[email protected]9060d8b02012-01-13 02:14:30284 }
[email protected]b2907fd2011-03-25 16:43:37285}
286
[email protected]145a317b2011-04-12 16:03:46287bool PendingExtensionManager::AddExtensionImpl(
[email protected]9060d8b02012-01-13 02:14:30288 const std::string& id,
[email protected]d8fd0fd2014-03-24 13:16:06289 const std::string& install_parameter,
[email protected]9060d8b02012-01-13 02:14:30290 const GURL& update_url,
pwnallcbd73192016-08-22 18:59:17291 const base::Version& version,
[email protected]b2907fd2011-03-25 16:43:37292 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
[email protected]9060d8b02012-01-13 02:14:30293 bool is_from_sync,
[email protected]464213a2013-10-15 01:06:48294 Manifest::Location install_source,
mamir0128d5a2016-07-15 20:55:48295 int creation_flags,
[email protected]21db9ef2014-05-16 02:06:27296 bool mark_acknowledged,
297 bool remote_install) {
[email protected]b2907fd2011-03-25 16:43:37298 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299
[email protected]4ec0f4b2012-12-07 09:41:46300 PendingExtensionInfo info(id,
[email protected]d8fd0fd2014-03-24 13:16:06301 install_parameter,
[email protected]4ec0f4b2012-12-07 09:41:46302 update_url,
303 version,
304 should_allow_install,
305 is_from_sync,
[email protected]464213a2013-10-15 01:06:48306 install_source,
mamir0128d5a2016-07-15 20:55:48307 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27308 mark_acknowledged,
309 remote_install);
[email protected]4ec0f4b2012-12-07 09:41:46310
[email protected]51a3bf8b2012-06-08 22:53:06311 if (const PendingExtensionInfo* pending = GetById(id)) {
[email protected]145a317b2011-04-12 16:03:46312 // Bugs in this code will manifest as sporadic incorrect extension
313 // locations in situations where multiple install sources run at the
314 // same time. For example, on first login to a chrome os machine, an
[email protected]9060d8b02012-01-13 02:14:30315 // extension may be requested by sync and the default extension set.
[email protected]145a317b2011-04-12 16:03:46316 // The following logging will help diagnose such issues.
[email protected]b2907fd2011-03-25 16:43:37317 VLOG(1) << "Extension id " << id
318 << " was entered for update more than once."
[email protected]51a3bf8b2012-06-08 22:53:06319 << " old location: " << pending->install_source()
[email protected]4ec0f4b2012-12-07 09:41:46320 << " new location: " << install_source
321 << " old version: " << GetVersionString(pending->version())
322 << " new version: " << GetVersionString(version);
[email protected]145a317b2011-04-12 16:03:46323
[email protected]e3987852012-05-04 10:06:30324 // Never override an existing extension with an older version. Only
325 // extensions from local CRX files have a known version; extensions from an
326 // update URL will get the latest version.
[email protected]e3987852012-05-04 10:06:30327
[email protected]4ec0f4b2012-12-07 09:41:46328 // If |pending| has the same or higher precedence than |info| then don't
329 // install |info| over |pending|.
330 if (pending->CompareTo(info) >= 0)
[email protected]e3987852012-05-04 10:06:30331 return false;
[email protected]e3987852012-05-04 10:06:30332
333 VLOG(1) << "Overwrite existing record.";
[email protected]51a3bf8b2012-06-08 22:53:06334
335 std::replace(pending_extension_list_.begin(),
336 pending_extension_list_.end(),
337 *pending,
[email protected]4ec0f4b2012-12-07 09:41:46338 info);
[email protected]51a3bf8b2012-06-08 22:53:06339 } else {
[email protected]4ec0f4b2012-12-07 09:41:46340 pending_extension_list_.push_back(info);
[email protected]b2907fd2011-03-25 16:43:37341 }
342
[email protected]e3987852012-05-04 10:06:30343 return true;
[email protected]b2907fd2011-03-25 16:43:37344}
345
346void PendingExtensionManager::AddForTesting(
[email protected]b2907fd2011-03-25 16:43:37347 const PendingExtensionInfo& pending_extension_info) {
[email protected]51a3bf8b2012-06-08 22:53:06348 pending_extension_list_.push_back(pending_extension_info);
[email protected]b2907fd2011-03-25 16:43:37349}
[email protected]3f213ad2012-07-26 23:39:41350
351} // namespace extensions