You can use the ota_from_target_files
tool provided in build/make/tools/releasetools
to build full and incremental
OTA packages for devices that use A/B system updates or
non-A/B system updates. The tool takes the
target-files.zip
file produced by the Android build system as input.
For devices running Android 11 or higher, you can build one OTA package for multiple devices with different SKUs. Doing so requires configuring the target devices to use dynamic fingerprints and updating the OTA metadata to include the device name and fingerprint in the pre and postcondition entries.
Android 8.0 deprecated file-based OTA packages for non-A/B devices, which must
instead use block-based OTA packages. To
generate block-based OTA packages or devices running Android 7.x or lower, pass
the --block
option to the ota_from_target_files
parameter.
Build full updates
A full update is an OTA package that contains the entire final state of the
device (system, boot, and recovery partitions). As long as the device is capable
of receiving and applying the package, the package can install the build
regardless of the current state of the device. For example, the following
commands use release tools to build the target-files.zip
archive for the
tardis
device.
. build/envsetup.sh && lunch tardis-eng
mkdir dist_output
make dist DIST_DIR=dist_output
make dist
builds a full OTA package (in $OUT
). The resultant .zip
file
contains everything needed to construct OTA packages for the tardis
device.
You can also build the ota_from_target_files
as a python binary and call it to
build either full or incremental packages.
ota_from_target_files dist_output/tardis-target_files.zip ota_update.zip
The ota_from_target_files
path is set up in $PATH
, and the resulting python
binary is located in the out/
directory.
ota_update.zip
is now ready to be sent to test devices (everything is signed
with the test key). For user devices, generate and use your own private keys as
detailed in Signing builds for release.
Build incremental updates
An incremental update is an OTA package that contains binary patches to data already on the device. Packages with incremental updates are typically smaller as they don't need to include unchanged files. In addition, as changed files are often very similar to their previous versions, the package only needs to include an encoding of the differences between the two files.
You can install an incremental update package only on devices that have the
source build used in constructing the package. To build an incremental update,
you need the target_files.zip
file from the previous build (the one you want
to update from) as well as the target_files.zip
file from the new build. For
example, the following commands use release tools to build an incremental update
for the tardis
device.
ota_from_target_files -i PREVIOUS-tardis-target_files.zip dist_output/tardis-target_files.zip incremental_ota_update.zip
This build is very similar to the previous build, and the incremental update
package (incremental_ota_update.zip
) is much smaller than the corresponding
full update (about 1 MB instead of 60 MB).
Distribute an incremental package only to devices that run exactly the same
previous build used as the incremental package's starting point. You must flash
the images in PREVIOUS-tardis-target_files.zip
or PREVIOUS-tardis-img.zip
(both built with make dist
, to be flashed with fastboot update
), instead of
the ones under the PRODUCT_OUT
directory (built with make
, which will be
flashed with fastboot flashall
). Attempting to install the incremental package
on a device with some other build results in an installation error. When the
install fails, the device remains in the same working state (running the old
system); the package verifies the previous state of all the files it updates
before touching them, so the device isn't stranded in a half upgraded state.
For the best user experience, offer a full update for every 3–4 incremental updates. This helps users catch up to the latest release and avoid a long install sequence of incremental updates.
Build OTA packages for multiple SKUs
Android 11 or higher supports using a single OTA package for multiple devices with different SKUs. Doing so requires configuring the target devices to use dynamic fingerprints and updating the OTA metadata (using OTA tools) to include the device name and fingerprint in the pre and post condition entries.
About SKUs
The format of a SKU is a variation of combined build
parameter values and
is typically an undeclared subset of the current build_fingerprint
parameters.
OEMs can use any combination of CDD-approved build parameters for a SKU while
also using a single image for those SKUs. For example, the following SKU has
multiple variations:
SKU = <product><device><modifierA><modifierB><modifierC>
modifierA
is the device level (such as Pro, Premium, or Plus)modifierB
is the hardware variation (such as radio)modifierC
is the region, which can be general (such as NA, EMEA, or CHN ) or country- or language-specific (such as JPN, ENG, or CHN)
Many OEMs use a single image for multiple SKUs, then derive the final product
name and device fingerprint at runtime after the device boots up. This process
simplifies the platform development process, enabling devices with minor
customizations but different product names to share common images (such as
tardis
and tardispro
).
Use dynamic fingerprints
A fingerprint is a defined concatenation of build
parameters such as
ro.product.brand
, ro.product.name
, and ro.product.device
. The fingerprint
of a device is derived from the system partition fingerprint and is used as an
unique identifier of the images (and bytes) running on the device. To create a
dynamic fingerprint, use dynamic logic in the device's build.prop
file to
get the value of bootloader variables at device boot time, then use that data to
create a dynamic fingerprint for that device.
For example, to use dynamic fingerprints for tardis
and tardispro
devices,
update the following files as shown below.
Update the
odm/etc/build_std.prop
file to contain the following line.ro.odm.product.device=tardis
Update the
odm/etc/build_pro.prop
file to contain the following line.ro.odm.product.device=tardispro
Update the
odm/etc/build.prop
file to contain the following lines.ro.odm.product.device=tardis import /odm/etc/build_${ro.boot.product.hardware.sku}.prop
These lines dynamically set the device name, fingerprint, and
ro.build.fingerprint
values based on the value of the
ro.boot.product.hardware.sku
bootloader property (which is read-only).
Update OTA package metadata
An OTA package contains a metadata file (META-INF/com/android/metadata
) that
describes the package, including the precondition and postcondition of the OTA
package. For example, the following code is the metadata file for an OTA package
targeting the tardis
device.
post-build=google/tardis/tardis:11/RP1A.200521.001/6516341:userdebug/dev-keys
post-build-incremental=6516341
post-sdk-level=30
post-security-patch-level=2020-07-05
post-timestamp=1590026334
pre-build=google/tardis/tardis:11/RP1A.200519.002.A1/6515794:userdebug/dev-keys
pre-build-incremental=6515794
pre-device=tardis
The pre-device
, pre-build-incremental
, and pre-build
values define the
state a device must have before the OTA package can install. The
post-build-incremental
and post-build
values define the state a device is
expected to have after the OTA package installs. The values of pre-
and
post-
fields are derived from the following corresponding build properties.
- The
pre-device
value is derived from thero.product.device
build property. - The
pre-build-incremental
andpost-build-incremental
values are derived from thero.build.version.incremental
build property. - The
pre-build
andpost-build
values are derived from thero.build.fingerprint
build property.
On devices running Android 11 or higher, you can use
the --boot_variable_file
flag in OTA tools to specify a path to a file that
contains the values of the runtime variables used in creating the device's
dynamic fingerprint. The data is then used to update the OTA metadata to include
the device name and fingerprint in the pre-
and post-
conditions (using the
pipe character | as the delimiter). The --boot_variable_file
flag has the
following syntax and description.
- Syntax:
--boot_variable_file <path>
- Description: Specifies a path to a file that contains the possible values of
ro.boot.*
properties. Used to calculate the possible runtime fingerprints when somero.product.*
properties are overridden by the import statement. The file expects one property per line where each line has the following format:prop_name=value1,value2
.
For example, when the property is ro.boot.product.hardware.sku=std,pro
, the
OTA metadata for tardis
and tardispro
devices is as shown below.
post-build=google/tardis/tardis:11/<suffix>|google/tardis/tardispro:11/<suffix>
pre-build=google/tardis/tardis:11/<suffix>|google/tardis/tardispro:11/<suffix>
pre-device=tardis|tardispro
To support this functionality on devices running Android 10, see the reference
implementation.
This changelist conditionally parses the import
statements in the build.prop
file, which enables property overrides to be recognized and reflected in the
final OTA metadata.