blob: 4b8061c85619a87b18b55275efb0954349771c5c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <map>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/version.h"
#include "components/update_client/update_client_errors.h"
// The UpdateClient class is a facade with a simple interface. The interface
// exposes a few APIs to install a CRX or update a group of CRXs.
// The difference between a CRX install and a CRX update is relatively minor.
// The terminology going forward will use the word "update" to cover both
// install and update scenarios, except where details regarding the install
// case are relevant.
// Handling an update consists of a series of actions such as sending an update
// check to the server, followed by parsing the server response, identifying
// the CRXs that require an update, downloading the differential update if
// it is available, unpacking and patching the differential update, then
// falling back to trying a similar set of actions using the full update.
// At the end of this process, completion pings are sent to the server,
// as needed, for the CRXs which had updates.
// As a general idea, this code handles the action steps needed to update
// a group of components serially, one step at a time. However, concurrent
// execution of calls to UpdateClient::Update is possible, therefore,
// queuing of updates could happen in some cases. More below.
// The UpdateClient class features a subject-observer interface to observe
// the CRX state changes during an update.
// The threading model for this code assumes that most of the code in the
// public interface runs on a SingleThreadTaskRunner.
// This task runner corresponds to the browser UI thread in many cases. There
// are parts of the installer interface that run on blocking task runners, which
// are usually threads in a thread pool.
// Using the UpdateClient is relatively easy. This assumes that the client
// of this code has already implemented the observer interface as needed, and
// can provide an installer, as described below.
// std::unique_ptr<UpdateClient> update_client(UpdateClientFactory(...));
// update_client->AddObserver(&observer);
// std::vector<std::string> ids;
// ids.push_back(...));
// update_client->Update(ids, base::BindOnce(...), base::BindOnce(...));
// UpdateClient::Update takes two callbacks as parameters. First callback
// allows the client of this code to provide an instance of CrxComponent
// data structure that specifies additional parameters of the update.
// CrxComponent has a CrxInstaller data member, which must be provided by the
// callers of this class. The second callback indicates that this non-blocking
// call has completed.
// There could be several ways of triggering updates for a CRX, user-initiated,
// or timer-based. Since the execution of updates is concurrent, the parameters
// for the update must be provided right before the update is handled.
// Otherwise, the version of the CRX set in the CrxComponent may not be correct.
// The UpdateClient public interface includes two functions: Install and
// Update. These functions correspond to installing one CRX immediately as a
// foreground activity (Install), and updating a group of CRXs silently in the
// background (Update). This distinction is important. Background updates are
// queued up and their actions run serially, one at a time, for the purpose of
// conserving local resources such as CPU, network, and I/O.
// On the other hand, installs are never queued up but run concurrently, as
// requested by the user.
// The update client introduces a runtime constraint regarding interleaving
// updates and installs. If installs or updates for a given CRX are in progress,
// then installs for the same CRX will fail with a specific error.
// Implementation details.
// The implementation details below are not relevant to callers of this
// code. However, these design notes are relevant to the owners and maintainers
// of this module.
// The design for the update client consists of a number of abstractions
// such as: task, update engine, update context, and action.
// The execution model for these abstractions is simple. They usually expose
// a public, non-blocking Run function, and they invoke a callback when
// the Run function has completed.
// A task is the unit of work for the UpdateClient. A task is associated
// with a single call of the Update function. A task represents a group
// of CRXs that are updated together.
// The UpdateClient is responsible for the queuing of tasks, if queuing is
// needed.
// When the task runs, it calls the update engine to handle the updates for
// the CRXs associated with the task. The UpdateEngine is the abstraction
// responsible for breaking down the update in a set of discrete steps, which
// are implemented as actions, and running the actions.
// The UpdateEngine maintains a set of UpdateContext instances. Each of
// these instances maintains the update state for all the CRXs belonging to
// a given task. The UpdateContext contains a queue of CRX ids.
// The UpdateEngine will handle updates for the CRXs in the order they appear
// in the queue, until the queue is empty.
// The update state for each CRX is maintained in a container of CrxUpdateItem*.
// As actions run, each action updates the CRX state, represented by one of
// these CrxUpdateItem* instances.
// Although the UpdateEngine can and will run update tasks concurrently, the
// actions of a task are run sequentially.
// The Action is a polymorphic type. There is some code reuse for convenience,
// implemented as a mixin. The polymorphic behavior of some of the actions
// is achieved using a template method.
// State changes of a CRX could generate events, which are observed using a
// subject-observer interface.
// The actions chain up. In some sense, the actions implement a state machine,
// as the CRX undergoes a series of state transitions in the process of
// being checked for updates and applying the update.
class PrefRegistrySimple;
namespace base {
class FilePath;
namespace crx_file {
enum class VerifierFormat;
namespace update_client {
class Configurator;
enum class Error;
struct CrxUpdateItem;
enum class ComponentState {
// Defines an interface for a generic CRX installer.
class CrxInstaller : public base::RefCountedThreadSafe<CrxInstaller> {
// Contains the result of the Install operation.
struct Result {
explicit Result(int error, int extended_error = 0)
: error(error), extended_error(extended_error) {}
explicit Result(InstallError error, int extended_error = 0)
: error(static_cast<int>(error)), extended_error(extended_error) {}
int error = 0; // 0 indicates that install has been successful.
int extended_error = 0;
using Callback = base::OnceCallback<void(const Result& result)>;
// Called on the main thread when there was a problem unpacking or
// verifying the CRX. |error| is a non-zero value which is only meaningful
// to the caller.
virtual void OnUpdateError(int error) = 0;
// Called by the update service when a CRX has been unpacked
// and it is ready to be installed. |unpack_path| contains the
// temporary directory with all the unpacked CRX files. |pubkey| contains the
// public key of the CRX in the PEM format, without the header and the footer.
// The caller must invoke the |callback| when the install flow has completed.
// This method may be called from a thread other than the main thread.
virtual void Install(const base::FilePath& unpack_path,
const std::string& public_key,
Callback callback) = 0;
// Sets |installed_file| to the full path to the installed |file|. |file| is
// the filename of the file in this CRX. Returns false if this is
// not possible (the file has been removed or modified, or its current
// location is unknown). Otherwise, it returns true.
virtual bool GetInstalledFile(const std::string& file,
base::FilePath* installed_file) = 0;
// Called when a CRX has been unregistered and all versions should
// be uninstalled from disk. Returns true if uninstallation is supported,
// and false otherwise.
virtual bool Uninstall() = 0;
friend class base::RefCountedThreadSafe<CrxInstaller>;
virtual ~CrxInstaller() {}
// A dictionary of installer-specific, arbitrary name-value pairs, which
// may be used in the update checks requests.
using InstallerAttributes = std::map<std::string, std::string>;
struct CrxComponent {
CrxComponent(const CrxComponent& other);
// Optional SHA256 hash of the CRX's public key. If not supplied, the
// unpacker can accept any CRX for this app, provided that the CRX meets the
// VerifierFormat requirements specified by the service's configurator.
// Callers that know or need a specific developer signature on acceptable CRX
// files must provide this.
std::vector<uint8_t> pk_hash;
scoped_refptr<CrxInstaller> installer;
std::string app_id;
// The current version if the CRX is updated. Otherwise, "0" or "0.0" if
// the CRX is installed.
base::Version version;
std::string fingerprint; // Optional.
std::string name; // Optional.
std::vector<std::string> handled_mime_types;
// Optional.
// Valid values for the name part of an attribute match
// ^[-_a-zA-Z0-9]{1,256}$ and valid values the value part of an attribute
// match ^[-.,;+_=a-zA-Z0-9]{0,256}$ .
InstallerAttributes installer_attributes;
// Specifies that the CRX can be background-downloaded in some cases.
// The default for this value is |true|.
bool allows_background_download;
// Specifies that the update checks and pings associated with this component
// require confidentiality. The default for this value is |true|. As a side
// note, the confidentiality of the downloads is enforced by the server,
// which only returns secure download URLs in this case.
bool requires_network_encryption;
// Specifies the strength of package validation required for the item.
crx_file::VerifierFormat crx_format_requirement;
// True if the component allows enabling or disabling updates by group policy.
// This member should be set to |false| for data, non-binary components, such
// as CRLSet, Supervised User Whitelists, STH Set, Origin Trials, and File
// Type Policies.
bool supports_group_policy_enable_component_updates;
// Reasons why this component/extension is disabled.
std::vector<int> disabled_reasons;
// Information about where the component/extension was installed from.
// For extension, this information is set from the update service, which
// gets the install source from the update URL.
std::string install_source;
// Information about where the component/extension was loaded from.
// For extensions, this information is inferred from the extension
// registry.
std::string install_location;
// Called when a non-blocking call of UpdateClient completes.
using Callback = base::OnceCallback<void(Error error)>;
// All methods are safe to call only from the browser's main thread. Once an
// instance of this class is created, the reference to it must be released
// only after the thread pools of the browser process have been destroyed and
// the browser process has gone single-threaded.
class UpdateClient : public base::RefCounted<UpdateClient> {
using CrxDataCallback =
const std::vector<std::string>& ids)>;
// Defines an interface to observe the UpdateClient. It provides
// notifications when state changes occur for the service itself or for the
// registered CRXs.
class Observer {
enum class Events {
// Sent before the update client does an update check.
// Sent when there is a new version of a registered CRX. After
// the notification is sent the CRX will be downloaded unless the
// update client inserts a
// Sent when a CRX is in the update queue but it can't be acted on
// right away, because the update client spaces out CRX updates due to a
// throttling policy.
// Sent after the new CRX has been downloaded but before the install
// or the upgrade is attempted.
// Sent when a CRX has been successfully updated.
// Sent when a CRX has not been updated because there was no update
// available for this component.
// Sent when an error ocurred during an update for any reason, including
// the update check itself failed, or the download of the update payload
// failed, or applying the update failed.
// Sent when CRX bytes are being downloaded.
virtual ~Observer() {}
// Called by the update client when a state change happens.
// If an |id| is specified, then the event is fired on behalf of the
// specific CRX. The implementors of this interface are
// expected to filter the relevant events based on the id of the CRX.
virtual void OnEvent(Events event, const std::string& id) = 0;
// Adds an observer for this class. An observer should not be added more
// than once. The caller retains the ownership of the observer object.
virtual void AddObserver(Observer* observer) = 0;
// Removes an observer. It is safe for an observer to be removed while
// the observers are being notified.
virtual void RemoveObserver(Observer* observer) = 0;
// Installs the specified CRX. Calls back on |callback| after the
// update has been handled. The |error| parameter of the |callback|
// contains an error code in the case of a run-time error, or 0 if the
// install has been handled successfully. Overlapping calls of this function
// are executed concurrently, as long as the id parameter is different,
// meaning that installs of different components are parallelized.
// The |Install| function is intended to be used for foreground installs of
// one CRX. These cases are usually associated with on-demand install
// scenarios, which are triggered by user actions. Installs are never
// queued up.
virtual void Install(const std::string& id,
CrxDataCallback crx_data_callback,
Callback callback) = 0;
// Updates the specified CRXs. Calls back on |crx_data_callback| before the
// update is attempted to give the caller the opportunity to provide the
// instances of CrxComponent to be used for this update. The |Update| function
// is intended to be used for background updates of several CRXs. Overlapping
// calls to this function result in a queuing behavior, and the execution
// of each call is serialized. In addition, updates are always queued up when
// installs are running. The |is_foreground| parameter must be set to true if
// the invocation of this function is a result of a user initiated update.
virtual void Update(const std::vector<std::string>& ids,
CrxDataCallback crx_data_callback,
bool is_foreground,
Callback callback) = 0;
// Sends an uninstall ping for the CRX identified by |id| and |version|. The
// |reason| parameter is defined by the caller. The current implementation of
// this function only sends a best-effort, fire-and-forget ping. It has no
// other side effects regarding installs or updates done through an instance
// of this class.
virtual void SendUninstallPing(const std::string& id,
const base::Version& version,
int reason,
Callback callback) = 0;
// Returns status details about a CRX update. The function returns true in
// case of success and false in case of errors, such as |id| was
// invalid or not known.
virtual bool GetCrxUpdateState(const std::string& id,
CrxUpdateItem* update_item) const = 0;
// Returns true if the |id| is found in any running task.
virtual bool IsUpdating(const std::string& id) const = 0;
// Cancels the queued updates and makes a best effort to stop updates in
// progress as soon as possible. Some updates may not be stopped, in which
// case, the updates will run to completion. Calling this function has no
// effect if updates are not currently executed or queued up.
virtual void Stop() = 0;
friend class base::RefCounted<UpdateClient>;
virtual ~UpdateClient() {}
// Creates an instance of the update client.
scoped_refptr<UpdateClient> UpdateClientFactory(
scoped_refptr<Configurator> config);
// This must be called prior to the construction of any Configurator that
// contains a PrefService.
void RegisterPrefs(PrefRegistrySimple* registry);
// This must be called prior to the construction of any Configurator that
// needs access to local user profiles.
// This function is mostly used for ExtensionUpdater, which requires update
// info from user profiles.
void RegisterProfilePrefs(PrefRegistrySimple* registry);
} // namespace update_client