blob: 36038b92f83039747805229bc92149a9311f202c [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"
asargent56282ab72016-09-09 16:58:0310#include "base/metrics/histogram.h"
11#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) {
asargent56282ab72016-09-09 16:58:0358 if (base::ContainsKey(expected_policy_reinstalls_, id)) {
59 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
asargent56282ab72016-09-09 16:58:0398void PendingExtensionManager::ExpectPolicyReinstallForCorruption(
99 const ExtensionId& id) {
100 expected_policy_reinstalls_[id] = base::TimeTicks::Now();
101 UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptPolicyExtensionDetected", true);
102}
103
104bool PendingExtensionManager::IsPolicyReinstallForCorruptionExpected(
105 const ExtensionId& id) const {
106 return base::ContainsKey(expected_policy_reinstalls_, id);
107}
108
[email protected]145a317b2011-04-12 16:03:46109bool PendingExtensionManager::AddFromSync(
[email protected]b2907fd2011-03-25 16:43:37110 const std::string& id,
111 const GURL& update_url,
treibe960e282015-09-11 10:38:08112 const base::Version& version,
[email protected]b2907fd2011-03-25 16:43:37113 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
mamir192d7882016-06-22 17:10:16114 bool remote_install) {
[email protected]b2907fd2011-03-25 16:43:37115 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
116
[email protected]6c9bedf2014-05-21 03:55:51117 if (ExtensionRegistry::Get(context_)->GetExtensionById(
118 id, ExtensionRegistry::EVERYTHING)) {
[email protected]145a317b2011-04-12 16:03:46119 LOG(ERROR) << "Trying to add pending extension " << id
120 << " which already exists";
121 return false;
[email protected]b2907fd2011-03-25 16:43:37122 }
123
[email protected]b873cd92012-02-09 21:51:48124 // Make sure we don't ever try to install the CWS app, because even though
125 // it is listed as a syncable app (because its values need to be synced) it
126 // should already be installed on every instance.
hanxia3182da2014-09-02 22:51:19127 if (id == extensions::kWebStoreAppId) {
[email protected]b873cd92012-02-09 21:51:48128 NOTREACHED();
129 return false;
130 }
131
[email protected]6c9bedf2014-05-21 03:55:51132 static const bool kIsFromSync = true;
133 static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
134 static const bool kMarkAcknowledged = false;
[email protected]145a317b2011-04-12 16:03:46135
[email protected]d8fd0fd2014-03-24 13:16:06136 return AddExtensionImpl(id,
137 std::string(),
138 update_url,
treibe960e282015-09-11 10:38:08139 version,
[email protected]d8fd0fd2014-03-24 13:16:06140 should_allow_install,
141 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06142 kSyncLocation,
mamir0128d5a2016-07-15 20:55:48143 Extension::NO_FLAGS,
[email protected]21db9ef2014-05-16 02:06:27144 kMarkAcknowledged,
145 remote_install);
[email protected]b2907fd2011-03-25 16:43:37146}
147
[email protected]9f4e4f082013-06-21 07:11:19148bool PendingExtensionManager::AddFromExtensionImport(
149 const std::string& id,
150 const GURL& update_url,
151 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
152 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153
[email protected]6c9bedf2014-05-21 03:55:51154 if (ExtensionRegistry::Get(context_)->GetExtensionById(
155 id, ExtensionRegistry::EVERYTHING)) {
[email protected]9f4e4f082013-06-21 07:11:19156 LOG(ERROR) << "Trying to add pending extension " << id
157 << " which already exists";
158 return false;
159 }
160
[email protected]6c9bedf2014-05-21 03:55:51161 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51162 static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
163 static const bool kMarkAcknowledged = false;
164 static const bool kRemoteInstall = false;
[email protected]9f4e4f082013-06-21 07:11:19165
[email protected]d8fd0fd2014-03-24 13:16:06166 return AddExtensionImpl(id,
167 std::string(),
168 update_url,
pwnallcbd73192016-08-22 18:59:17169 base::Version(),
[email protected]d8fd0fd2014-03-24 13:16:06170 should_allow_install,
171 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06172 kManifestLocation,
mamir0128d5a2016-07-15 20:55:48173 Extension::NO_FLAGS,
[email protected]21db9ef2014-05-16 02:06:27174 kMarkAcknowledged,
175 kRemoteInstall);
[email protected]9f4e4f082013-06-21 07:11:19176}
177
[email protected]9060d8b02012-01-13 02:14:30178bool PendingExtensionManager::AddFromExternalUpdateUrl(
[email protected]612a1cb12012-10-17 13:18:03179 const std::string& id,
[email protected]d8fd0fd2014-03-24 13:16:06180 const std::string& install_parameter,
[email protected]612a1cb12012-10-17 13:18:03181 const GURL& update_url,
[email protected]464213a2013-10-15 01:06:48182 Manifest::Location location,
183 int creation_flags,
184 bool mark_acknowledged) {
[email protected]b2907fd2011-03-25 16:43:37185 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186
[email protected]6c9bedf2014-05-21 03:55:51187 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51188 static const bool kRemoteInstall = false;
[email protected]b2907fd2011-03-25 16:43:37189
[email protected]6c9bedf2014-05-21 03:55:51190 const Extension* extension = ExtensionRegistry::Get(context_)
191 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
[email protected]d8fd0fd2014-03-24 13:16:06192 if (extension && location == Manifest::GetHigherPriorityLocation(
193 location, extension->location())) {
[email protected]8a87a5332011-08-11 17:54:59194 // If the new location has higher priority than the location of an existing
195 // extension, let the update process overwrite the existing extension.
196 } else {
emaxx6699afb682016-10-10 21:22:13197 // Skip the installation if the extension was removed by the user and it's
198 // not specified to be force-installed through the policy.
199 if (!Manifest::IsPolicyLocation(location) &&
200 ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id)) {
[email protected]9060d8b02012-01-13 02:14:30201 return false;
emaxx6699afb682016-10-10 21:22:13202 }
[email protected]9060d8b02012-01-13 02:14:30203
[email protected]8a87a5332011-08-11 17:54:59204 if (extension) {
205 LOG(DFATAL) << "Trying to add extension " << id
206 << " by external update, but it is already installed.";
[email protected]9060d8b02012-01-13 02:14:30207 return false;
[email protected]8a87a5332011-08-11 17:54:59208 }
[email protected]b2907fd2011-03-25 16:43:37209 }
210
[email protected]d8fd0fd2014-03-24 13:16:06211 return AddExtensionImpl(id,
212 install_parameter,
213 update_url,
pwnallcbd73192016-08-22 18:59:17214 base::Version(),
[email protected]d8fd0fd2014-03-24 13:16:06215 &AlwaysInstall,
216 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06217 location,
mamir0128d5a2016-07-15 20:55:48218 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27219 mark_acknowledged,
220 kRemoteInstall);
[email protected]b2907fd2011-03-25 16:43:37221}
222
thakis37be69c2015-08-19 03:26:57223
[email protected]9060d8b02012-01-13 02:14:30224bool PendingExtensionManager::AddFromExternalFile(
[email protected]b2907fd2011-03-25 16:43:37225 const std::string& id,
[email protected]1d5e58b2013-01-31 08:41:40226 Manifest::Location install_source,
pwnallcbd73192016-08-22 18:59:17227 const base::Version& version,
[email protected]464213a2013-10-15 01:06:48228 int creation_flags,
229 bool mark_acknowledged) {
[email protected]9060d8b02012-01-13 02:14:30230 // TODO(skerner): AddFromSync() checks to see if the extension is
231 // installed, but this method assumes that the caller already
232 // made sure it is not installed. Make all AddFrom*() methods
233 // consistent.
[email protected]6c9bedf2014-05-21 03:55:51234 const GURL& kUpdateUrl = GURL::EmptyGURL();
235 static const bool kIsFromSync = false;
[email protected]6c9bedf2014-05-21 03:55:51236 static const bool kRemoteInstall = false;
[email protected]b2907fd2011-03-25 16:43:37237
[email protected]d8fd0fd2014-03-24 13:16:06238 return AddExtensionImpl(id,
239 std::string(),
240 kUpdateUrl,
241 version,
242 &AlwaysInstall,
243 kIsFromSync,
[email protected]d8fd0fd2014-03-24 13:16:06244 install_source,
mamir0128d5a2016-07-15 20:55:48245 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27246 mark_acknowledged,
247 kRemoteInstall);
[email protected]9060d8b02012-01-13 02:14:30248}
249
250void PendingExtensionManager::GetPendingIdsForUpdateCheck(
[email protected]51a3bf8b2012-06-08 22:53:06251 std::list<std::string>* out_ids_for_update_check) const {
252 PendingExtensionList::const_iterator iter;
253 for (iter = pending_extension_list_.begin();
254 iter != pending_extension_list_.end();
[email protected]9060d8b02012-01-13 02:14:30255 ++iter) {
[email protected]1d5e58b2013-01-31 08:41:40256 Manifest::Location install_source = iter->install_source();
[email protected]9060d8b02012-01-13 02:14:30257
258 // Some install sources read a CRX from the filesystem. They can
259 // not be fetched from an update URL, so don't include them in the
260 // set of ids.
[email protected]1d5e58b2013-01-31 08:41:40261 if (install_source == Manifest::EXTERNAL_PREF ||
binjin52eb40412015-08-18 06:29:30262 install_source == Manifest::EXTERNAL_REGISTRY ||
263 install_source == Manifest::EXTERNAL_POLICY) {
[email protected]9060d8b02012-01-13 02:14:30264 continue;
binjin52eb40412015-08-18 06:29:30265 }
[email protected]9060d8b02012-01-13 02:14:30266
[email protected]51a3bf8b2012-06-08 22:53:06267 out_ids_for_update_check->push_back(iter->id());
[email protected]9060d8b02012-01-13 02:14:30268 }
[email protected]b2907fd2011-03-25 16:43:37269}
270
[email protected]145a317b2011-04-12 16:03:46271bool PendingExtensionManager::AddExtensionImpl(
[email protected]9060d8b02012-01-13 02:14:30272 const std::string& id,
[email protected]d8fd0fd2014-03-24 13:16:06273 const std::string& install_parameter,
[email protected]9060d8b02012-01-13 02:14:30274 const GURL& update_url,
pwnallcbd73192016-08-22 18:59:17275 const base::Version& version,
[email protected]b2907fd2011-03-25 16:43:37276 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
[email protected]9060d8b02012-01-13 02:14:30277 bool is_from_sync,
[email protected]464213a2013-10-15 01:06:48278 Manifest::Location install_source,
mamir0128d5a2016-07-15 20:55:48279 int creation_flags,
[email protected]21db9ef2014-05-16 02:06:27280 bool mark_acknowledged,
281 bool remote_install) {
[email protected]b2907fd2011-03-25 16:43:37282 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
283
[email protected]4ec0f4b2012-12-07 09:41:46284 PendingExtensionInfo info(id,
[email protected]d8fd0fd2014-03-24 13:16:06285 install_parameter,
[email protected]4ec0f4b2012-12-07 09:41:46286 update_url,
287 version,
288 should_allow_install,
289 is_from_sync,
[email protected]464213a2013-10-15 01:06:48290 install_source,
mamir0128d5a2016-07-15 20:55:48291 creation_flags,
[email protected]21db9ef2014-05-16 02:06:27292 mark_acknowledged,
293 remote_install);
[email protected]4ec0f4b2012-12-07 09:41:46294
[email protected]51a3bf8b2012-06-08 22:53:06295 if (const PendingExtensionInfo* pending = GetById(id)) {
[email protected]145a317b2011-04-12 16:03:46296 // Bugs in this code will manifest as sporadic incorrect extension
297 // locations in situations where multiple install sources run at the
298 // same time. For example, on first login to a chrome os machine, an
[email protected]9060d8b02012-01-13 02:14:30299 // extension may be requested by sync and the default extension set.
[email protected]145a317b2011-04-12 16:03:46300 // The following logging will help diagnose such issues.
[email protected]b2907fd2011-03-25 16:43:37301 VLOG(1) << "Extension id " << id
302 << " was entered for update more than once."
[email protected]51a3bf8b2012-06-08 22:53:06303 << " old location: " << pending->install_source()
[email protected]4ec0f4b2012-12-07 09:41:46304 << " new location: " << install_source
305 << " old version: " << GetVersionString(pending->version())
306 << " new version: " << GetVersionString(version);
[email protected]145a317b2011-04-12 16:03:46307
[email protected]e3987852012-05-04 10:06:30308 // Never override an existing extension with an older version. Only
309 // extensions from local CRX files have a known version; extensions from an
310 // update URL will get the latest version.
[email protected]e3987852012-05-04 10:06:30311
[email protected]4ec0f4b2012-12-07 09:41:46312 // If |pending| has the same or higher precedence than |info| then don't
313 // install |info| over |pending|.
314 if (pending->CompareTo(info) >= 0)
[email protected]e3987852012-05-04 10:06:30315 return false;
[email protected]e3987852012-05-04 10:06:30316
317 VLOG(1) << "Overwrite existing record.";
[email protected]51a3bf8b2012-06-08 22:53:06318
319 std::replace(pending_extension_list_.begin(),
320 pending_extension_list_.end(),
321 *pending,
[email protected]4ec0f4b2012-12-07 09:41:46322 info);
[email protected]51a3bf8b2012-06-08 22:53:06323 } else {
[email protected]4ec0f4b2012-12-07 09:41:46324 pending_extension_list_.push_back(info);
[email protected]b2907fd2011-03-25 16:43:37325 }
326
[email protected]e3987852012-05-04 10:06:30327 return true;
[email protected]b2907fd2011-03-25 16:43:37328}
329
330void PendingExtensionManager::AddForTesting(
[email protected]b2907fd2011-03-25 16:43:37331 const PendingExtensionInfo& pending_extension_info) {
[email protected]51a3bf8b2012-06-08 22:53:06332 pending_extension_list_.push_back(pending_extension_info);
[email protected]b2907fd2011-03-25 16:43:37333}
[email protected]3f213ad2012-07-26 23:39:41334
335} // namespace extensions