背景
由于设备无法使用无线网卡连接无线网络,且服务器暂时未打包出新的ROM包。为了验证系统的可用性和OTA apk的正确性,先采用本地更新的方式。
1. 制作升级包
1.1 编译源码
source build/envsetup.sh && lunch deviceModel-userdebug
mkdir dist_output
make dist DIST_DIR=dist_output
使用指令在源码路径下创建一个dist_output目录,并将编译结果输出到该目录下。 编译会生成一个deviceModel-target_files-eng.zip压缩包。
1.2 制作全量升级包
ota_from_target_files dist_output/deviceModel-target_files-eng.zip full_ota_package.zip
使用ota_from_target_files指令,将第一步编译源码生成的zip重新编译成全量包。
解压缩编译生成的全量包full_ota_package.zip,可以看到其中的文件组成如下所示:
文件结构如下所示:
在解压缩完编译好的全量升级包,主要有两个文件:payload.bin 和 payload_properties.txt。其中payload.bin就是编译好的升级包,稍后验证升级就需要将这个文件刷入系统,而payload_properties.txt中记录了升级所需的hash。
payload_properties.txt的文件内容如下所示:
其中记录的两个hash值稍后本地验证的时候需要传入。
1.3 制作差分升级包
在制作全量升级包的时候使用了一个ota_from_target_files的指令。这个指令的详细参数如下所示:
owner@owner:m_files$ ota_from_target_files --help
Given a target-files zipfile, produces an OTA package that installs that build.
An incremental OTA is produced if -i is given, otherwise a full OTA is produced.
Usage: ota_from_target_files [options] input_target_files output_ota_package
Common options that apply to both of non-A/B and A/B OTAs
--downgrade
Intentionally generate an incremental OTA that updates from a newer build
to an older one (e.g. downgrading from P preview back to O MR1).
"ota-downgrade=yes" will be set in the package metadata file. A data wipe
will always be enforced when using this flag, so "ota-wipe=yes" will also
be included in the metadata file. The update-binary in the source build
will be used in the OTA package, unless --binary flag is specified. Please
also check the comment for --override_timestamp below.
-i (--incremental_from) <file>
Generate an incremental OTA using the given target-files zip as the
starting build.
-k (--package_key) <key>
Key to use to sign the package (default is the value of
default_system_dev_certificate from the input target-files's
META/misc_info.txt, or "build/make/target/product/security/testkey" if
that value is not specified).
For incremental OTAs, the default value is based on the source
target-file, not the target build.
--override_timestamp
Intentionally generate an incremental OTA that updates from a newer build
to an older one (based on timestamp comparison), by setting the downgrade
flag in the package metadata. This differs from --downgrade flag, as we
don't enforce a data wipe with this flag. Because we know for sure this is
NOT an actual downgrade case, but two builds happen to be cut in a reverse
order (e.g. from two branches). A legit use case is that we cut a new
build C (after having A and B), but want to enfore an update path of A ->
C -> B. Specifying --downgrade may not help since that would enforce a
data wipe for C -> B update.
We used to set a fake timestamp in the package metadata for this flow. But
now we consolidate the two cases (i.e. an actual downgrade, or a downgrade
based on timestamp) with the same "ota-downgrade=yes" flag, with the
difference being whether "ota-wipe=yes" is set.
--wipe_user_data
Generate an OTA package that will wipe the user data partition when
installed.
--retrofit_dynamic_partitions
Generates an OTA package that updates a device to support dynamic
partitions (default False). This flag is implied when generating
an incremental OTA where the base build does not support dynamic
partitions but the target build does. For A/B, when this flag is set,
--skip_postinstall is implied.
--skip_compatibility_check
Skip checking compatibility of the input target files package.
--output_metadata_path
Write a copy of the metadata to a separate file. Therefore, users can
read the post build fingerprint without extracting the OTA package.
--force_non_ab
This flag can only be set on an A/B device that also supports non-A/B
updates. Implies --two_step.
If set, generate that non-A/B update package.
If not set, generates A/B package for A/B device and non-A/B package for
non-A/B device.
Non-A/B OTA specific options
-b (--binary) <file>
Use the given binary as the update-binary in the output package, instead
of the binary in the build's target_files. Use for development only.
--block
Generate a block-based OTA for non-A/B device. We have deprecated the
support for file-based OTA since O. Block-based OTA will be used by
default for all non-A/B devices. Keeping this flag here to not break
existing callers.
-e (--extra_script) <file>
Insert the contents of file at the end of the update script.
--full_bootloader
Similar to --full_radio. When generating an incremental OTA, always
include a full copy of bootloader image.
--full_radio
When generating an incremental OTA, always include a full copy of radio
image. This option is only meaningful when -i is specified, because a full
radio is always included in a full OTA if applicable.
--log_diff <file>
Generate a log file that shows the differences in the source and target
builds for an incremental package. This option is only meaningful when -i
is specified.
-o (--oem_settings) <main_file[,additional_files...]>
Comma seperated list of files used to specify the expected OEM-specific
properties on the OEM partition of the intended device. Multiple expected
values can be used by providing multiple files. Only the first dict will
be used to compute fingerprint, while the rest will be used to assert
OEM-specific properties.
--oem_no_mount
For devices with OEM-specific properties but without an OEM partition, do
not mount the OEM partition in the updater-script. This should be very
rarely used, since it's expected to have a dedicated OEM partition for
OEM-specific properties. Only meaningful when -o is specified.
--stash_threshold <float>
Specify the threshold that will be used to compute the maximum allowed
stash size (defaults to 0.8).
-t (--worker_threads) <int>
Specify the number of worker-threads that will be used when generating
patches for incremental updates (defaults to 3).
--verify
Verify the checksums of the updated system and vendor (if any) partitions.
Non-A/B incremental OTAs only.
-2 (--two_step)
Generate a 'two-step' OTA package, where recovery is updated first, so
that any changes made to the system partition are done using the new
recovery (new kernel, etc.).
A/B OTA specific options
--disable_fec_computation
Disable the on device FEC data computation for incremental updates.
--include_secondary
Additionally include the payload for secondary slot images (default:
False). Only meaningful when generating A/B OTAs.
By default, an A/B OTA package doesn't contain the images for the
secondary slot (e.g. system_other.img). Specifying this flag allows
generating a separate payload that will install secondary slot images.
Such a package needs to be applied in a two-stage manner, with a reboot
in-between. During the first stage, the updater applies the primary
payload only. Upon finishing, it reboots the device into the newly updated
slot. It then continues to install the secondary payload to the inactive
slot, but without switching the active slot at the end (needs the matching
support in update_engine, i.e. SWITCH_SLOT_ON_REBOOT flag).
Due to the special install procedure, the secondary payload will be always
generated as a full payload.
--payload_signer <signer>
Specify the signer when signing the payload and metadata for A/B OTAs.
By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
with the package private key. If the private key cannot be accessed
directly, a payload signer that knows how to do that should be specified.
The signer will be supplied with "-inkey <path_to_key>",
"-in <input_file>" and "-out <output_file>" parameters.
--payload_signer_args <args>
Specify the arguments needed for payload signer.
--payload_signer_maximum_signature_size <signature_size>
The maximum signature size (in bytes) that would be generated by the given
payload signer. Only meaningful when custom payload signer is specified
via '--payload_signer'.
If the signer uses a RSA key, this should be the number of bytes to
represent the modulus. If it uses an EC key, this is the size of a
DER-encoded ECDSA signature.
--payload_signer_key_size <key_size>
Deprecated. Use the '--payload_signer_maximum_signature_size' instead.
--boot_variable_file <path>
A file that contains the possible values of ro.boot.* properties. It's
used to calculate the possible runtime fingerprints when some
ro.product.* properties are overridden by the 'import' statement.
The file expects one property per line, and each line has the following
format: 'prop_name=value1,value2'. e.g. 'ro.boot.product.sku=std,pro'
--skip_postinstall
Skip the postinstall hooks when generating an A/B OTA package (default:
False). Note that this discards ALL the hooks, including non-optional
ones. Should only be used if caller knows it's safe to do so (e.g. all the
postinstall work is to dexopt apps and a data wipe will happen immediately
after). Only meaningful when generating A/B OTAs.
Global options
-p (--path) <dir>
Prepend <dir>/bin to the list of places to search for binaries run by this
script, and expect to find jars in <dir>/framework.
-s (--device_specific) <file>
Path to the Python module containing device-specific releasetools code.
-x (--extra) <key=value>
Add a key/value pair to the 'extras' dict, which device-specific extension
code may look at.
-v (--verbose)
Show command lines being executed.
-h (--help)
Display this usage message and exit.
--logfile <file>
Put verbose logs to specified file (regardless of --verbose option.)
重点关注-i:
Generate an incremental OTA using the given target-files zip as the starting build.
也就是说可以使用这个参数制作差分升级包。但是差分包是基于两个系统源码的差异制成。在1.1编译源码之后在源码目录下生成一个压缩包 /dist_output/deviceModel-target_files-eng.zip。在这个基础上,我们稍加修改系统代码,然后使用和第一步同样的指令重新编译一下系统源码,并且将编译结果输出到new_dist_output目录下。使用指令如下:
source build/envsetup.sh && lunch deviceModel-userdebug
mkdir new_dist_output
make dist DIST_DIR=new_dist_output
在目录new_dist_output下会生成一个deviceModel-target_files-eng.zip压缩包。
接着使用指令将1.1中编译生成的zip和当前这一步生成的zip作为参数,制作出出incremental_ota.zip
ota_from_target_files -i dist_output/deviceModel-target_files-eng.zip new_dist_output/deviceModel-target_files-eng.zip incremental_ota_package.zip
最终制作出incremental_ota_package.zip用于差分升级验证。
2. 升级验证
本地升级验证使用update_engine_client指令。
使用指令如下:
# 将制作好的ota升级包push到设备中
adb push D:\release\payload.bin /sdcard/payload.bin
# 暂停SELinux权限校验
setenforce 0
# 使用指令开始升级
update_engine_client --payload=file:///sdcard/payload.bin --update --headers="
FILE_HASH=ffDiU+EsGtSP3j1NqSJjPXJYbp8pHmuD/HmQkcgGFM4=
FILE_SIZE=436934454
METADATA_HASH=T/8NwBNEfSr2IZyqp2/BRqOzYrh/o6RzOhw/4hFpFoU=
METADATA_SIZE=31232"
使用update_engine_client升级时,--headers后面带的参数就是编译出的hash值,也就是payload_properties.txt文件中记录的hash。
完成以上指令后,可以抓取update_engine日志或者查看OTA apk的UI,可以看到设备更新的日志。