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(&registry_->enabled_extensions(), pending_ids, request_id,
383                     params.fetch_priority, &update_check_params);
384     AddToDownloader(&registry_->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