1 // Copyright (c) 2012 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.
4
5 #include "chrome/browser/extensions/updater/extension_updater.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <set>
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/rand_util.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_split.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/extensions/api/module/module.h"
25 #include "chrome/browser/extensions/crx_installer.h"
26 #include "chrome/browser/extensions/extension_service.h"
27 #include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h"
28 #include "chrome/browser/extensions/pending_extension_manager.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "components/prefs/pref_service.h"
31 #include "components/update_client/update_query_params.h"
32 #include "content/public/browser/browser_task_traits.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/notification_source.h"
37 #include "crypto/sha2.h"
38 #include "extensions/browser/extension_file_task_runner.h"
39 #include "extensions/browser/extension_prefs.h"
40 #include "extensions/browser/extension_registry.h"
41 #include "extensions/browser/pref_names.h"
42 #include "extensions/browser/updater/extension_cache.h"
43 #include "extensions/browser/updater/extension_update_data.h"
44 #include "extensions/common/constants.h"
45 #include "extensions/common/extension.h"
46 #include "extensions/common/extension_set.h"
47 #include "extensions/common/extension_updater_uma.h"
48 #include "extensions/common/extension_urls.h"
49 #include "extensions/common/manifest.h"
50 #include "extensions/common/manifest_constants.h"
51 #include "extensions/common/manifest_url_handlers.h"
52
53 using base::RandDouble;
54 using base::RandInt;
55 typedef extensions::ExtensionDownloaderDelegate::Error Error;
56 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
57
58 namespace {
59
60 bool g_should_immediately_update = false;
61
62 // For sanity checking on update frequency - enforced in release mode only.
63 #if defined(NDEBUG)
64 const int kMinUpdateFrequencySeconds = 30;
65 #endif
66 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
67
68 bool g_skip_scheduled_checks_for_tests = false;
69
70 bool g_force_use_update_service_for_tests = false;
71
72 // When we've computed a days value, we want to make sure we don't send a
73 // negative value (due to the system clock being set backwards, etc.), since -1
74 // is a special sentinel value that means "never pinged", and other negative
75 // values don't make sense.
SanitizeDays(int days)76 int SanitizeDays(int days) {
77 if (days < 0)
78 return 0;
79 return days;
80 }
81
82 // Calculates the value to use for the ping days parameter.
CalculatePingDaysForExtension(const base::Time & last_ping_day)83 int CalculatePingDaysForExtension(const base::Time& last_ping_day) {
84 int days = extensions::ManifestFetchData::kNeverPinged;
85 if (!last_ping_day.is_null()) {
86 days = SanitizeDays((base::Time::Now() - last_ping_day).InDays());
87 }
88 return days;
89 }
90
CalculateActivePingDays(const base::Time & last_active_ping_day,bool hasActiveBit)91 int CalculateActivePingDays(const base::Time& last_active_ping_day,
92 bool hasActiveBit) {
93 if (!hasActiveBit)
94 return 0;
95 if (last_active_ping_day.is_null())
96 return extensions::ManifestFetchData::kNeverPinged;
97 return SanitizeDays((base::Time::Now() - last_active_ping_day).InDays());
98 }
99
100 } // namespace
101
102 namespace extensions {
103
104 ExtensionUpdater::CheckParams::CheckParams() = default;
105
106 ExtensionUpdater::CheckParams::~CheckParams() = default;
107
108 ExtensionUpdater::CheckParams::CheckParams(
109 ExtensionUpdater::CheckParams&& other) = default;
110 ExtensionUpdater::CheckParams& ExtensionUpdater::CheckParams::operator=(
111 ExtensionUpdater::CheckParams&& other) = default;
112
FetchedCRXFile(const CRXFileInfo & file,bool file_ownership_passed,const std::set<int> & request_ids,InstallCallback callback)113 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
114 const CRXFileInfo& file,
115 bool file_ownership_passed,
116 const std::set<int>& request_ids,
117 InstallCallback callback)
118 : info(file),
119 file_ownership_passed(file_ownership_passed),
120 request_ids(request_ids),
121 callback(std::move(callback)) {}
122
FetchedCRXFile()123 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
124 : file_ownership_passed(true) {}
125
126 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(FetchedCRXFile&& other) =
127 default;
128
129 ExtensionUpdater::FetchedCRXFile& ExtensionUpdater::FetchedCRXFile::operator=(
130 FetchedCRXFile&& other) = default;
131
132 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() = default;
133
134 ExtensionUpdater::InProgressCheck::InProgressCheck() = default;
135
136 ExtensionUpdater::InProgressCheck::~InProgressCheck() = default;
137
ExtensionUpdater(ExtensionServiceInterface * service,ExtensionPrefs * extension_prefs,PrefService * prefs,Profile * profile,int frequency_seconds,ExtensionCache * cache,const ExtensionDownloader::Factory & downloader_factory)138 ExtensionUpdater::ExtensionUpdater(
139 ExtensionServiceInterface* service,
140 ExtensionPrefs* extension_prefs,
141 PrefService* prefs,
142 Profile* profile,
143 int frequency_seconds,
144 ExtensionCache* cache,
145 const ExtensionDownloader::Factory& downloader_factory)
146 : service_(service),
147 downloader_factory_(downloader_factory),
148 frequency_(base::TimeDelta::FromSeconds(frequency_seconds)),
149 extension_prefs_(extension_prefs),
150 prefs_(prefs),
151 profile_(profile),
152 registry_(ExtensionRegistry::Get(profile)),
153 extension_cache_(cache) {
154 DCHECK_LE(frequency_seconds, kMaxUpdateFrequencySeconds);
155 #if defined(NDEBUG)
156 // In Release mode we enforce that update checks don't happen too often.
157 frequency_seconds = std::max(frequency_seconds, kMinUpdateFrequencySeconds);
158 #endif
159 frequency_seconds = std::min(frequency_seconds, kMaxUpdateFrequencySeconds);
160 frequency_ = base::TimeDelta::FromSeconds(frequency_seconds);
161 }
162
~ExtensionUpdater()163 ExtensionUpdater::~ExtensionUpdater() {
164 Stop();
165 }
166
EnsureDownloaderCreated()167 void ExtensionUpdater::EnsureDownloaderCreated() {
168 if (!downloader_.get()) {
169 downloader_ = downloader_factory_.Run(this);
170 }
171 if (!update_service_) {
172 update_service_ = UpdateService::Get(profile_);
173 }
174 }
175
Start()176 void ExtensionUpdater::Start() {
177 DCHECK(!alive_);
178 // If these are NULL, then that means we've been called after Stop()
179 // has been called.
180 DCHECK(service_);
181 DCHECK(extension_prefs_);
182 DCHECK(prefs_);
183 DCHECK(profile_);
184 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
185 DCHECK(registry_);
186 alive_ = true;
187 // Check soon, and set up the first delayed check.
188 if (!g_skip_scheduled_checks_for_tests) {
189 if (g_should_immediately_update)
190 CheckNow({});
191 else
192 CheckSoon();
193 ScheduleNextCheck();
194 }
195 }
196
Stop()197 void ExtensionUpdater::Stop() {
198 weak_ptr_factory_.InvalidateWeakPtrs();
199 alive_ = false;
200 service_ = nullptr;
201 extension_prefs_ = nullptr;
202 prefs_ = nullptr;
203 profile_ = nullptr;
204 will_check_soon_ = false;
205 downloader_.reset();
206 update_service_ = nullptr;
207 registry_ = nullptr;
208 }
209
ScheduleNextCheck()210 void ExtensionUpdater::ScheduleNextCheck() {
211 DCHECK(alive_);
212 // Jitter the frequency by +/- 20%.
213 const double jitter_factor = RandDouble() * 0.4 + 0.8;
214 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(
215 static_cast<int64_t>(frequency_.InMilliseconds() * jitter_factor));
216 content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
217 ->PostDelayedTask(FROM_HERE,
218 base::BindOnce(&ExtensionUpdater::NextCheck,
219 weak_ptr_factory_.GetWeakPtr()),
220 delay);
221 }
222
NextCheck()223 void ExtensionUpdater::NextCheck() {
224 if (!alive_)
225 return;
226 CheckNow(CheckParams());
227 ScheduleNextCheck();
228 }
229
CheckSoon()230 void ExtensionUpdater::CheckSoon() {
231 DCHECK(alive_);
232 if (will_check_soon_)
233 return;
234 if (content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
235 ->PostTask(FROM_HERE,
236 base::BindOnce(&ExtensionUpdater::DoCheckSoon,
237 weak_ptr_factory_.GetWeakPtr()))) {
238 will_check_soon_ = true;
239 } else {
240 NOTREACHED();
241 }
242 }
243
WillCheckSoon() const244 bool ExtensionUpdater::WillCheckSoon() const {
245 return will_check_soon_;
246 }
247
SetExtensionCacheForTesting(ExtensionCache * extension_cache)248 void ExtensionUpdater::SetExtensionCacheForTesting(
249 ExtensionCache* extension_cache) {
250 extension_cache_ = extension_cache;
251 }
252
SetExtensionDownloaderForTesting(std::unique_ptr<ExtensionDownloader> downloader)253 void ExtensionUpdater::SetExtensionDownloaderForTesting(
254 std::unique_ptr<ExtensionDownloader> downloader) {
255 downloader_.swap(downloader);
256 }
257
258 // static
UpdateImmediatelyForFirstRun()259 void ExtensionUpdater::UpdateImmediatelyForFirstRun() {
260 g_should_immediately_update = true;
261 }
262
SetBackoffPolicyForTesting(const net::BackoffEntry::Policy * backoff_policy)263 void ExtensionUpdater::SetBackoffPolicyForTesting(
264 const net::BackoffEntry::Policy* backoff_policy) {
265 EnsureDownloaderCreated();
266 downloader_->SetBackoffPolicyForTesting(backoff_policy);
267 }
268
269 // static
GetScopedUseUpdateServiceForTesting()270 base::AutoReset<bool> ExtensionUpdater::GetScopedUseUpdateServiceForTesting() {
271 return base::AutoReset<bool>(&g_force_use_update_service_for_tests, true);
272 }
273
DoCheckSoon()274 void ExtensionUpdater::DoCheckSoon() {
275 if (!will_check_soon_) {
276 // Another caller called CheckNow() between CheckSoon() and now. Skip this
277 // check.
278 return;
279 }
280 CheckNow(CheckParams());
281 }
282
AddToDownloader(const ExtensionSet * extensions,const std::list<ExtensionId> & pending_ids,int request_id,ManifestFetchData::FetchPriority fetch_priority,ExtensionUpdateCheckParams * update_check_params)283 void ExtensionUpdater::AddToDownloader(
284 const ExtensionSet* extensions,
285 const std::list<ExtensionId>& pending_ids,
286 int request_id,
287 ManifestFetchData::FetchPriority fetch_priority,
288 ExtensionUpdateCheckParams* update_check_params) {
289 DCHECK(update_service_);
290 InProgressCheck& request = requests_in_progress_[request_id];
291 for (ExtensionSet::const_iterator extension_iter = extensions->begin();
292 extension_iter != extensions->end(); ++extension_iter) {
293 const Extension& extension = **extension_iter;
294 const ExtensionId& extension_id = extension.id();
295 if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
296 VLOG(2) << "Extension " << extension_id << " is not auto updateable";
297 continue;
298 }
299 // An extension might be overwritten by policy, and have its update url
300 // changed. Make sure existing extensions aren't fetched again, if a
301 // pending fetch for an extension with the same id already exists.
302 if (!base::Contains(pending_ids, extension_id)) {
303 if (CanUseUpdateService(extension_id)) {
304 update_check_params->update_info[extension_id] = ExtensionUpdateData();
305 } else if (downloader_->AddExtension(extension, request_id,
306 fetch_priority)) {
307 request.in_progress_ids_.insert(extension_id);
308 }
309 }
310 }
311 }
312
CheckNow(CheckParams params)313 void ExtensionUpdater::CheckNow(CheckParams params) {
314 if (params.ids.empty()) {
315 // Checking all extensions. Cancel pending DoCheckSoon() call if there's
316 // one, as it would be redundant.
317 will_check_soon_ = false;
318 }
319
320 int request_id = next_request_id_++;
321
322 VLOG(2) << "Starting update check " << request_id;
323 if (params.ids.empty())
324 NotifyStarted();
325
326 DCHECK(alive_);
327
328 InProgressCheck& request = requests_in_progress_[request_id];
329 request.callback = std::move(params.callback);
330 request.install_immediately = params.install_immediately;
331
332 EnsureDownloaderCreated();
333
334 // Add fetch records for extensions that should be fetched by an update URL.
335 // These extensions are not yet installed. They come from group policy
336 // and external install sources.
337 const PendingExtensionManager* pending_extension_manager =
338 service_->pending_extension_manager();
339
340 std::list<ExtensionId> pending_ids;
341 ExtensionUpdateCheckParams update_check_params;
342
343 if (params.ids.empty()) {
344 // We have to mark high-priority extensions (such as policy-forced
345 // extensions or external component extensions) with foreground fetch
346 // priority; otherwise their installation may be throttled by bandwidth
347 // limits.
348 // See https://crbug.com/904600 and https://crbug.com/965686.
349 if (pending_extension_manager->HasHighPriorityPendingExtension())
350 params.fetch_priority = ManifestFetchData::FOREGROUND;
351
352 // If no extension ids are specified, check for updates for all extensions.
353 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
354
355 for (const ExtensionId& pending_id : pending_ids) {
356 const PendingExtensionInfo* info =
357 pending_extension_manager->GetById(pending_id);
358 if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
359 VLOG(2) << "Extension " << pending_id << " is not auto updateable";
360 continue;
361 }
362
363 const bool is_corrupt_reinstall =
364 pending_extension_manager->IsPolicyReinstallForCorruptionExpected(
365 pending_id);
366 if (CanUseUpdateService(pending_id)) {
367 update_check_params.update_info[pending_id].is_corrupt_reinstall =
368 is_corrupt_reinstall;
369 } else if (downloader_->AddPendingExtension(
370 pending_id, info->update_url(), info->install_source(),
371 is_corrupt_reinstall, request_id, params.fetch_priority)) {
372 request.in_progress_ids_.insert(pending_id);
373 InstallStageTracker::Get(profile_)->ReportInstallationStage(
374 pending_id, InstallStageTracker::Stage::DOWNLOADING);
375 } else {
376 InstallStageTracker::Get(profile_)->ReportFailure(
377 pending_id,
378 InstallStageTracker::FailureReason::DOWNLOADER_ADD_FAILED);
379 }
380 }
381
382 AddToDownloader(®istry_->enabled_extensions(), pending_ids, request_id,
383 params.fetch_priority, &update_check_params);
384 AddToDownloader(®istry_->disabled_extensions(), pending_ids, request_id,
385 params.fetch_priority, &update_check_params);
386 ExtensionSet remotely_disabled_extensions;
387 for (auto extension : registry_->blocklisted_extensions()) {
388 if (extension_prefs_->HasDisableReason(
389 extension->id(), disable_reason::DISABLE_REMOTELY_FOR_MALWARE))
390 remotely_disabled_extensions.Insert(extension);
391 }
392 AddToDownloader(&remotely_disabled_extensions, pending_ids, request_id,
393 params.fetch_priority, &update_check_params);
394 } else {
395 for (const ExtensionId& id : params.ids) {
396 const Extension* extension = registry_->GetExtensionById(
397 id, extensions::ExtensionRegistry::EVERYTHING);
398 if (extension) {
399 if (CanUseUpdateService(id)) {
400 update_check_params.update_info[id] = ExtensionUpdateData();
401 } else if (downloader_->AddExtension(*extension, request_id,
402 params.fetch_priority)) {
403 request.in_progress_ids_.insert(extension->id());
404 }
405 }
406 }
407 }
408
409 // StartAllPending() might call OnExtensionDownloadFailed/Finished before
410 // it returns, which would cause NotifyIfFinished to incorrectly try to
411 // send out a notification. So check before we call StartAllPending if any
412 // extensions are going to be updated, and use that to figure out if
413 // NotifyIfFinished should be called.
414 bool empty_downloader = request.in_progress_ids_.empty();
415 bool awaiting_update_service = !update_check_params.update_info.empty();
416
417 request.awaiting_update_service = awaiting_update_service;
418
419 // StartAllPending() will call OnExtensionDownloadFailed or
420 // OnExtensionDownloadFinished for each extension that was checked.
421 downloader_->StartAllPending(extension_cache_);
422
423 if (awaiting_update_service) {
424 update_check_params.priority =
425 params.fetch_priority == ManifestFetchData::FetchPriority::BACKGROUND
426 ? ExtensionUpdateCheckParams::UpdateCheckPriority::BACKGROUND
427 : ExtensionUpdateCheckParams::UpdateCheckPriority::FOREGROUND;
428 update_check_params.install_immediately = params.install_immediately;
429 update_service_->StartUpdateCheck(
430 update_check_params,
431 base::BindOnce(&ExtensionUpdater::OnUpdateServiceFinished,
432 base::Unretained(this), request_id));
433 } else if (empty_downloader) {
434 NotifyIfFinished(request_id);
435 }
436 }
437
OnExtensionDownloadStageChanged(const ExtensionId & id,Stage stage)438 void ExtensionUpdater::OnExtensionDownloadStageChanged(const ExtensionId& id,
439 Stage stage) {
440 InstallStageTracker::Get(profile_)->ReportDownloadingStage(id, stage);
441 }
442
OnExtensionDownloadCacheStatusRetrieved(const ExtensionId & id,CacheStatus cache_status)443 void ExtensionUpdater::OnExtensionDownloadCacheStatusRetrieved(
444 const ExtensionId& id,
445 CacheStatus cache_status) {
446 InstallStageTracker::Get(profile_)->ReportDownloadingCacheStatus(
447 id, cache_status);
448 }
449
OnExtensionDownloadFailed(const ExtensionId & id,Error error,const PingResult & ping,const std::set<int> & request_ids,const FailureData & data)450 void ExtensionUpdater::OnExtensionDownloadFailed(
451 const ExtensionId& id,
452 Error error,
453 const PingResult& ping,
454 const std::set<int>& request_ids,
455 const FailureData& data) {
456 DCHECK(alive_);
457 InstallStageTracker* install_stage_tracker =
458 InstallStageTracker::Get(profile_);
459
460 switch (error) {
461 case Error::CRX_FETCH_FAILED:
462 install_stage_tracker->ReportFetchError(
463 id, InstallStageTracker::FailureReason::CRX_FETCH_FAILED, data);
464 break;
465 case Error::CRX_FETCH_URL_EMPTY:
466 DCHECK(data.additional_info);
467 install_stage_tracker->ReportInfoOnNoUpdatesFailure(
468 id, data.additional_info.value());
469 install_stage_tracker->ReportFailure(
470 id, InstallStageTracker::FailureReason::CRX_FETCH_URL_EMPTY);
471 break;
472 case Error::CRX_FETCH_URL_INVALID:
473 install_stage_tracker->ReportFailure(
474 id, InstallStageTracker::FailureReason::CRX_FETCH_URL_INVALID);
475 break;
476 case Error::MANIFEST_FETCH_FAILED:
477 install_stage_tracker->ReportFetchError(
478 id, InstallStageTracker::FailureReason::MANIFEST_FETCH_FAILED, data);
479 break;
480 case Error::MANIFEST_INVALID:
481 DCHECK(data.manifest_invalid_error);
482 install_stage_tracker->ReportManifestInvalidFailure(id, data);
483 break;
484 case Error::NO_UPDATE_AVAILABLE:
485 install_stage_tracker->ReportFailure(
486 id, InstallStageTracker::FailureReason::NO_UPDATE);
487 break;
488 case Error::DISABLED:
489 // Error::DISABLED corresponds to the browser having disabled extension
490 // updates, the extension updater does not actually run when this error
491 // code is emitted.
492 break;
493 }
494
495 UpdatePingData(id, ping);
496 bool install_immediately = false;
497 for (const int request_id : request_ids) {
498 InProgressCheck& request = requests_in_progress_[request_id];
499 install_immediately |= request.install_immediately;
500 request.in_progress_ids_.erase(id);
501 NotifyIfFinished(request_id);
502 }
503
504 // This method is called if no updates were found. However a previous update
505 // check might have queued an update for this extension already. If a
506 // current update check has |install_immediately| set the previously
507 // queued update should be installed now.
508 if (install_immediately && service_->GetPendingExtensionUpdate(id))
509 service_->FinishDelayedInstallationIfReady(id, install_immediately);
510 }
511
OnExtensionDownloadFinished(const CRXFileInfo & file,bool file_ownership_passed,const GURL & download_url,const PingResult & ping,const std::set<int> & request_ids,InstallCallback callback)512 void ExtensionUpdater::OnExtensionDownloadFinished(
513 const CRXFileInfo& file,
514 bool file_ownership_passed,
515 const GURL& download_url,
516 const PingResult& ping,
517 const std::set<int>& request_ids,
518 InstallCallback callback) {
519 DCHECK(alive_);
520 InstallStageTracker::Get(profile_)->ReportInstallationStage(
521 file.extension_id, InstallStageTracker::Stage::INSTALLING);
522 UpdatePingData(file.extension_id, ping);
523
524 VLOG(2) << download_url << " written to " << file.path.value();
525
526 FetchedCRXFile fetched(file, file_ownership_passed, request_ids,
527 std::move(callback));
528 // InstallCRXFile() removes extensions from |in_progress_ids_| after starting
529 // the crx installer.
530 InstallCRXFile(std::move(fetched));
531 }
532
GetPingDataForExtension(const ExtensionId & id,ManifestFetchData::PingData * ping_data)533 bool ExtensionUpdater::GetPingDataForExtension(
534 const ExtensionId& id,
535 ManifestFetchData::PingData* ping_data) {
536 DCHECK(alive_);
537 ping_data->rollcall_days =
538 CalculatePingDaysForExtension(extension_prefs_->LastPingDay(id));
539 ping_data->is_enabled = service_->IsExtensionEnabled(id);
540 if (!ping_data->is_enabled)
541 ping_data->disable_reasons = extension_prefs_->GetDisableReasons(id);
542 ping_data->active_days =
543 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
544 extension_prefs_->GetActiveBit(id));
545 return true;
546 }
547
GetUpdateUrlData(const ExtensionId & id)548 std::string ExtensionUpdater::GetUpdateUrlData(const ExtensionId& id) {
549 DCHECK(alive_);
550 return extension::GetUpdateURLData(extension_prefs_, id);
551 }
552
IsExtensionPending(const ExtensionId & id)553 bool ExtensionUpdater::IsExtensionPending(const ExtensionId& id) {
554 DCHECK(alive_);
555 return service_->pending_extension_manager()->IsIdPending(id);
556 }
557
GetExtensionExistingVersion(const ExtensionId & id,std::string * version)558 bool ExtensionUpdater::GetExtensionExistingVersion(const ExtensionId& id,
559 std::string* version) {
560 DCHECK(alive_);
561 const Extension* extension = registry_->GetExtensionById(
562 id, extensions::ExtensionRegistry::EVERYTHING);
563 if (!extension)
564 return false;
565 const Extension* update = service_->GetPendingExtensionUpdate(id);
566 if (update)
567 *version = update->VersionString();
568 else
569 *version = extension->VersionString();
570 return true;
571 }
572
UpdatePingData(const ExtensionId & id,const PingResult & ping_result)573 void ExtensionUpdater::UpdatePingData(const ExtensionId& id,
574 const PingResult& ping_result) {
575 DCHECK(alive_);
576 if (ping_result.did_ping)
577 extension_prefs_->SetLastPingDay(id, ping_result.day_start);
578 if (extension_prefs_->GetActiveBit(id)) {
579 extension_prefs_->SetActiveBit(id, false);
580 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
581 }
582 }
583
PutExtensionInCache(const CRXFileInfo & crx_info)584 void ExtensionUpdater::PutExtensionInCache(const CRXFileInfo& crx_info) {
585 if (extension_cache_) {
586 const ExtensionId& extension_id = crx_info.extension_id;
587 const base::Version& expected_version = crx_info.expected_version;
588 const std::string& expected_hash = crx_info.expected_hash;
589 const base::FilePath& crx_path = crx_info.path;
590 DCHECK(expected_version.IsValid());
591 extension_cache_->PutExtension(
592 extension_id, expected_hash, crx_path, expected_version.GetString(),
593 base::BindRepeating(&ExtensionUpdater::CleanUpCrxFileIfNeeded,
594 weak_ptr_factory_.GetWeakPtr()));
595 } else {
596 CleanUpCrxFileIfNeeded(crx_info.path, true);
597 }
598 }
599
CleanUpCrxFileIfNeeded(const base::FilePath & crx_path,bool file_ownership_passed)600 void ExtensionUpdater::CleanUpCrxFileIfNeeded(const base::FilePath& crx_path,
601 bool file_ownership_passed) {
602 if (file_ownership_passed &&
603 !GetExtensionFileTaskRunner()->PostTask(
604 FROM_HERE, base::BindOnce(base::GetDeleteFileCallback(), crx_path))) {
605 NOTREACHED();
606 }
607 }
608
CanUseUpdateService(const ExtensionId & extension_id) const609 bool ExtensionUpdater::CanUseUpdateService(
610 const ExtensionId& extension_id) const {
611 if (g_force_use_update_service_for_tests)
612 return true;
613
614 // Won't update extensions with empty IDs.
615 if (extension_id.empty())
616 return false;
617
618 // Update service can only update extensions that have been installed on the
619 // system.
620 const Extension* extension = registry_->GetInstalledExtension(extension_id);
621 if (extension == nullptr)
622 return false;
623
624 // Furthermore, we can only update extensions that were installed from the
625 // default webstore or extensions with empty update URLs not converted from
626 // user scripts.
627 const GURL& update_url = ManifestURL::GetUpdateURL(extension);
628 if (update_url.is_empty())
629 return !extension->converted_from_user_script();
630 return extension_urls::IsWebstoreUpdateUrl(update_url);
631 }
632
InstallCRXFile(FetchedCRXFile crx_file)633 void ExtensionUpdater::InstallCRXFile(FetchedCRXFile crx_file) {
634 std::set<int> request_ids;
635
636 VLOG(2) << "updating " << crx_file.info.extension_id << " with "
637 << crx_file.info.path.value();
638
639 // The ExtensionService is now responsible for cleaning up the temp file
640 // at |crx_file.info.path|.
641 CrxInstaller* installer = nullptr;
642 if (service_->UpdateExtension(crx_file.info, crx_file.file_ownership_passed,
643 &installer)) {
644 // If the crx file passes the expectations from the update manifest, this
645 // callback inserts an entry in the extension cache and deletes it, if
646 // required.
647 installer->set_expectations_verified_callback(
648 base::BindOnce(&ExtensionUpdater::PutExtensionInCache,
649 weak_ptr_factory_.GetWeakPtr(), crx_file.info));
650
651 for (const int request_id : crx_file.request_ids) {
652 InProgressCheck& request = requests_in_progress_[request_id];
653 if (request.install_immediately) {
654 installer->set_install_immediately(true);
655 break;
656 }
657 }
658
659 running_crx_installs_[installer] = std::move(crx_file);
660
661 // Source parameter ensures that we only see the completion event for an
662 // installer we started.
663 registrar_.Add(this, NOTIFICATION_CRX_INSTALLER_DONE,
664 content::Source<CrxInstaller>(installer));
665 } else {
666 for (const int request_id : crx_file.request_ids) {
667 InProgressCheck& request = requests_in_progress_[request_id];
668 request.in_progress_ids_.erase(crx_file.info.extension_id);
669 }
670 request_ids.insert(crx_file.request_ids.begin(),
671 crx_file.request_ids.end());
672 }
673
674 for (const int request_id : request_ids)
675 NotifyIfFinished(request_id);
676 }
677
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)678 void ExtensionUpdater::Observe(int type,
679 const content::NotificationSource& source,
680 const content::NotificationDetails& details) {
681 DCHECK_EQ(NOTIFICATION_CRX_INSTALLER_DONE, type);
682
683 registrar_.Remove(this, NOTIFICATION_CRX_INSTALLER_DONE, source);
684
685 // If installing this file didn't succeed, we may need to re-download it.
686 const Extension* extension = content::Details<const Extension>(details).ptr();
687
688 CrxInstaller* installer = content::Source<CrxInstaller>(source).ptr();
689 auto iter = running_crx_installs_.find(installer);
690 DCHECK(iter != running_crx_installs_.end());
691 FetchedCRXFile& crx_file = iter->second;
692 if (!extension && installer->verification_check_failed() &&
693 !crx_file.callback.is_null()) {
694 // If extension downloader asked us to notify it about failed installations,
695 // it will resume a pending download from the manifest data it has already
696 // fetched and call us again with the same request_id's (with either
697 // OnExtensionDownloadFailed or OnExtensionDownloadFinished). For that
698 // reason we don't notify finished requests yet.
699 std::move(crx_file.callback).Run(true);
700 } else {
701 for (const int request_id : crx_file.request_ids) {
702 InProgressCheck& request = requests_in_progress_[request_id];
703 request.in_progress_ids_.erase(crx_file.info.extension_id);
704 NotifyIfFinished(request_id);
705 }
706 if (!crx_file.callback.is_null()) {
707 std::move(crx_file.callback).Run(false);
708 }
709 }
710
711 running_crx_installs_.erase(iter);
712 }
713
NotifyStarted()714 void ExtensionUpdater::NotifyStarted() {
715 content::NotificationService::current()->Notify(
716 NOTIFICATION_EXTENSION_UPDATING_STARTED,
717 content::Source<Profile>(profile_),
718 content::NotificationService::NoDetails());
719 }
720
OnUpdateServiceFinished(int request_id)721 void ExtensionUpdater::OnUpdateServiceFinished(int request_id) {
722 DCHECK(base::Contains(requests_in_progress_, request_id));
723 InProgressCheck& request = requests_in_progress_[request_id];
724 DCHECK(request.awaiting_update_service);
725 request.awaiting_update_service = false;
726 NotifyIfFinished(request_id);
727 }
728
NotifyIfFinished(int request_id)729 void ExtensionUpdater::NotifyIfFinished(int request_id) {
730 DCHECK(base::Contains(requests_in_progress_, request_id));
731 InProgressCheck& request = requests_in_progress_[request_id];
732 if (!request.in_progress_ids_.empty() || request.awaiting_update_service)
733 return; // This request is not done yet.
734 VLOG(2) << "Finished update check " << request_id;
735 if (!request.callback.is_null())
736 std::move(request.callback).Run();
737 requests_in_progress_.erase(request_id);
738 }
739
740 ExtensionUpdater::ScopedSkipScheduledCheckForTest::
ScopedSkipScheduledCheckForTest()741 ScopedSkipScheduledCheckForTest() {
742 DCHECK(!g_skip_scheduled_checks_for_tests);
743 g_skip_scheduled_checks_for_tests = true;
744 }
745
746 ExtensionUpdater::ScopedSkipScheduledCheckForTest::
~ScopedSkipScheduledCheckForTest()747 ~ScopedSkipScheduledCheckForTest() {
748 g_skip_scheduled_checks_for_tests = false;
749 }
750
751 } // namespace extensions
752