blob: 58c2e0d47b36c22407d5456e4694748f1fda320a [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_UPDATER_H_
#define CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_UPDATER_H_
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include "base/auto_reset.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/updater/extension_downloader.h"
#include "extensions/browser/updater/extension_downloader_delegate.h"
#include "extensions/browser/updater/extension_downloader_types.h"
#include "extensions/browser/updater/extension_update_data.h"
#include "extensions/browser/updater/update_service.h"
#include "extensions/common/extension_id.h"
#include "url/gurl.h"
class PrefService;
class Profile;
class ScopedProfileKeepAlive;
namespace extensions {
class CrxInstallError;
class CrxInstaller;
class ExtensionCache;
class ExtensionPrefs;
class ExtensionRegistry;
class ExtensionServiceInterface;
class ExtensionSet;
struct ExtensionUpdateCheckParams;
class ExtensionUpdaterTest;
// A class for doing auto-updates of installed Extensions. Used like this:
//
// std::unique_ptr<ExtensionUpdater> updater =
// std::make_unique<ExtensionUpdater>(my_extensions_service,
// extension_prefs,
// pref_service,
// profile,
// update_frequency_secs,
// downloader_factory);
// updater->Start();
// ....
// updater->Stop();
class ExtensionUpdater : public ExtensionDownloaderDelegate {
public:
using FinishedCallback = base::OnceClosure;
struct CheckParams {
// Creates a default CheckParams instance that checks for all extensions.
CheckParams();
~CheckParams();
CheckParams(const CheckParams& other) = delete;
CheckParams& operator=(const CheckParams& other) = delete;
CheckParams(CheckParams&& other);
CheckParams& operator=(CheckParams&& other);
// The set of extensions that should be checked for updates. If empty
// all extensions will be included in the update check.
std::list<ExtensionId> ids;
// Normally extension updates get installed only when the extension is idle.
// Setting this to true causes any updates that are found to be installed
// right away.
bool install_immediately = false;
// An extension update check can be originated by a user or by a scheduled
// task. When the value of |fetch_priority| is FOREGROUND, the update
// request was initiated by a user.
DownloadFetchPriority fetch_priority = DownloadFetchPriority::kBackground;
// If set, will be called when an update is found and before an attempt to
// download and install it is made.
UpdateFoundCallback update_found_callback;
// Callback to call when the update check is complete. Can be null, if
// you're not interested in when this happens.
FinishedCallback callback;
};
// A class for use in tests to skip scheduled update checks for extensions
// during the lifetime of an instance of it. Only one instance should be alive
// at any given time.
class ScopedSkipScheduledCheckForTest {
public:
ScopedSkipScheduledCheckForTest();
ScopedSkipScheduledCheckForTest(const ScopedSkipScheduledCheckForTest&) =
delete;
ScopedSkipScheduledCheckForTest& operator=(
const ScopedSkipScheduledCheckForTest&) = delete;
~ScopedSkipScheduledCheckForTest();
};
// Holds a pointer to the passed |service|, using it for querying installed
// extensions and installing updated ones. The |frequency_seconds| parameter
// controls how often update checks are scheduled.
ExtensionUpdater(ExtensionServiceInterface* service,
ExtensionPrefs* extension_prefs,
PrefService* prefs,
Profile* profile,
int frequency_seconds,
ExtensionCache* cache,
const ExtensionDownloader::Factory& downloader_factory);
ExtensionUpdater(const ExtensionUpdater&) = delete;
ExtensionUpdater& operator=(const ExtensionUpdater&) = delete;
~ExtensionUpdater() override;
// Starts the updater running. Should be called at most once.
void Start();
// Stops the updater running, cancelling any outstanding update manifest and
// crx downloads. Does not cancel any in-progress installs.
void Stop();
// Posts a task to do an update check. Does nothing if there is
// already a pending task that has not yet run.
void CheckSoon();
// Starts an update check right now, instead of waiting for the next
// regularly scheduled check or a pending check from CheckSoon().
void CheckNow(CheckParams params);
// Returns true iff CheckSoon() has been called but the update check
// hasn't been performed yet. This is used mostly by tests; calling
// code should just call CheckSoon().
bool WillCheckSoon() const;
// Overrides the extension cache with |extension_cache| for testing.
void SetExtensionCacheForTesting(ExtensionCache* extension_cache);
// Overrides the extension downloader with |downloader| for testing.
void SetExtensionDownloaderForTesting(
std::unique_ptr<ExtensionDownloader> downloader);
// After this is called, the next ExtensionUpdater instance to be started will
// call CheckNow() instead of CheckSoon() for its initial update.
static void UpdateImmediatelyForFirstRun();
// For testing, changes the backoff policy for ExtensionDownloader's manifest
// queue to get less initial delay and the tests don't time out.
void SetBackoffPolicyForTesting(
const net::BackoffEntry::Policy& backoff_policy);
// Always fetch updates via update service, not the extension downloader.
static base::AutoReset<bool> GetScopedUseUpdateServiceForTesting();
// Set a callback to invoke when updating has started.
void SetUpdatingStartedCallbackForTesting(base::RepeatingClosure callback);
// A callback that is invoked when the next invocation of CxrInstaller
// finishes (successfully or not).
void SetCrxInstallerResultCallbackForTesting(
ExtensionSystem::InstallUpdateCallback callback);
private:
friend class ExtensionUpdaterTest;
friend class ExtensionUpdaterFileHandler;
// FetchedCRXFile holds information about a CRX file we fetched to disk,
// but have not yet installed.
struct FetchedCRXFile {
FetchedCRXFile();
FetchedCRXFile(const CRXFileInfo& file,
bool file_ownership_passed,
const std::set<int>& request_ids,
InstallCallback callback);
FetchedCRXFile(FetchedCRXFile&& other);
FetchedCRXFile& operator=(FetchedCRXFile&& other);
~FetchedCRXFile();
CRXFileInfo info;
GURL download_url;
bool file_ownership_passed;
std::set<int> request_ids;
InstallCallback callback;
scoped_refptr<CrxInstaller> installer;
};
struct InProgressCheck {
InProgressCheck();
InProgressCheck(const InProgressCheck&) = delete;
InProgressCheck& operator=(const InProgressCheck&) = delete;
~InProgressCheck();
bool install_immediately = false;
bool awaiting_update_service = false;
UpdateFoundCallback update_found_callback;
FinishedCallback callback;
// Prevents the destruction of the Profile* while an update check is in
// progress.
// TODO(crbug.com/40174537): Find a way to pass the keepalive to
// UpdateClient instead of holding it here.
std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive;
// The ids of extensions that have in-progress update checks.
std::set<ExtensionId> in_progress_ids;
};
// Ensure that we have a valid ExtensionDownloader instance referenced by
// |downloader|.
void EnsureDownloaderCreated();
// Schedules a task to call NextCheck after |frequency_| delay, plus
// or minus 0 to 20% (to help spread load evenly on servers).
void ScheduleNextCheck();
// Add fetch records for extensions that are installed to the downloader,
// ignoring |pending_ids| so the extension isn't fetched again.
void AddToDownloader(const ExtensionSet* extensions,
const std::set<ExtensionId>& pending_ids,
int request_id,
DownloadFetchPriority fetch_priority,
ExtensionUpdateCheckParams* update_check_params);
// Adds |extension| to the downloader, providing it with |fetch_priority|,
// |request_id| and data extracted from the extension object.
// |fetch_priority| parameter notifies the downloader the priority of this
// extension update (either foreground or background).
bool AddExtensionToDownloader(const Extension& extension,
int request_id,
DownloadFetchPriority fetch_priority);
// Conduct a check as scheduled by ScheduleNextCheck.
void NextCheck();
// Posted by CheckSoon().
void DoCheckSoon();
// Implementation of ExtensionDownloaderDelegate.
void OnExtensionDownloadStageChanged(const ExtensionId& id,
Stage stage) override;
void OnExtensionUpdateFound(const ExtensionId& id,
const std::set<int>& request_ids,
const base::Version& version) override;
void OnExtensionDownloadCacheStatusRetrieved(const ExtensionId& id,
CacheStatus status) override;
void OnExtensionDownloadFailed(const ExtensionId& id,
Error error,
const PingResult& ping,
const std::set<int>& request_ids,
const FailureData& data) override;
void OnExtensionDownloadRetry(const ExtensionId& id,
const FailureData& data) override;
void OnExtensionDownloadFinished(const CRXFileInfo& file,
bool file_ownership_passed,
const GURL& download_url,
const PingResult& ping,
const std::set<int>& request_id,
InstallCallback callback) override;
bool GetPingDataForExtension(const ExtensionId& id,
DownloadPingData* ping_data) override;
bool IsExtensionPending(const ExtensionId& id) override;
bool GetExtensionExistingVersion(const ExtensionId& id,
std::string* version) override;
void UpdatePingData(const ExtensionId& id, const PingResult& ping_result);
// Starts installing a crx file that has been fetched but not installed yet.
void InstallCRXFile(FetchedCRXFile crx_file);
// Send a notification that update checks are starting.
void NotifyStarted();
// Send a notification if we're finished updating.
void NotifyIfFinished(int request_id);
// |udpate_service_| will execute this function on finish.
void OnUpdateServiceFinished(int request_id);
void ExtensionCheckFinished(const ExtensionId& extension_id,
FinishedCallback callback);
// Callback set in the crx installer and invoked when the crx file has passed
// the expectations check. It takes the ownership of the file pointed to by
// |crx_info|.
void PutExtensionInCache(const CRXFileInfo& crx_info);
// Deletes the crx file at |crx_path| if ownership is passed.
void CleanUpCrxFileIfNeeded(const base::FilePath& crx_path,
bool file_ownership_passed);
void OnInstallerDone(const base::UnguessableToken& token,
const std::optional<CrxInstallError>& error);
// This function verifies if |extension_id| can be updated using
// UpdateService.
bool CanUseUpdateService(const ExtensionId& extension_id) const;
// Whether Start() has been called but not Stop().
bool alive_ = false;
// Pointer back to the service that owns this ExtensionUpdater.
raw_ptr<ExtensionServiceInterface> service_ = nullptr;
// A closure passed into the ExtensionUpdater to teach it how to construct
// new ExtensionDownloader instances.
const ExtensionDownloader::Factory downloader_factory_;
// Fetches the crx files for the extensions that have an available update.
std::unique_ptr<ExtensionDownloader> downloader_;
// Update service is responsible for updating Webstore extensions.
// Note that |UpdateService| is a KeyedService class, which can only be
// created through a |KeyedServiceFactory| singleton, thus |update_service_|
// will be freed by the same factory singleton before the browser is
// shutdown.
raw_ptr<UpdateService> update_service_ = nullptr;
base::TimeDelta frequency_;
bool will_check_soon_ = false;
raw_ptr<ExtensionPrefs, DanglingUntriaged> extension_prefs_ = nullptr;
raw_ptr<PrefService, DanglingUntriaged> prefs_ = nullptr;
raw_ptr<Profile, DanglingUntriaged> profile_ = nullptr;
raw_ptr<ExtensionRegistry, DanglingUntriaged> registry_ = nullptr;
std::map<int, InProgressCheck> requests_in_progress_;
int next_request_id_ = 0;
// CRX installs that are currently in progress. Used to get the FetchedCRXFile
// when OnInstallerDone is called.
std::map<base::UnguessableToken, FetchedCRXFile> running_crx_installs_;
raw_ptr<ExtensionCache, DanglingUntriaged> extension_cache_ = nullptr;
base::RepeatingClosure updating_started_callback_;
ExtensionSystem::InstallUpdateCallback installer_result_callback_for_testing_;
base::WeakPtrFactory<ExtensionUpdater> weak_ptr_factory_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_UPDATER_EXTENSION_UPDATER_H_