This is the functional specification for Chromium Updater. It describes the externally observable behavior of the updater, including APIs and UI.
The metainstaller (UpdaterSetup) is a small executable that contains a compressed copy of the updater as a resource, extracts it, and triggers installation of the updater / an app. The metainstaller is downloaded by the user and can be run from any directory.
The size of the metainstaller is less than 1500KiB.
The metainstaller may have a tag attached to it. The tag is a piece of unsigned data from which the metainstaller extracts the ID of the application to be installed, along with the application's brand code, usage-stats opt-in status, and any additional parameters to be associated with the application.
On Windows, the tag is embedded in one of the certificates in the metainstaller PE.
The metainstaller parses its tag and re-launches itself at high integrity if installing an application with needsadmin=true
or needsadmin=prefers
.
Metainstaller localization presents the metainstaller UI with the user's preferred language on the current system. Every string shown in the UI is translated.
The bundle installer allows installation of more than one application. The bundle installer is typically used in software distribution scenarios.
TODO(crbug.com/1035895): Document bundled installers.
TODO(crbug.com/1035895): Document the standalone installer, including building a standalone installer for a given application.
Applications on macOS frequently install via “drag-install”, and then install the updater using a standalone installer on the application's first-run. The updater app can be embedded in a macOS application bundle as a helper and then invoked with appropriate command line arguments to install itself.
TODO(crbug.com/1327497) - document.
The updater is installed at:
%LOCAL_APP_DATA%\{COMPANY}\{UPDATERNAME}\{VERSION}\updater.exe
%PROGRAM_FILES%\{COMPANY}\{UPDATERNAME}\{VERSION}\updater.exe
~/Library/{COMPANY}/{UPDATERNAME}/{VERSION}/{UPDATERNAME}.app
/Library/{COMPANY}/{UPDATERNAME}/{VERSION}/{UPDATERNAME}.app
The updater's functionality is split between several processes. The mode of a process is determined by command-line arguments:
OfflineManifest.gup
or <app-id>
.gup
. The file contains the update check response in XML format.--handoff
above.update
, the server will answer RPC messages on the UpdateService interface only.update-internal
, the server will answer RPC messages on the UpdateServiceInternal interface only.SERVICE_AUTO_START
) or when CoCreate
is called on one of several CLSIDs that the server supports.ServiceMain
by the SCM when CoCreate is called on one of several CLSIDs that the server supports. This is used for:If none of the above arguments are set, the updater will exit with an error.
Additionally, the mode may be modified by combining it with:
The updater communicates with update servers using the Omaha Protocol.
The updater accepts updates packaged as CRX₃ files. All files must be signed with a publisher key. The corresponding public key is hardcoded into the updater.
The updater must handle the installation of new applications. The updater can download, install, and update an applications when the application is running.
One or more applications can be installed at once, as a bundle.
Before installing, the integrity of the payload if verified. The payloads are stored in secure locations of the file system for per-system installs.
Considering network connectivity, there are two scenarios for installing an application:
An online install is done with a metainstaller. Every time an online installer is run, it sends an install event ping. The update check and the install event ping have the same session id. The install ping is lost if the network is unreachable for any reason, or the program has crashed.
This type of installs is done with a [standalone/offline installer] (#Standalone-Installer). This is an installer which embeds all data required to install the application, including the payload and various configuration data needed by the application setup. Such an install must be able to complete when a network connection is not available.
There are a couple of scenarios where the standalone/offline installer is used:
installdataindex provides a mechanism to specify configuration data which is passed to the application installer.
TODO(crbug.com/1035895): Document UI/UX
If the installation fails, the updater shows an error message with a “Help” button. Clicking the help button opens a web page in the user's default browser. The page is opened with a query string: ?product={AppId}&errorcode={ErrorCode}
.
TODO(crbug.com/1139014): Document OEM.
The installsource
identifies the originator of an install. It is provided on the command line of the metainstaller. TODO(crbug.com/1327491) - is this needed? If yes, document the algorithm.
As part of installing or updating an application, the updater will execute the application's installer. The API for the application installer is platform- specific.
The macOS API is defined here.
TODO(crbug.com/1035895): Document Windows installer APIs
To maintain backwards compatibility with Omaha and Keystone, the updater installs small versions of those programs that implement a subset of their APIs.
The updater installs a Keystone-like application that contains these shims:
Both the Keystone and Keystone Agent executables simply exit immediately when run.
The ksinstall executable expects to be called with --uninstall
and possibly --system
. If so, it deletes the Keystone shim (but not the overall updater) from the file system. Otherwise, it exits with a non-zero exit code.
The ksadmin shim is frequently called by applications and handles a variety of command lines:
Some of these actions accept parameters:
On Windows, the updater replaces Omaha's files with a copy of the updater, and keeps the Omaha registry entry (CLIENTS/{430FD4D0-B729-4F61-AA34-91526481799D}
) up-to-date with the latest pv
value. Additionally, the updater replaces the Omaha uninstall command line with its own.
Enterprise policies can prevent the installation of applications:
Refer to chrome/updater/protos/omaha_settings.proto for more details.
needsadmin
needsadmin
is one of the install parameters that can be specified for first installs via the metainstaller tag. needsadmin
is used to indicate whether the application needs admin rights to install.
For example, here is a command line for the Updater on Windows that includes:
UpdaterSetup.exe --install --tag="appguid=YourAppID&needsadmin=False"
In this case, the updater client understands that the application installer needs to install the application on a per-user basis for the current user.
needsadmin
has the following supported values:
true
: the application supports being installed systemwide and once installed, is available to all users on the system.false
: the application supports only user installs.prefers
: the application installation is first attempted systemwide. If the user refuses the UAC prompt however, the application is then only installed for the current user. The application installer needs to be able to support the installation as system, or per-user, or both modes.installdataindex
installdataindex
is one of the install parameters that can be specified for first installs on the command line or via the metainstaller tag.
For example, here is a typical command line for the Updater on Windows:
UpdaterSetup.exe /install "appguid=YourAppID&appname=YourAppName&needsadmin=False&lang=en&installdataindex =verboselog"
In this case, the updater client sends the installdataindex
of verboselog
to the update server.
This is how a JSON request from the updater client may look like:
{ "request":{ "@os":"win", "@updater":"updater", "acceptformat":"crx3", "app":[ { "appid":"YourAppID", "data":[ { "index":"verboselog", "name":"install" } ], "enabled":true, "installsource":"ondemand", "ping":{ "r":-2 }, "updatecheck":{ "sameversionupdate":true }, "version":"0.1" } ], "arch":"x86", "dedup":"cr", "domainjoined":true, "hw":{ "avx":true, "physmemory":32, "sse":true, "sse2":true, "sse3":true, "sse41":true, "sse42":true, "ssse3":true }, "ismachine":false, "lang":"en-US", "nacl_arch":"x86-64", "os":{ "arch":"x86_64", "platform":"Windows", "version":"10.0.19042.1586" }, "prodversion":"101.0.4949.0", "protocol":"3.1", "requestid":"{6b417770-1f68-4d52-8843-356760c84d33}", "sessionid":"{37775211-4487-48d5-845d-35a1d71b03bc}", "updaterversion":"101.0.4949.0", "wow64":true } }
The server retrieves the data corresponding to installdataindex=verboselog
and returns it back to the updater client.
This is how a JSON response from the update server may look like:
"response":{ "protocol":"3.1", "app":[ {"appid":"12345", "data":[{ "status":"ok", "name":"install", "index":"verboselog", "#text":"{\"logging\":{\"verbose\":true}}" }], "updatecheck":{ "status":"ok", "urls":{"url":[{"codebase":"http://example.com/"}, {"codebasediff":"http://diff.example.com/"}]}, "manifest":{ "version":"1.2.3.4", "prodversionmin":"2.0.143.0", "run":"UpdaterSetup.exe", "arguments":"--arg1 --arg2", "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}} } } ] }
The updater client writes this data to a temporary file in the same directory as the application installer. This is for security reasons, since writing the data to the temp directory could potentially allow a man-in-the-middle attack.
The updater client provides the temporary file as a parameter to the application installer.
Let's say, as shown above, that the update server responds with these example file contents:
{"logging":{"verbose":true}}
The updater client will now create a temporary file, say c:\my path\temporaryfile.dat
(assuming the application installer is running from c:\my path\YesExe.exe
), with the following file contents:
\xEF\xBB\xBF{"logging":{"verbose":true}}
and then provide the file as a parameter to the application installer:
"c:\my path\YesExe.exe" --installerdata="c:\my path\temporaryfile.dat"
EF BB BF
.INSTALLERDATA="pathtofile"
.--installerdata="pathtofile"
.INSTALLERDATA="pathtofile"
.TODO(crbug.com/1035895): Document differential updates.
The updater runs periodic tasks every hour, checking its own status, detecting application uninstalls, and potential checking for updates (if it has been at least 5 hours since the last update check).
TODO(crbug.com/1035895): Does the updater run at user login on Windows?
The updater exposes an RPC interface for any user to trigger an update check. The update can be triggered by any user on the system, even in the system scope.
The caller provides the ID of the item to update, the install data index to request, the priority, whether a same-version update (repair) is permitted, and callbacks to monitor the progress and completion of the operation.
Regardless of the normal update check timing, the update check will be attempted immediately.
The updater exposes an RPC interface for users to register an application with the updater. Unlike on-demand updates, cross-user application registration is not permitted.
If the application is already installed, it should be registered with the version present on disk. If it has not yet been installed, a version of 0 should be used.
Applications can report whether they are actively used or not through the updater. Update servers can then aggregate this information to produce user counts.
Windows:
macOS:
TODO(crbug.com/1035895): Document EULA signals.
The updater may upload its crash reports and send usage stats if and only if any piece of software it manages is permitted to send usage stats.
Windows:
HKCU\SOFTWARE\{Company}\Update\ClientState\{APPID}
→ usagestats (DWORD): 1 or HKLM\SOFTWARE\{Company}\Update\ClientStateMedium\{APPID}
→ usagestats (DWORD): 1macOS:
IsUploadEnabled
to true for a crashpad database maintained in a “Crashpad” subdirectory of their application data directory.TODO(crbug.com/1035895): Document relevant enterprise policies.
When the updater installs an application (an installer is run) it will send an event with "eventtype": 2
indicating the outcome of installation. The updater does not send such a ping for its own installation.
When the updater updates an application (including itself) it will send an event with "eventtype": 3
indicating the outcome of update operation.
When the updater detects the uninstallation of an application, it will send an event with "eventtype": 4
to notify the server of the uninstallation.
When the updater attempts to download a file, it will send an event with "eventtype": 14
describing the parameters and outcome of the download.
Multiple events associated with an update session are bundled together into a single request.
TODO(crbug.com/1035895): Document updater crash reporting.
The Application Command feature allows installed Updater-managed products to pre-register and later run command lines in the format c:\path-to-exe\exe.exe {params}
(elevated for system applications). {params}
is optional and can also include replaceable parameters substituted at runtime.
The program path must always be an absolute path. Additionally, for system applications, the program path must also be a child of %ProgramFiles% or %ProgramFiles(x86)%. For instance:
c:\path-to-exe\exe.exe
is an invalid path."c:\Program Files\subdir\exe.exe"
is a valid path."c:\Program Files (x86)\subdir\exe.exe"
is also a valid path.App commands are registered in the registry with the following formats:
Update\Clients\{`app_id`}\Commands\`command_id` REG_SZ "CommandLine" == {command format}
Update\Clients\{`app_id`} REG_SZ `command_id` == {command format}
Example {command format}
: c:\path-to\echo.exe %1 %2 %3 StaticParam4
As shown above, {command format}
needs to be the complete path to an executable followed by optional parameters.
Once registered, commands may be invoked using the execute
method in the IAppCommandWeb
interface.
interface IAppCommandWeb : IDispatch { // Use values from the AppCommandStatus enum. [propget] HRESULT status([out, retval] UINT*); [propget] HRESULT exitCode([out, retval] DWORD*); [propget] HRESULT output([out, retval] BSTR*); HRESULT execute([in, optional] VARIANT parameter1, [in, optional] VARIANT parameter2, [in, optional] VARIANT parameter3, [in, optional] VARIANT parameter4, [in, optional] VARIANT parameter5, [in, optional] VARIANT parameter6, [in, optional] VARIANT parameter7, [in, optional] VARIANT parameter8, [in, optional] VARIANT parameter9); };
Here is a code snippet a client may use, with error checking omitted:
var bundle = update3WebServer.createAppBundleWeb(); bundle.initialize(); bundle.createInstalledApp(appGuid); var app = bundle.appWeb(0); cmd = app.command(command); cmd.execute();
Parameters placeholders (%1-%9
) are filled by the numbered parameters in IAppCommandWeb::execute
. Placeholders without corresponding parameters will cause execution to fail.
Clients may poll for the execution status of commands that they have invoked by using the status
method of IAppCommandWeb
. When the status is COMMAND_STATUS_COMPLETE
, the exitCode
method can be used to get the process exit code.
%ProgramFiles%
for security, since it will be run elevated.%
followed by a digit. Literal %
characters must be escaped by doubling them.For example, if parameters to IAppCommandWeb::execute
are AA
and BB
respectively, a command format of: echo.exe %1 %%2 %%%2
becomes the command line echo.exe AA %2 %BB
On Mac and Linux, if the application was registered with an existence path checker and no file at that path exists (or if the file at that path is owned by another user), the updater will consider the application uninstalled, send the ping, and cease trying to keep it up to date.
On Windows, if the ClientState entry for for the application is deleted, the app is considered uninstalled.
On Windows, the updater registers a “UninstallCmdLine” under the Software\{Company}\Updater
key. This command line can be invoked by application uninstallers to cause the updater to immediately update its registrations. The updater will also check for uninstallations in every periodic task execution.
When the last registered application is uninstalled, the updater will uninstall itself. The updater will also uninstall itself if it has started 24 times but never had a product (besides itself) registered for updates.
The updater uninstaller removes all updater files, registry keys, RPC hooks, scheduled tasks, and so forth from the file system, except that it leaves a small log file in its data directory.
Building the updater produces both a production-ready updater executable and a version of the executable used for the purposes of testing. The test executable is identical to the production one except that it allows cetain constants to be overridden by the execution environment:
url
: Update check & ping-back URL.use_cup
: Whether CUP is used at all.cup_public_key
: An unarmored PEM-encoded ASN.1 SubjectPublicKeyInfo with the ecPublicKey algorithm and containing a named elliptic curve.group_policies
: Allows setting group policies, such as install and update policies.Windows: these overrides exist in registry, under HKLM\Software\{Company}\Update\Clients\ClientState\UpdateDev
.
macOS: these overrides exist in user defaults, in the {MAC_BUNDLE_IDENTIFIER}
suite. For system installs, the defaults are those of the root user.
TODO(crbug.com/1035895): Document tagging tools.