2015-03-24 03:13:21 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright (C) 2008 The Android Open Source Project
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Signs all the APK files in a target-files zipfile, producing a new
|
|
|
|
target-files zip.
|
|
|
|
|
|
|
|
Usage: sign_target_files_apks [flags] input_target_files output_target_files
|
|
|
|
|
|
|
|
-e (--extra_apks) <name,name,...=key>
|
2019-03-15 17:37:01 +01:00
|
|
|
Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
|
|
|
|
or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
|
|
|
|
specified in -e override any value for that app contained in the
|
|
|
|
apkcerts.txt file, or the container key for an APEX. Option may be
|
|
|
|
repeated to give multiple extra packages.
|
|
|
|
|
2022-07-26 01:12:30 +02:00
|
|
|
--extra_apex_payload_key <name,name,...=key>
|
2019-03-15 17:37:01 +01:00
|
|
|
Add a mapping for APEX package name to payload signing key, which will
|
|
|
|
override the default payload signing key in apexkeys.txt. Note that the
|
|
|
|
container key should be overridden via the `--extra_apks` flag above.
|
|
|
|
Option may be repeated for multiple APEXes.
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
--skip_apks_with_path_prefix <prefix>
|
|
|
|
Skip signing an APK if it has the matching prefix in its path. The prefix
|
|
|
|
should be matching the entry name, which has partition names in upper
|
|
|
|
case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
|
|
|
|
repeated to give multiple prefixes.
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
-k (--key_mapping) <src_key=dest_key>
|
|
|
|
Add a mapping from the key name as specified in apkcerts.txt (the
|
|
|
|
src_key) to the real key you wish to sign the package with
|
|
|
|
(dest_key). Option may be repeated to give multiple key
|
|
|
|
mappings.
|
|
|
|
|
|
|
|
-d (--default_key_mappings) <dir>
|
|
|
|
Set up the following key mappings:
|
|
|
|
|
|
|
|
$devkey/devkey ==> $dir/releasekey
|
|
|
|
$devkey/testkey ==> $dir/releasekey
|
|
|
|
$devkey/media ==> $dir/media
|
|
|
|
$devkey/shared ==> $dir/shared
|
|
|
|
$devkey/platform ==> $dir/platform
|
|
|
|
|
|
|
|
where $devkey is the directory part of the value of
|
|
|
|
default_system_dev_certificate from the input target-files's
|
2019-04-10 06:35:37 +02:00
|
|
|
META/misc_info.txt. (Defaulting to "build/make/target/product/security"
|
2015-03-24 03:13:21 +01:00
|
|
|
if the value is not present in misc_info.
|
|
|
|
|
|
|
|
-d and -k options are added to the set of mappings in the order
|
|
|
|
in which they appear on the command line.
|
|
|
|
|
|
|
|
-o (--replace_ota_keys)
|
2016-06-16 23:41:24 +02:00
|
|
|
Replace the certificate (public key) used by OTA package verification
|
|
|
|
with the ones specified in the input target_files zip (in the
|
|
|
|
META/otakeys.txt file). Key remapping (-k and -d) is performed on the
|
|
|
|
keys. For A/B devices, the payload verification key will be replaced
|
|
|
|
as well. If there're multiple OTA keys, only the first one will be used
|
|
|
|
for payload verification.
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
-t (--tag_changes) <+tag>,<-tag>,...
|
|
|
|
Comma-separated list of changes to make to the set of tags (in
|
|
|
|
the last component of the build fingerprint). Prefix each with
|
|
|
|
'+' or '-' to indicate whether that tag should be added or
|
|
|
|
removed. Changes are processed in the order they appear.
|
|
|
|
Default value is "-test-keys,-dev-keys,+release-keys".
|
|
|
|
|
2016-06-18 02:01:22 +02:00
|
|
|
--replace_verity_private_key <key>
|
|
|
|
Replace the private key used for verity signing. It expects a filename
|
|
|
|
WITHOUT the extension (e.g. verity_key).
|
|
|
|
|
|
|
|
--replace_verity_public_key <key>
|
|
|
|
Replace the certificate (public key) used for verity verification. The
|
2022-10-12 12:29:14 +02:00
|
|
|
key file replaces the one at BOOT/RAMDISK/verity_key. It expects the key
|
|
|
|
filename WITH the extension (e.g. verity_key.pub).
|
2016-06-18 02:01:22 +02:00
|
|
|
|
2016-06-17 04:58:44 +02:00
|
|
|
--replace_verity_keyid <path_to_X509_PEM_cert_file>
|
|
|
|
Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
|
2016-06-18 02:01:22 +02:00
|
|
|
with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
|
2017-06-20 00:48:02 +02:00
|
|
|
|
2020-02-21 10:48:18 +01:00
|
|
|
--remove_avb_public_keys <key1>,<key2>,...
|
|
|
|
Remove AVB public keys from the first-stage ramdisk. The key file to
|
|
|
|
remove is located at either of the following dirs:
|
|
|
|
- BOOT/RAMDISK/avb/ or
|
|
|
|
- BOOT/RAMDISK/first_stage_ramdisk/avb/
|
|
|
|
The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
|
|
|
|
set to true.
|
|
|
|
|
2022-11-07 22:36:38 +01:00
|
|
|
--avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
|
|
|
|
vbmeta_system,vbmeta_vendor}_algorithm <algorithm>
|
|
|
|
--avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
|
|
|
|
vbmeta_system,vbmeta_vendor}_key <key>
|
2017-06-20 00:48:02 +02:00
|
|
|
Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
|
|
|
|
the specified image. Otherwise it uses the existing values in info dict.
|
|
|
|
|
2022-11-07 22:36:38 +01:00
|
|
|
--avb_{apex,init_boot,boot,recovery,system,system_other,vendor,dtbo,vbmeta,
|
2021-12-11 23:03:10 +01:00
|
|
|
vbmeta_system,vbmeta_vendor}_extra_args <args>
|
2017-06-20 00:48:02 +02:00
|
|
|
Specify any additional args that are needed to AVB-sign the image
|
|
|
|
(e.g. "--signing_helper /path/to/helper"). The args will be appended to
|
|
|
|
the existing ones in info dict.
|
2020-01-23 19:47:54 +01:00
|
|
|
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
--avb_extra_custom_image_key <partition=key>
|
|
|
|
--avb_extra_custom_image_algorithm <partition=algorithm>
|
|
|
|
Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
|
|
|
|
the specified custom images mounted on the partition. Otherwise it uses
|
|
|
|
the existing values in info dict.
|
|
|
|
|
|
|
|
--avb_extra_custom_image_extra_args <partition=extra_args>
|
|
|
|
Specify any additional args that are needed to AVB-sign the custom images
|
|
|
|
mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
|
|
|
|
args will be appended to the existing ones in info dict.
|
|
|
|
|
2023-12-01 08:02:17 +01:00
|
|
|
--gki_signing_algorithm <algorithm>
|
|
|
|
--gki_signing_key <key>
|
|
|
|
--gki_signing_extra_args <args>
|
2024-01-24 07:10:17 +01:00
|
|
|
DEPRECATED Does nothing.
|
2023-12-01 08:02:17 +01:00
|
|
|
|
2020-01-23 19:47:54 +01:00
|
|
|
--android_jar_path <path>
|
|
|
|
Path to the android.jar to repack the apex file.
|
2021-10-13 11:39:33 +02:00
|
|
|
|
|
|
|
--allow_gsi_debug_sepolicy
|
|
|
|
Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
|
|
|
|
(/system/system_ext|/system_ext)/etc/selinux.
|
|
|
|
If not set, error out when the file exists.
|
2022-08-02 00:58:51 +02:00
|
|
|
|
|
|
|
--override_apk_keys <path>
|
|
|
|
Replace all APK keys with this private key
|
|
|
|
|
|
|
|
--override_apex_keys <path>
|
|
|
|
Replace all APEX keys with this private key
|
2023-11-06 19:53:41 +01:00
|
|
|
|
|
|
|
-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.
|
|
|
|
|
|
|
|
--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.
|
2015-03-24 03:13:21 +01:00
|
|
|
"""
|
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
from __future__ import print_function
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
import base64
|
|
|
|
import copy
|
|
|
|
import errno
|
2017-08-14 15:49:21 +02:00
|
|
|
import gzip
|
2019-07-25 08:31:19 +02:00
|
|
|
import io
|
2019-03-15 17:37:01 +01:00
|
|
|
import itertools
|
2019-03-15 17:33:43 +01:00
|
|
|
import logging
|
2015-03-24 03:13:21 +01:00
|
|
|
import os
|
|
|
|
import re
|
2017-08-14 15:49:21 +02:00
|
|
|
import shutil
|
2017-07-12 20:57:05 +02:00
|
|
|
import stat
|
2017-12-24 19:37:38 +01:00
|
|
|
import sys
|
2015-03-24 03:13:21 +01:00
|
|
|
import tempfile
|
|
|
|
import zipfile
|
2017-12-05 02:16:36 +01:00
|
|
|
from xml.etree import ElementTree
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
import add_img_to_target_files
|
2019-03-15 17:37:01 +01:00
|
|
|
import apex_utils
|
2015-03-24 03:13:21 +01:00
|
|
|
import common
|
2023-11-06 19:53:41 +01:00
|
|
|
import payload_signer
|
|
|
|
from payload_signer import SignOtaPackage, PAYLOAD_BIN
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
|
|
|
|
if sys.hexversion < 0x02070000:
|
|
|
|
print("Python 2.7 or newer is required.", file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
2019-03-15 17:33:43 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
OPTIONS = common.OPTIONS
|
|
|
|
|
|
|
|
OPTIONS.extra_apks = {}
|
2019-03-15 17:37:01 +01:00
|
|
|
OPTIONS.extra_apex_payload_keys = {}
|
2018-06-19 21:19:35 +02:00
|
|
|
OPTIONS.skip_apks_with_path_prefix = set()
|
2015-03-24 03:13:21 +01:00
|
|
|
OPTIONS.key_map = {}
|
2017-05-23 23:51:02 +02:00
|
|
|
OPTIONS.rebuild_recovery = False
|
2015-03-24 03:13:21 +01:00
|
|
|
OPTIONS.replace_ota_keys = False
|
2020-02-21 10:48:18 +01:00
|
|
|
OPTIONS.remove_avb_public_keys = None
|
2015-03-24 03:13:21 +01:00
|
|
|
OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
|
2017-06-20 00:48:02 +02:00
|
|
|
OPTIONS.avb_keys = {}
|
|
|
|
OPTIONS.avb_algorithms = {}
|
|
|
|
OPTIONS.avb_extra_args = {}
|
2020-01-23 19:47:54 +01:00
|
|
|
OPTIONS.android_jar_path = None
|
2021-09-14 19:29:38 +02:00
|
|
|
OPTIONS.vendor_partitions = set()
|
|
|
|
OPTIONS.vendor_otatools = None
|
2021-10-13 11:39:33 +02:00
|
|
|
OPTIONS.allow_gsi_debug_sepolicy = False
|
2022-08-02 00:58:51 +02:00
|
|
|
OPTIONS.override_apk_keys = None
|
|
|
|
OPTIONS.override_apex_keys = None
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
|
2019-10-09 09:04:28 +02:00
|
|
|
AVB_FOOTER_ARGS_BY_PARTITION = {
|
2021-03-04 02:31:04 +01:00
|
|
|
'boot': 'avb_boot_add_hash_footer_args',
|
2021-12-13 23:04:08 +01:00
|
|
|
'init_boot': 'avb_init_boot_add_hash_footer_args',
|
2021-03-04 02:31:04 +01:00
|
|
|
'dtbo': 'avb_dtbo_add_hash_footer_args',
|
|
|
|
'product': 'avb_product_add_hashtree_footer_args',
|
|
|
|
'recovery': 'avb_recovery_add_hash_footer_args',
|
|
|
|
'system': 'avb_system_add_hashtree_footer_args',
|
2022-01-27 08:05:08 +01:00
|
|
|
'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
|
2021-03-04 02:31:04 +01:00
|
|
|
'system_ext': 'avb_system_ext_add_hashtree_footer_args',
|
|
|
|
'system_other': 'avb_system_other_add_hashtree_footer_args',
|
|
|
|
'odm': 'avb_odm_add_hashtree_footer_args',
|
|
|
|
'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
|
|
|
|
'pvmfw': 'avb_pvmfw_add_hash_footer_args',
|
|
|
|
'vendor': 'avb_vendor_add_hashtree_footer_args',
|
|
|
|
'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
|
2022-04-18 10:00:40 +02:00
|
|
|
'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
|
2021-03-04 02:31:04 +01:00
|
|
|
'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
|
|
|
|
'vbmeta': 'avb_vbmeta_args',
|
|
|
|
'vbmeta_system': 'avb_vbmeta_system_args',
|
|
|
|
'vbmeta_vendor': 'avb_vbmeta_vendor_args',
|
2019-10-09 09:04:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-04 02:31:04 +01:00
|
|
|
# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
|
|
|
|
for partition in common.AVB_PARTITIONS:
|
|
|
|
if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
|
|
|
|
raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
|
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
# Partitions that can be regenerated after signing using a separate
|
|
|
|
# vendor otatools package.
|
|
|
|
ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
|
|
|
|
|
2021-03-04 02:31:04 +01:00
|
|
|
|
2021-06-12 02:03:43 +02:00
|
|
|
def IsApexFile(filename):
|
|
|
|
return filename.endswith(".apex") or filename.endswith(".capex")
|
|
|
|
|
|
|
|
|
2023-11-06 19:53:41 +01:00
|
|
|
def IsOtaPackage(fp):
|
|
|
|
with zipfile.ZipFile(fp) as zfp:
|
|
|
|
if not PAYLOAD_BIN in zfp.namelist():
|
|
|
|
return False
|
|
|
|
with zfp.open(PAYLOAD_BIN, "r") as payload:
|
|
|
|
magic = payload.read(4)
|
|
|
|
return magic == b"CrAU"
|
|
|
|
|
|
|
|
|
|
|
|
def IsEntryOtaPackage(input_zip, filename):
|
|
|
|
with input_zip.open(filename, "r") as fp:
|
2024-03-24 20:52:45 +01:00
|
|
|
external_attr = input_zip.getinfo(filename).external_attr
|
|
|
|
if stat.S_ISLNK(external_attr >> 16):
|
|
|
|
return IsEntryOtaPackage(input_zip,
|
|
|
|
os.path.join(os.path.dirname(filename), fp.read().decode()))
|
2023-11-06 19:53:41 +01:00
|
|
|
return IsOtaPackage(fp)
|
|
|
|
|
|
|
|
|
2021-06-12 02:03:43 +02:00
|
|
|
def GetApexFilename(filename):
|
|
|
|
name = os.path.basename(filename)
|
|
|
|
# Replace the suffix for compressed apex
|
|
|
|
if name.endswith(".capex"):
|
|
|
|
return name.replace(".capex", ".apex")
|
|
|
|
return name
|
|
|
|
|
|
|
|
|
2017-08-14 15:49:21 +02:00
|
|
|
def GetApkCerts(certmap):
|
2022-08-02 00:58:51 +02:00
|
|
|
if OPTIONS.override_apk_keys is not None:
|
|
|
|
for apk in certmap.keys():
|
|
|
|
certmap[apk] = OPTIONS.override_apk_keys
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
# apply the key remapping to the contents of the file
|
2019-06-25 00:33:41 +02:00
|
|
|
for apk, cert in certmap.items():
|
2015-03-24 03:13:21 +01:00
|
|
|
certmap[apk] = OPTIONS.key_map.get(cert, cert)
|
|
|
|
|
|
|
|
# apply all the -e options, overriding anything in the file
|
2019-06-25 00:33:41 +02:00
|
|
|
for apk, cert in OPTIONS.extra_apks.items():
|
2015-03-24 03:13:21 +01:00
|
|
|
if not cert:
|
|
|
|
cert = "PRESIGNED"
|
|
|
|
certmap[apk] = OPTIONS.key_map.get(cert, cert)
|
|
|
|
|
|
|
|
return certmap
|
|
|
|
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
def GetApexKeys(keys_info, key_map):
|
|
|
|
"""Gets APEX payload and container signing keys by applying the mapping rules.
|
|
|
|
|
2019-03-19 20:24:03 +01:00
|
|
|
Presigned payload / container keys will be set accordingly.
|
2019-03-15 17:37:01 +01:00
|
|
|
|
|
|
|
Args:
|
|
|
|
keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
|
2021-10-26 20:58:09 +02:00
|
|
|
container_key, sign_tool).
|
2019-03-15 17:37:01 +01:00
|
|
|
key_map: A dict that overrides the keys, specified via command-line input.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A dict that contains the updated APEX key mapping, which should be used for
|
|
|
|
the current signing.
|
2019-04-24 23:51:25 +02:00
|
|
|
|
|
|
|
Raises:
|
|
|
|
AssertionError: On invalid container / payload key overrides.
|
2019-03-15 17:37:01 +01:00
|
|
|
"""
|
2022-08-02 00:58:51 +02:00
|
|
|
if OPTIONS.override_apex_keys is not None:
|
|
|
|
for apex in keys_info.keys():
|
|
|
|
keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
|
|
|
|
|
|
|
|
if OPTIONS.override_apk_keys is not None:
|
|
|
|
key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
|
|
|
|
for apex in keys_info.keys():
|
|
|
|
keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
# Apply all the --extra_apex_payload_key options to override the payload
|
|
|
|
# signing keys in the given keys_info.
|
|
|
|
for apex, key in OPTIONS.extra_apex_payload_keys.items():
|
2019-03-19 20:24:03 +01:00
|
|
|
if not key:
|
|
|
|
key = 'PRESIGNED'
|
2019-07-11 20:52:52 +02:00
|
|
|
if apex not in keys_info:
|
|
|
|
logger.warning('Failed to find %s in target_files; Ignored', apex)
|
|
|
|
continue
|
2021-10-26 20:58:09 +02:00
|
|
|
keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
|
2019-03-15 17:37:01 +01:00
|
|
|
|
|
|
|
# Apply the key remapping to container keys.
|
2021-10-26 20:58:09 +02:00
|
|
|
for apex, (payload_key, container_key, sign_tool) in keys_info.items():
|
|
|
|
keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
|
2019-03-15 17:37:01 +01:00
|
|
|
|
|
|
|
# Apply all the --extra_apks options to override the container keys.
|
|
|
|
for apex, key in OPTIONS.extra_apks.items():
|
|
|
|
# Skip non-APEX containers.
|
|
|
|
if apex not in keys_info:
|
|
|
|
continue
|
2019-03-19 20:24:03 +01:00
|
|
|
if not key:
|
|
|
|
key = 'PRESIGNED'
|
2021-10-26 20:58:09 +02:00
|
|
|
keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2019-04-24 23:51:25 +02:00
|
|
|
# A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
|
|
|
|
# APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
|
|
|
|
# (overridden via commandline) indicates a config error, which should not be
|
|
|
|
# allowed.
|
2021-10-26 20:58:09 +02:00
|
|
|
for apex, (payload_key, container_key, sign_tool) in keys_info.items():
|
2019-04-24 23:51:25 +02:00
|
|
|
if container_key != 'PRESIGNED':
|
|
|
|
continue
|
|
|
|
if apex in OPTIONS.extra_apex_payload_keys:
|
|
|
|
payload_override = OPTIONS.extra_apex_payload_keys[apex]
|
|
|
|
assert payload_override == '', \
|
|
|
|
("Invalid APEX key overrides: {} has PRESIGNED container but "
|
|
|
|
"non-PRESIGNED payload key {}").format(apex, payload_override)
|
|
|
|
if payload_key != 'PRESIGNED':
|
|
|
|
print(
|
|
|
|
"Setting {} payload as PRESIGNED due to PRESIGNED container".format(
|
|
|
|
apex))
|
2021-10-26 20:58:09 +02:00
|
|
|
keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
|
2019-04-24 23:51:25 +02:00
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
return keys_info
|
|
|
|
|
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
|
2018-06-19 21:19:35 +02:00
|
|
|
"""Returns the APK info based on the given filename.
|
|
|
|
|
|
|
|
Checks if the given filename (with path) looks like an APK file, by taking the
|
2018-06-19 21:19:35 +02:00
|
|
|
compressed extension into consideration. If it appears to be an APK file,
|
|
|
|
further checks if the APK file should be skipped when signing, based on the
|
|
|
|
given path prefixes.
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
filename: Path to the file.
|
|
|
|
compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
|
|
|
|
or None if there's no compressed APKs.
|
2018-06-19 21:19:35 +02:00
|
|
|
skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
Returns:
|
2018-06-19 21:19:35 +02:00
|
|
|
(is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
|
|
|
|
given filename is an APK file. is_compressed indicates whether the APK file
|
|
|
|
is compressed (only meaningful when is_apk is True). should_be_skipped
|
|
|
|
indicates whether the filename matches any of the given prefixes to be
|
|
|
|
skipped.
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
Raises:
|
2018-06-19 21:19:35 +02:00
|
|
|
AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
|
2018-06-19 21:19:35 +02:00
|
|
|
"""
|
|
|
|
assert compressed_extension is None or compressed_extension.startswith('.'), \
|
|
|
|
"Invalid compressed_extension arg: '{}'".format(compressed_extension)
|
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
# skipped_prefixes should be one of set/list/tuple types. Other types such as
|
|
|
|
# str shouldn't be accepted.
|
2019-03-15 17:33:43 +01:00
|
|
|
assert isinstance(skipped_prefixes, (set, list, tuple)), \
|
|
|
|
"Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
|
2018-06-19 21:19:35 +02:00
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
compressed_apk_extension = (
|
|
|
|
".apk" + compressed_extension if compressed_extension else None)
|
|
|
|
is_apk = (filename.endswith(".apk") or
|
|
|
|
(compressed_apk_extension and
|
|
|
|
filename.endswith(compressed_apk_extension)))
|
|
|
|
if not is_apk:
|
2018-06-19 21:19:35 +02:00
|
|
|
return (False, False, False)
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
is_compressed = (compressed_apk_extension and
|
|
|
|
filename.endswith(compressed_apk_extension))
|
2018-06-19 21:19:35 +02:00
|
|
|
should_be_skipped = filename.startswith(tuple(skipped_prefixes))
|
|
|
|
return (True, is_compressed, should_be_skipped)
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
|
2019-03-19 20:24:03 +01:00
|
|
|
compressed_extension, apex_keys):
|
2019-03-15 17:37:01 +01:00
|
|
|
"""Checks that all the APKs and APEXes have keys specified.
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
input_tf_zip: An open target_files zip file.
|
2019-03-15 17:37:01 +01:00
|
|
|
known_keys: A set of APKs and APEXes that have known signing keys.
|
2018-06-19 21:19:35 +02:00
|
|
|
compressed_extension: The extension string of compressed APKs, such as
|
2019-03-15 17:37:01 +01:00
|
|
|
'.gz', or None if there's no compressed APKs.
|
2019-03-19 20:24:03 +01:00
|
|
|
apex_keys: A dict that contains the key mapping from APEX name to
|
2021-10-26 20:58:09 +02:00
|
|
|
(payload_key, container_key, sign_tool).
|
2018-06-19 21:19:35 +02:00
|
|
|
|
|
|
|
Raises:
|
2019-03-15 17:37:01 +01:00
|
|
|
AssertionError: On finding unknown APKs and APEXes.
|
2018-06-19 21:19:35 +02:00
|
|
|
"""
|
2019-03-15 17:37:01 +01:00
|
|
|
unknown_files = []
|
2015-03-24 03:13:21 +01:00
|
|
|
for info in input_tf_zip.infolist():
|
2021-02-19 08:02:36 +01:00
|
|
|
# Handle APEXes on all partitions
|
2021-06-12 02:03:43 +02:00
|
|
|
if IsApexFile(info.filename):
|
|
|
|
name = GetApexFilename(info.filename)
|
2019-03-15 17:37:01 +01:00
|
|
|
if name not in known_keys:
|
|
|
|
unknown_files.append(name)
|
|
|
|
continue
|
|
|
|
|
|
|
|
# And APKs.
|
2018-06-19 21:19:35 +02:00
|
|
|
(is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
|
|
|
|
info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
|
|
|
|
if not is_apk or should_be_skipped:
|
2018-06-19 21:19:35 +02:00
|
|
|
continue
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
name = os.path.basename(info.filename)
|
|
|
|
if is_compressed:
|
|
|
|
name = name[:-len(compressed_extension)]
|
2019-03-15 17:37:01 +01:00
|
|
|
if name not in known_keys:
|
|
|
|
unknown_files.append(name)
|
2018-06-19 21:19:35 +02:00
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
assert not unknown_files, \
|
2018-06-19 21:19:35 +02:00
|
|
|
("No key specified for:\n {}\n"
|
|
|
|
"Use '-e <apkname>=' to specify a key (which may be an empty string to "
|
2019-03-15 17:37:01 +01:00
|
|
|
"not sign this apk).".format("\n ".join(unknown_files)))
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2019-03-19 20:24:03 +01:00
|
|
|
# For all the APEXes, double check that we won't have an APEX that has only
|
2019-04-24 23:51:25 +02:00
|
|
|
# one of the payload / container keys set. Note that non-PRESIGNED container
|
|
|
|
# with PRESIGNED payload could be allowed but currently unsupported. It would
|
|
|
|
# require changing SignApex implementation.
|
2019-03-19 20:24:03 +01:00
|
|
|
if not apex_keys:
|
|
|
|
return
|
|
|
|
|
|
|
|
invalid_apexes = []
|
|
|
|
for info in input_tf_zip.infolist():
|
2021-06-12 02:03:43 +02:00
|
|
|
if not IsApexFile(info.filename):
|
2019-03-19 20:24:03 +01:00
|
|
|
continue
|
|
|
|
|
2021-06-12 02:03:43 +02:00
|
|
|
name = GetApexFilename(info.filename)
|
|
|
|
|
2021-10-26 20:58:09 +02:00
|
|
|
(payload_key, container_key, _) = apex_keys[name]
|
2019-03-19 20:24:03 +01:00
|
|
|
if ((payload_key in common.SPECIAL_CERT_STRINGS and
|
|
|
|
container_key not in common.SPECIAL_CERT_STRINGS) or
|
|
|
|
(payload_key not in common.SPECIAL_CERT_STRINGS and
|
|
|
|
container_key in common.SPECIAL_CERT_STRINGS)):
|
|
|
|
invalid_apexes.append(
|
|
|
|
"{}: payload_key {}, container_key {}".format(
|
|
|
|
name, payload_key, container_key))
|
|
|
|
|
|
|
|
assert not invalid_apexes, \
|
|
|
|
"Invalid APEX keys specified:\n {}\n".format(
|
|
|
|
"\n ".join(invalid_apexes))
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-08-14 15:49:21 +02:00
|
|
|
def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
|
2020-06-03 01:02:38 +02:00
|
|
|
is_compressed, apk_name):
|
|
|
|
unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
|
2015-03-24 03:13:21 +01:00
|
|
|
unsigned.write(data)
|
|
|
|
unsigned.flush()
|
|
|
|
|
2017-08-14 15:49:21 +02:00
|
|
|
if is_compressed:
|
|
|
|
uncompressed = tempfile.NamedTemporaryFile()
|
2017-12-24 19:37:38 +01:00
|
|
|
with gzip.open(unsigned.name, "rb") as in_file, \
|
2021-08-03 01:58:14 +02:00
|
|
|
open(uncompressed.name, "wb") as out_file:
|
2017-08-14 15:49:21 +02:00
|
|
|
shutil.copyfileobj(in_file, out_file)
|
|
|
|
|
|
|
|
# Finally, close the "unsigned" file (which is gzip compressed), and then
|
|
|
|
# replace it with the uncompressed version.
|
|
|
|
#
|
|
|
|
# TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
|
|
|
|
# we could just gzip / gunzip in-memory buffers instead.
|
|
|
|
unsigned.close()
|
|
|
|
unsigned = uncompressed
|
|
|
|
|
2020-06-03 01:02:38 +02:00
|
|
|
signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2016-01-13 19:32:47 +01:00
|
|
|
# For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
|
|
|
|
# minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
|
|
|
|
# didn't change, we don't want its signature to change due to the switch
|
|
|
|
# from SHA-1 to SHA-256.
|
|
|
|
# By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
|
|
|
|
# is 18 or higher. For pre-N builds we disable this mechanism by pretending
|
|
|
|
# that the APK's minSdkVersion is 1.
|
|
|
|
# For N+ builds, we let APK signer rely on the APK's minSdkVersion to
|
|
|
|
# determine whether to use SHA-256.
|
|
|
|
min_api_level = None
|
|
|
|
if platform_api_level > 23:
|
|
|
|
# Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
|
|
|
|
# minSdkVersion attribute
|
|
|
|
min_api_level = None
|
|
|
|
else:
|
|
|
|
# Force APK signer to use SHA-1
|
|
|
|
min_api_level = 1
|
|
|
|
|
|
|
|
common.SignFile(unsigned.name, signed.name, keyname, pw,
|
2017-12-24 19:37:38 +01:00
|
|
|
min_api_level=min_api_level,
|
|
|
|
codename_to_api_level_map=codename_to_api_level_map)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
data = None
|
2017-08-14 15:49:21 +02:00
|
|
|
if is_compressed:
|
|
|
|
# Recompress the file after it has been signed.
|
|
|
|
compressed = tempfile.NamedTemporaryFile()
|
2017-12-24 19:37:38 +01:00
|
|
|
with open(signed.name, "rb") as in_file, \
|
2021-08-03 01:58:14 +02:00
|
|
|
gzip.open(compressed.name, "wb") as out_file:
|
2017-08-14 15:49:21 +02:00
|
|
|
shutil.copyfileobj(in_file, out_file)
|
|
|
|
|
|
|
|
data = compressed.read()
|
|
|
|
compressed.close()
|
|
|
|
else:
|
|
|
|
data = signed.read()
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
unsigned.close()
|
|
|
|
signed.close()
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
2021-02-19 08:02:36 +01:00
|
|
|
|
2023-11-06 19:53:41 +01:00
|
|
|
|
2021-02-10 18:45:24 +01:00
|
|
|
def IsBuildPropFile(filename):
|
|
|
|
return filename in (
|
2021-08-03 01:58:14 +02:00
|
|
|
"SYSTEM/etc/prop.default",
|
|
|
|
"BOOT/RAMDISK/prop.default",
|
|
|
|
"RECOVERY/RAMDISK/prop.default",
|
2021-02-10 18:45:24 +01:00
|
|
|
|
2021-08-03 01:58:14 +02:00
|
|
|
"VENDOR_BOOT/RAMDISK/default.prop",
|
|
|
|
"VENDOR_BOOT/RAMDISK/prop.default",
|
2021-02-10 18:45:24 +01:00
|
|
|
|
2021-08-03 01:58:14 +02:00
|
|
|
# ROOT/default.prop is a legacy path, but may still exist for upgrading
|
|
|
|
# devices that don't support `property_overrides_split_enabled`.
|
|
|
|
"ROOT/default.prop",
|
2021-02-10 18:45:24 +01:00
|
|
|
|
2021-08-03 01:58:14 +02:00
|
|
|
# RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
|
|
|
|
# as a symlink in the current code. So it's a no-op here. Keeping the
|
|
|
|
# path here for clarity.
|
2023-01-11 06:02:02 +01:00
|
|
|
# Some build props might be stored under path
|
2023-01-29 19:51:19 +01:00
|
|
|
# VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
|
|
|
|
# default.prop can be a symbolic link to prop.default, so overwrite all
|
|
|
|
# files that ends with build.prop, default.prop or prop.default
|
2023-01-11 06:02:02 +01:00
|
|
|
"RECOVERY/RAMDISK/default.prop") or \
|
|
|
|
filename.endswith("build.prop") or \
|
2023-01-29 19:51:19 +01:00
|
|
|
filename.endswith("/default.prop") or \
|
|
|
|
filename.endswith("/prop.default")
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2021-02-19 08:02:36 +01:00
|
|
|
|
2023-11-06 19:53:41 +01:00
|
|
|
def ProcessTargetFiles(input_tf_zip: zipfile.ZipFile, output_tf_zip, misc_info,
|
2019-03-15 17:37:01 +01:00
|
|
|
apk_keys, apex_keys, key_passwords,
|
|
|
|
platform_api_level, codename_to_api_level_map,
|
2022-04-13 01:22:11 +02:00
|
|
|
compressed_extension):
|
2018-06-19 21:19:35 +02:00
|
|
|
# maxsize measures the maximum filename length, including the ones to be
|
|
|
|
# skipped.
|
2022-01-04 08:15:35 +01:00
|
|
|
try:
|
|
|
|
maxsize = max(
|
|
|
|
[len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
|
|
|
|
if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
|
|
|
|
except ValueError:
|
2024-01-24 07:10:17 +01:00
|
|
|
# Sets this to zero for targets without APK files.
|
2022-01-04 08:15:35 +01:00
|
|
|
maxsize = 0
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
for info in input_tf_zip.infolist():
|
2018-06-19 21:19:35 +02:00
|
|
|
filename = info.filename
|
|
|
|
if filename.startswith("IMAGES/"):
|
2015-03-24 03:13:21 +01:00
|
|
|
continue
|
|
|
|
|
2019-07-26 08:11:41 +02:00
|
|
|
# Skip OTA-specific images (e.g. split super images), which will be
|
|
|
|
# re-generated during signing.
|
2019-01-11 21:37:35 +01:00
|
|
|
if filename.startswith("OTA/") and filename.endswith(".img"):
|
|
|
|
continue
|
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
data = input_tf_zip.read(filename)
|
2015-03-24 03:13:21 +01:00
|
|
|
out_info = copy.copy(info)
|
2018-06-19 21:19:35 +02:00
|
|
|
(is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
|
|
|
|
filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
|
|
|
|
|
|
|
|
if is_apk and should_be_skipped:
|
|
|
|
# Copy skipped APKs verbatim.
|
|
|
|
print(
|
|
|
|
"NOT signing: %s\n"
|
|
|
|
" (skipped due to matching prefix)" % (filename,))
|
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2015-07-22 21:33:18 +02:00
|
|
|
# Sign APKs.
|
2018-06-19 21:19:35 +02:00
|
|
|
elif is_apk:
|
2018-06-19 21:19:35 +02:00
|
|
|
name = os.path.basename(filename)
|
2017-08-14 15:49:21 +02:00
|
|
|
if is_compressed:
|
|
|
|
name = name[:-len(compressed_extension)]
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
key = apk_keys[name]
|
2015-03-24 03:13:21 +01:00
|
|
|
if key not in common.SPECIAL_CERT_STRINGS:
|
2017-12-24 19:37:38 +01:00
|
|
|
print(" signing: %-*s (%s)" % (maxsize, name, key))
|
2016-01-13 19:32:47 +01:00
|
|
|
signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
|
2020-06-03 01:02:38 +02:00
|
|
|
codename_to_api_level_map, is_compressed, name)
|
2015-04-01 20:21:55 +02:00
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, signed_data)
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
|
|
|
# an APK we're not supposed to sign.
|
2018-06-19 21:19:35 +02:00
|
|
|
print(
|
|
|
|
"NOT signing: %s\n"
|
|
|
|
" (skipped due to special cert string)" % (name,))
|
2015-04-01 20:21:55 +02:00
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2021-02-19 08:02:36 +01:00
|
|
|
# Sign bundled APEX files on all partitions
|
2021-06-12 02:03:43 +02:00
|
|
|
elif IsApexFile(filename):
|
|
|
|
name = GetApexFilename(filename)
|
|
|
|
|
2021-10-26 20:58:09 +02:00
|
|
|
payload_key, container_key, sign_tool = apex_keys[name]
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2019-03-19 20:24:03 +01:00
|
|
|
# We've asserted not having a case with only one of them PRESIGNED.
|
|
|
|
if (payload_key not in common.SPECIAL_CERT_STRINGS and
|
2021-08-03 01:58:14 +02:00
|
|
|
container_key not in common.SPECIAL_CERT_STRINGS):
|
2019-03-19 20:24:03 +01:00
|
|
|
print(" signing: %-*s container (%s)" % (
|
|
|
|
maxsize, name, container_key))
|
|
|
|
print(" : %-*s payload (%s)" % (
|
|
|
|
maxsize, name, payload_key))
|
|
|
|
|
2019-05-10 01:54:15 +02:00
|
|
|
signed_apex = apex_utils.SignApex(
|
2019-06-26 20:58:22 +02:00
|
|
|
misc_info['avb_avbtool'],
|
2019-03-19 20:24:03 +01:00
|
|
|
data,
|
|
|
|
payload_key,
|
|
|
|
container_key,
|
2020-10-05 16:04:59 +02:00
|
|
|
key_passwords,
|
2020-01-23 19:47:54 +01:00
|
|
|
apk_keys,
|
2019-03-19 20:24:03 +01:00
|
|
|
codename_to_api_level_map,
|
2021-08-03 01:58:14 +02:00
|
|
|
no_hashtree=None, # Let apex_util determine if hash tree is needed
|
2021-10-26 20:58:09 +02:00
|
|
|
signing_args=OPTIONS.avb_extra_args.get('apex'),
|
2022-04-13 01:22:11 +02:00
|
|
|
sign_tool=sign_tool)
|
2019-03-19 20:24:03 +01:00
|
|
|
common.ZipWrite(output_tf_zip, signed_apex, filename)
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2019-03-19 20:24:03 +01:00
|
|
|
else:
|
|
|
|
print(
|
|
|
|
"NOT signing: %s\n"
|
|
|
|
" (skipped due to special cert string)" % (name,))
|
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2023-11-06 19:53:41 +01:00
|
|
|
elif filename.endswith(".zip") and IsEntryOtaPackage(input_tf_zip, filename):
|
|
|
|
logger.info("Re-signing OTA package {}".format(filename))
|
|
|
|
with tempfile.NamedTemporaryFile() as input_ota, tempfile.NamedTemporaryFile() as output_ota:
|
|
|
|
with input_tf_zip.open(filename, "r") as in_fp:
|
|
|
|
shutil.copyfileobj(in_fp, input_ota)
|
|
|
|
input_ota.flush()
|
|
|
|
SignOtaPackage(input_ota.name, output_ota.name)
|
|
|
|
common.ZipWrite(output_tf_zip, output_ota.name, filename,
|
|
|
|
compress_type=zipfile.ZIP_STORED)
|
2016-06-16 23:41:24 +02:00
|
|
|
# System properties.
|
2021-02-10 18:45:24 +01:00
|
|
|
elif IsBuildPropFile(filename):
|
2018-06-19 21:19:35 +02:00
|
|
|
print("Rewriting %s:" % (filename,))
|
2017-05-01 15:56:26 +02:00
|
|
|
if stat.S_ISLNK(info.external_attr >> 16):
|
|
|
|
new_data = data
|
|
|
|
else:
|
2019-06-25 00:33:41 +02:00
|
|
|
new_data = RewriteProps(data.decode())
|
2015-04-01 20:21:55 +02:00
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, new_data)
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2017-12-05 02:16:36 +01:00
|
|
|
# Replace the certs in *mac_permissions.xml (there could be multiple, such
|
2021-12-21 07:57:03 +01:00
|
|
|
# as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
|
2018-06-19 21:19:35 +02:00
|
|
|
elif filename.endswith("mac_permissions.xml"):
|
|
|
|
print("Rewriting %s with new keys." % (filename,))
|
2019-06-25 00:33:41 +02:00
|
|
|
new_data = ReplaceCerts(data.decode())
|
2015-04-01 20:21:55 +02:00
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, new_data)
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2017-05-23 23:51:02 +02:00
|
|
|
# Ask add_img_to_target_files to rebuild the recovery patch if needed.
|
2018-06-19 21:19:35 +02:00
|
|
|
elif filename in ("SYSTEM/recovery-from-boot.p",
|
2020-01-03 19:16:32 +01:00
|
|
|
"VENDOR/recovery-from-boot.p",
|
|
|
|
|
2018-06-19 21:19:35 +02:00
|
|
|
"SYSTEM/etc/recovery.img",
|
2020-01-03 19:16:32 +01:00
|
|
|
"VENDOR/etc/recovery.img",
|
|
|
|
|
|
|
|
"SYSTEM/bin/install-recovery.sh",
|
|
|
|
"VENDOR/bin/install-recovery.sh"):
|
2017-05-23 23:51:02 +02:00
|
|
|
OPTIONS.rebuild_recovery = True
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2018-10-19 23:34:15 +02:00
|
|
|
# Don't copy OTA certs if we're replacing them.
|
2019-10-16 03:06:25 +02:00
|
|
|
# Replacement of update-payload-key.pub.pem was removed in b/116660991.
|
2021-02-12 01:10:44 +01:00
|
|
|
elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
|
2015-03-24 03:13:21 +01:00
|
|
|
pass
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2017-06-05 20:55:16 +02:00
|
|
|
# Skip META/misc_info.txt since we will write back the new values later.
|
2018-06-19 21:19:35 +02:00
|
|
|
elif filename == "META/misc_info.txt":
|
2015-03-24 03:13:21 +01:00
|
|
|
pass
|
2016-06-18 02:01:22 +02:00
|
|
|
|
2020-02-21 10:48:18 +01:00
|
|
|
elif (OPTIONS.remove_avb_public_keys and
|
|
|
|
(filename.startswith("BOOT/RAMDISK/avb/") or
|
|
|
|
filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
|
2020-06-23 21:06:58 +02:00
|
|
|
matched_removal = False
|
|
|
|
for key_to_remove in OPTIONS.remove_avb_public_keys:
|
|
|
|
if filename.endswith(key_to_remove):
|
|
|
|
matched_removal = True
|
|
|
|
print("Removing AVB public key from ramdisk: %s" % filename)
|
|
|
|
break
|
|
|
|
if not matched_removal:
|
|
|
|
# Copy it verbatim if we don't want to remove it.
|
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2021-05-04 06:18:56 +02:00
|
|
|
# Skip the vbmeta digest as we will recalculate it.
|
|
|
|
elif filename == "META/vbmeta_digest.txt":
|
|
|
|
pass
|
|
|
|
|
2016-08-12 03:04:27 +02:00
|
|
|
# Skip the care_map as we will regenerate the system/vendor images.
|
2020-06-23 21:06:58 +02:00
|
|
|
elif filename in ["META/care_map.pb", "META/care_map.txt"]:
|
2016-08-12 03:04:27 +02:00
|
|
|
pass
|
|
|
|
|
2021-01-19 21:30:46 +01:00
|
|
|
# Skip apex_info.pb because we sign/modify apexes
|
|
|
|
elif filename == "META/apex_info.pb":
|
|
|
|
pass
|
|
|
|
|
2019-02-27 03:15:51 +01:00
|
|
|
# Updates system_other.avbpubkey in /product/etc/.
|
|
|
|
elif filename in (
|
|
|
|
"PRODUCT/etc/security/avb/system_other.avbpubkey",
|
2021-10-13 11:39:33 +02:00
|
|
|
"SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
|
2019-02-27 03:15:51 +01:00
|
|
|
# Only update system_other's public key, if the corresponding signing
|
|
|
|
# key is specified via --avb_system_other_key.
|
|
|
|
signing_key = OPTIONS.avb_keys.get("system_other")
|
|
|
|
if signing_key:
|
2019-06-26 20:58:22 +02:00
|
|
|
public_key = common.ExtractAvbPublicKey(
|
|
|
|
misc_info['avb_avbtool'], signing_key)
|
2019-02-27 03:15:51 +01:00
|
|
|
print(" Rewriting AVB public key of system_other in /product")
|
|
|
|
common.ZipWrite(output_tf_zip, public_key, filename)
|
|
|
|
|
2022-02-17 23:34:27 +01:00
|
|
|
# Updates pvmfw embedded public key with the virt APEX payload key.
|
|
|
|
elif filename == "PREBUILT_IMAGES/pvmfw.img":
|
|
|
|
# Find the name of the virt APEX in the target files.
|
|
|
|
namelist = input_tf_zip.namelist()
|
|
|
|
apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
|
|
|
|
virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
|
|
|
|
virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
|
|
|
|
if not virt_apex:
|
|
|
|
print("Removing %s from ramdisk: virt APEX not found" % filename)
|
|
|
|
else:
|
|
|
|
print("Replacing %s embedded key with %s key" % (filename, virt_apex))
|
|
|
|
# Get the current and new embedded keys.
|
|
|
|
payload_key, container_key, sign_tool = apex_keys[virt_apex]
|
|
|
|
new_pubkey_path = common.ExtractAvbPublicKey(
|
|
|
|
misc_info['avb_avbtool'], payload_key)
|
|
|
|
with open(new_pubkey_path, 'rb') as f:
|
|
|
|
new_pubkey = f.read()
|
|
|
|
pubkey_info = copy.copy(
|
|
|
|
input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
|
|
|
|
old_pubkey = input_tf_zip.read(pubkey_info.filename)
|
|
|
|
# Validate the keys and image.
|
|
|
|
if len(old_pubkey) != len(new_pubkey):
|
|
|
|
raise common.ExternalError("pvmfw embedded public key size mismatch")
|
|
|
|
pos = data.find(old_pubkey)
|
|
|
|
if pos == -1:
|
|
|
|
raise common.ExternalError("pvmfw embedded public key not found")
|
|
|
|
# Replace the key and copy new files.
|
|
|
|
new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
|
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, new_data)
|
|
|
|
common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
|
|
|
|
elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
|
|
|
|
pass
|
|
|
|
|
2019-04-23 06:28:44 +02:00
|
|
|
# Should NOT sign boot-debug.img.
|
|
|
|
elif filename in (
|
|
|
|
"BOOT/RAMDISK/force_debuggable",
|
2021-10-13 11:39:33 +02:00
|
|
|
"BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
|
2019-04-23 06:28:44 +02:00
|
|
|
raise common.ExternalError("debuggable boot.img cannot be signed")
|
|
|
|
|
2021-10-13 11:39:33 +02:00
|
|
|
# Should NOT sign userdebug sepolicy file.
|
|
|
|
elif filename in (
|
|
|
|
"SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
|
|
|
|
"SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
|
|
|
|
if not OPTIONS.allow_gsi_debug_sepolicy:
|
|
|
|
raise common.ExternalError("debug sepolicy shouldn't be included")
|
|
|
|
else:
|
|
|
|
# Copy it verbatim if we allow the file to exist.
|
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
|
|
|
|
2024-02-22 07:34:08 +01:00
|
|
|
# Sign microdroid_vendor.img.
|
|
|
|
elif filename == "VENDOR/etc/avf/microdroid/microdroid_vendor.img":
|
|
|
|
vendor_key = OPTIONS.avb_keys.get("vendor")
|
|
|
|
vendor_algorithm = OPTIONS.avb_algorithms.get("vendor")
|
|
|
|
with tempfile.NamedTemporaryFile() as image:
|
|
|
|
image.write(data)
|
|
|
|
image.flush()
|
|
|
|
ReplaceKeyInAvbHashtreeFooter(image, vendor_key, vendor_algorithm,
|
|
|
|
misc_info)
|
|
|
|
common.ZipWrite(output_tf_zip, image.name, filename)
|
2016-06-16 23:41:24 +02:00
|
|
|
# A non-APK file; copy it verbatim.
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
2015-04-01 20:21:55 +02:00
|
|
|
common.ZipWriteStr(output_tf_zip, out_info, data)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
if OPTIONS.replace_ota_keys:
|
2017-05-23 23:51:02 +02:00
|
|
|
ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-06-20 00:48:02 +02:00
|
|
|
# Replace the AVB signing keys, if any.
|
|
|
|
ReplaceAvbSigningKeys(misc_info)
|
|
|
|
|
2019-10-09 09:04:28 +02:00
|
|
|
# Rewrite the props in AVB signing args.
|
|
|
|
if misc_info.get('avb_enable') == 'true':
|
|
|
|
RewriteAvbProps(misc_info)
|
|
|
|
|
2017-06-05 20:55:16 +02:00
|
|
|
# Write back misc_info with the latest values.
|
|
|
|
ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
|
|
|
|
|
2024-03-11 06:41:22 +01:00
|
|
|
# Parse string output of `avbtool info_image`.
|
|
|
|
def ParseAvbInfo(info_raw):
|
|
|
|
# line_matcher is for parsing each output line of `avbtool info_image`.
|
|
|
|
# example string input: " Hash Algorithm: sha1"
|
|
|
|
# example matched input: (" ", "Hash Algorithm", "sha1")
|
|
|
|
line_matcher = re.compile(r'^(\s*)([^:]+):\s*(.*)$')
|
|
|
|
# prop_matcher is for parsing value part of 'Prop' in `avbtool info_image`.
|
|
|
|
# example string input: "example_prop_key -> 'example_prop_value'"
|
|
|
|
# example matched output: ("example_prop_key", "example_prop_value")
|
|
|
|
prop_matcher = re.compile(r"(.+)\s->\s'(.+)'")
|
|
|
|
info = {}
|
|
|
|
indent_stack = [[-1, info]]
|
|
|
|
for line_info_raw in info_raw.split('\n'):
|
|
|
|
# Parse the line
|
|
|
|
line_info_parsed = line_matcher.match(line_info_raw)
|
|
|
|
if not line_info_parsed:
|
|
|
|
continue
|
|
|
|
indent = len(line_info_parsed.group(1))
|
|
|
|
key = line_info_parsed.group(2).strip()
|
|
|
|
value = line_info_parsed.group(3).strip()
|
|
|
|
|
|
|
|
# Pop indentation stack
|
|
|
|
while indent <= indent_stack[-1][0]:
|
|
|
|
del indent_stack[-1]
|
|
|
|
|
|
|
|
# Insert information into 'info'.
|
|
|
|
cur_info = indent_stack[-1][1]
|
|
|
|
if value == "":
|
|
|
|
if key == "Descriptors":
|
|
|
|
empty_list = []
|
|
|
|
cur_info[key] = empty_list
|
|
|
|
indent_stack.append([indent, empty_list])
|
|
|
|
else:
|
|
|
|
empty_dict = {}
|
|
|
|
cur_info.append({key:empty_dict})
|
|
|
|
indent_stack.append([indent, empty_dict])
|
|
|
|
elif key == "Prop":
|
|
|
|
prop_parsed = prop_matcher.match(value)
|
|
|
|
if not prop_parsed:
|
|
|
|
raise ValueError(
|
|
|
|
"Failed to parse prop while getting avb information.")
|
|
|
|
cur_info.append({key:{prop_parsed.group(1):prop_parsed.group(2)}})
|
|
|
|
else:
|
|
|
|
cur_info[key] = value
|
|
|
|
return info
|
|
|
|
|
2024-02-22 07:34:08 +01:00
|
|
|
def ReplaceKeyInAvbHashtreeFooter(image, new_key, new_algorithm, misc_info):
|
|
|
|
# Get avb information about the image by parsing avbtool info_image.
|
|
|
|
def GetAvbInfo(avbtool, image_name):
|
|
|
|
# Get information with raw string by `avbtool info_image`.
|
|
|
|
info_raw = common.RunAndCheckOutput([
|
|
|
|
avbtool, 'info_image',
|
|
|
|
'--image', image_name
|
|
|
|
])
|
2024-03-11 06:41:22 +01:00
|
|
|
return ParseAvbInfo(info_raw)
|
2024-02-22 07:34:08 +01:00
|
|
|
|
|
|
|
# Get hashtree descriptor from info
|
|
|
|
def GetAvbHashtreeDescriptor(avb_info):
|
|
|
|
hashtree_descriptors = tuple(filter(lambda x: "Hashtree descriptor" in x,
|
|
|
|
info.get('Descriptors')))
|
|
|
|
if len(hashtree_descriptors) != 1:
|
|
|
|
raise ValueError("The number of hashtree descriptor is not 1.")
|
|
|
|
return hashtree_descriptors[0]["Hashtree descriptor"]
|
|
|
|
|
|
|
|
# Get avb info
|
|
|
|
avbtool = misc_info['avb_avbtool']
|
|
|
|
info = GetAvbInfo(avbtool, image.name)
|
|
|
|
hashtree_descriptor = GetAvbHashtreeDescriptor(info)
|
|
|
|
|
|
|
|
# Generate command
|
|
|
|
cmd = [avbtool, 'add_hashtree_footer',
|
|
|
|
'--key', new_key,
|
|
|
|
'--algorithm', new_algorithm,
|
|
|
|
'--partition_name', hashtree_descriptor.get("Partition Name"),
|
|
|
|
'--partition_size', info.get("Image size").removesuffix(" bytes"),
|
|
|
|
'--hash_algorithm', hashtree_descriptor.get("Hash Algorithm"),
|
|
|
|
'--salt', hashtree_descriptor.get("Salt"),
|
|
|
|
'--do_not_generate_fec',
|
|
|
|
'--image', image.name
|
|
|
|
]
|
|
|
|
|
|
|
|
# Append properties into command
|
|
|
|
props = map(lambda x: x.get("Prop"), filter(lambda x: "Prop" in x,
|
|
|
|
info.get('Descriptors')))
|
|
|
|
for prop_wrapped in props:
|
|
|
|
prop = tuple(prop_wrapped.items())
|
|
|
|
if len(prop) != 1:
|
|
|
|
raise ValueError("The number of property is not 1.")
|
|
|
|
cmd.append('--prop')
|
|
|
|
cmd.append(prop[0][0] + ':' + prop[0][1])
|
|
|
|
|
|
|
|
# Replace Hashtree Footer with new key
|
|
|
|
common.RunAndCheckOutput(cmd)
|
|
|
|
|
|
|
|
# Check root digest is not changed
|
|
|
|
new_info = GetAvbInfo(avbtool, image.name)
|
|
|
|
new_hashtree_descriptor = GetAvbHashtreeDescriptor(info)
|
|
|
|
root_digest = hashtree_descriptor.get("Root Digest")
|
|
|
|
new_root_digest = new_hashtree_descriptor.get("Root Digest")
|
|
|
|
assert root_digest == new_root_digest, \
|
|
|
|
("Root digest in hashtree descriptor shouldn't be changed. Old: {}, New: "
|
|
|
|
"{}").format(root_digest, new_root_digest)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
def ReplaceCerts(data):
|
2017-12-05 02:16:36 +01:00
|
|
|
"""Replaces all the occurences of X.509 certs with the new ones.
|
|
|
|
|
|
|
|
The mapping info is read from OPTIONS.key_map. Non-existent certificate will
|
|
|
|
be skipped. After the replacement, it additionally checks for duplicate
|
|
|
|
entries, which would otherwise fail the policy loading code in
|
|
|
|
frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
data: Input string that contains a set of X.509 certs.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A string after the replacement.
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
AssertionError: On finding duplicate entries.
|
|
|
|
"""
|
2019-06-25 00:33:41 +02:00
|
|
|
for old, new in OPTIONS.key_map.items():
|
2017-12-05 02:16:36 +01:00
|
|
|
if OPTIONS.verbose:
|
|
|
|
print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
try:
|
2017-12-05 02:16:36 +01:00
|
|
|
with open(old + ".x509.pem") as old_fp:
|
|
|
|
old_cert16 = base64.b16encode(
|
2019-06-25 00:33:41 +02:00
|
|
|
common.ParseCertificate(old_fp.read())).decode().lower()
|
2017-12-05 02:16:36 +01:00
|
|
|
with open(new + ".x509.pem") as new_fp:
|
|
|
|
new_cert16 = base64.b16encode(
|
2019-06-25 00:33:41 +02:00
|
|
|
common.ParseCertificate(new_fp.read())).decode().lower()
|
2015-03-24 03:13:21 +01:00
|
|
|
except IOError as e:
|
2017-12-05 02:16:36 +01:00
|
|
|
if OPTIONS.verbose or e.errno != errno.ENOENT:
|
|
|
|
print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
|
|
|
|
"%s.x509.pem." % (e.filename, e.strerror, old, new))
|
|
|
|
continue
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-12-05 02:16:36 +01:00
|
|
|
# Only match entire certs.
|
|
|
|
pattern = "\\b" + old_cert16 + "\\b"
|
|
|
|
(data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
|
|
|
|
|
|
|
|
if OPTIONS.verbose:
|
|
|
|
print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
|
|
|
|
num, old, new))
|
|
|
|
|
|
|
|
# Verify that there're no duplicate entries after the replacement. Note that
|
|
|
|
# it's only checking entries with global seinfo at the moment (i.e. ignoring
|
|
|
|
# the ones with inner packages). (Bug: 69479366)
|
|
|
|
root = ElementTree.fromstring(data)
|
2021-08-03 01:58:14 +02:00
|
|
|
signatures = [signer.attrib['signature']
|
|
|
|
for signer in root.findall('signer')]
|
2017-12-05 02:16:36 +01:00
|
|
|
assert len(signatures) == len(set(signatures)), \
|
|
|
|
"Found duplicate entries after cert replacement: {}".format(data)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
def EditTags(tags):
|
2017-12-08 23:42:16 +01:00
|
|
|
"""Applies the edits to the tag string as specified in OPTIONS.tag_changes.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
tags: The input string that contains comma-separated tags.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The updated tags (comma-separated and sorted).
|
|
|
|
"""
|
2015-03-24 03:13:21 +01:00
|
|
|
tags = set(tags.split(","))
|
|
|
|
for ch in OPTIONS.tag_changes:
|
|
|
|
if ch[0] == "-":
|
|
|
|
tags.discard(ch[1:])
|
|
|
|
elif ch[0] == "+":
|
|
|
|
tags.add(ch[1:])
|
|
|
|
return ",".join(sorted(tags))
|
|
|
|
|
|
|
|
|
2017-12-08 23:42:16 +01:00
|
|
|
def RewriteProps(data):
|
|
|
|
"""Rewrites the system properties in the given string.
|
|
|
|
|
|
|
|
Each property is expected in 'key=value' format. The properties that contain
|
|
|
|
build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
|
|
|
|
EditTags().
|
|
|
|
|
|
|
|
Args:
|
|
|
|
data: Input string, separated by newlines.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The string with modified properties.
|
|
|
|
"""
|
2015-03-24 03:13:21 +01:00
|
|
|
output = []
|
|
|
|
for line in data.split("\n"):
|
|
|
|
line = line.strip()
|
|
|
|
original_line = line
|
|
|
|
if line and line[0] != '#' and "=" in line:
|
|
|
|
key, value = line.split("=", 1)
|
2019-05-01 23:09:30 +02:00
|
|
|
if (key.startswith("ro.") and
|
2021-08-03 01:58:14 +02:00
|
|
|
key.endswith((".build.fingerprint", ".build.thumbprint"))):
|
2015-03-24 03:13:21 +01:00
|
|
|
pieces = value.split("/")
|
|
|
|
pieces[-1] = EditTags(pieces[-1])
|
|
|
|
value = "/".join(pieces)
|
2015-09-12 00:27:56 +02:00
|
|
|
elif key == "ro.bootimage.build.fingerprint":
|
|
|
|
pieces = value.split("/")
|
|
|
|
pieces[-1] = EditTags(pieces[-1])
|
|
|
|
value = "/".join(pieces)
|
2015-03-24 03:13:21 +01:00
|
|
|
elif key == "ro.build.description":
|
2022-06-21 04:36:12 +02:00
|
|
|
pieces = value.split()
|
2021-03-23 10:58:22 +01:00
|
|
|
assert pieces[-1].endswith("-keys")
|
2015-03-24 03:13:21 +01:00
|
|
|
pieces[-1] = EditTags(pieces[-1])
|
|
|
|
value = " ".join(pieces)
|
2019-05-01 23:09:30 +02:00
|
|
|
elif key.startswith("ro.") and key.endswith(".build.tags"):
|
2015-03-24 03:13:21 +01:00
|
|
|
value = EditTags(value)
|
|
|
|
elif key == "ro.build.display.id":
|
|
|
|
# change, eg, "JWR66N dev-keys" to "JWR66N"
|
|
|
|
value = value.split()
|
|
|
|
if len(value) > 1 and value[-1].endswith("-keys"):
|
|
|
|
value.pop()
|
|
|
|
value = " ".join(value)
|
|
|
|
line = key + "=" + value
|
|
|
|
if line != original_line:
|
2017-12-24 19:37:38 +01:00
|
|
|
print(" replace: ", original_line)
|
|
|
|
print(" with: ", line)
|
2015-03-24 03:13:21 +01:00
|
|
|
output.append(line)
|
|
|
|
return "\n".join(output) + "\n"
|
|
|
|
|
|
|
|
|
2018-10-19 23:34:15 +02:00
|
|
|
def WriteOtacerts(output_zip, filename, keys):
|
|
|
|
"""Constructs a zipfile from given keys; and writes it to output_zip.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
output_zip: The output target_files zip.
|
|
|
|
filename: The archive name in the output zip.
|
|
|
|
keys: A list of public keys to use during OTA package verification.
|
|
|
|
"""
|
2019-07-25 08:31:19 +02:00
|
|
|
temp_file = io.BytesIO()
|
2020-09-22 22:15:57 +02:00
|
|
|
certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
|
2018-10-19 23:34:15 +02:00
|
|
|
for k in keys:
|
|
|
|
common.ZipWrite(certs_zip, k)
|
2023-04-14 23:32:54 +02:00
|
|
|
common.ZipClose(certs_zip)
|
2018-10-19 23:34:15 +02:00
|
|
|
common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
|
|
|
|
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
|
|
|
|
try:
|
|
|
|
keylist = input_tf_zip.read("META/otakeys.txt").split()
|
|
|
|
except KeyError:
|
|
|
|
raise common.ExternalError("can't read META/otakeys.txt from input")
|
|
|
|
|
2021-12-29 09:29:05 +01:00
|
|
|
extra_ota_keys_info = misc_info.get("extra_ota_keys")
|
|
|
|
if extra_ota_keys_info:
|
|
|
|
extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
|
|
|
|
for k in extra_ota_keys_info.split()]
|
|
|
|
print("extra ota key(s): " + ", ".join(extra_ota_keys))
|
|
|
|
else:
|
|
|
|
extra_ota_keys = []
|
|
|
|
for k in extra_ota_keys:
|
|
|
|
if not os.path.isfile(k):
|
|
|
|
raise common.ExternalError(k + " does not exist or is not a file")
|
|
|
|
|
|
|
|
extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
|
|
|
|
if extra_recovery_keys_info:
|
2015-03-24 03:13:21 +01:00
|
|
|
extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
|
2021-12-29 09:29:05 +01:00
|
|
|
for k in extra_recovery_keys_info.split()]
|
|
|
|
print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
|
|
|
extra_recovery_keys = []
|
2021-12-29 09:29:05 +01:00
|
|
|
for k in extra_recovery_keys:
|
|
|
|
if not os.path.isfile(k):
|
|
|
|
raise common.ExternalError(k + " does not exist or is not a file")
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
mapped_keys = []
|
|
|
|
for k in keylist:
|
|
|
|
m = re.match(r"^(.*)\.x509\.pem$", k)
|
|
|
|
if not m:
|
|
|
|
raise common.ExternalError(
|
|
|
|
"can't parse \"%s\" from META/otakeys.txt" % (k,))
|
|
|
|
k = m.group(1)
|
|
|
|
mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
|
|
|
|
|
|
|
|
if mapped_keys:
|
2017-12-24 19:37:38 +01:00
|
|
|
print("using:\n ", "\n ".join(mapped_keys))
|
|
|
|
print("for OTA package verification")
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
|
|
|
devkey = misc_info.get("default_system_dev_certificate",
|
2019-04-10 06:35:37 +02:00
|
|
|
"build/make/target/product/security/testkey")
|
2017-11-09 19:10:10 +01:00
|
|
|
mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
|
|
|
|
if mapped_devkey != devkey:
|
|
|
|
misc_info["default_system_dev_certificate"] = mapped_devkey
|
|
|
|
mapped_keys.append(mapped_devkey + ".x509.pem")
|
2016-06-16 23:41:24 +02:00
|
|
|
print("META/otakeys.txt has no keys; using %s for OTA package"
|
|
|
|
" verification." % (mapped_keys[0],))
|
2021-12-29 09:29:05 +01:00
|
|
|
for k in mapped_keys:
|
|
|
|
if not os.path.isfile(k):
|
|
|
|
raise common.ExternalError(k + " does not exist or is not a file")
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2021-02-12 01:10:44 +01:00
|
|
|
otacerts = [info
|
|
|
|
for info in input_tf_zip.infolist()
|
|
|
|
if info.filename.endswith("/otacerts.zip")]
|
|
|
|
for info in otacerts:
|
2021-12-29 09:29:05 +01:00
|
|
|
if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
|
|
|
|
extra_keys = extra_recovery_keys
|
|
|
|
else:
|
|
|
|
extra_keys = extra_ota_keys
|
|
|
|
print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
|
|
|
|
WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2016-06-16 23:41:24 +02:00
|
|
|
|
2017-06-05 20:55:16 +02:00
|
|
|
def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
|
|
|
|
"""Replaces META/misc_info.txt.
|
|
|
|
|
|
|
|
Only writes back the ones in the original META/misc_info.txt. Because the
|
|
|
|
current in-memory dict contains additional items computed at runtime.
|
|
|
|
"""
|
|
|
|
misc_info_old = common.LoadDictionaryFromLines(
|
2019-06-25 00:33:41 +02:00
|
|
|
input_zip.read('META/misc_info.txt').decode().split('\n'))
|
2017-06-05 20:55:16 +02:00
|
|
|
items = []
|
|
|
|
for key in sorted(misc_info):
|
|
|
|
if key in misc_info_old:
|
|
|
|
items.append('%s=%s' % (key, misc_info[key]))
|
|
|
|
common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
|
2016-06-17 04:58:44 +02:00
|
|
|
|
2016-06-18 02:01:22 +02:00
|
|
|
|
2017-06-20 00:48:02 +02:00
|
|
|
def ReplaceAvbSigningKeys(misc_info):
|
|
|
|
"""Replaces the AVB signing keys."""
|
|
|
|
|
|
|
|
def ReplaceAvbPartitionSigningKey(partition):
|
|
|
|
key = OPTIONS.avb_keys.get(partition)
|
|
|
|
if not key:
|
|
|
|
return
|
|
|
|
|
|
|
|
algorithm = OPTIONS.avb_algorithms.get(partition)
|
|
|
|
assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
|
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
print('Replacing AVB signing key for %s with "%s" (%s)' % (
|
|
|
|
partition, key, algorithm))
|
2017-06-20 00:48:02 +02:00
|
|
|
misc_info['avb_' + partition + '_algorithm'] = algorithm
|
|
|
|
misc_info['avb_' + partition + '_key_path'] = key
|
|
|
|
|
|
|
|
extra_args = OPTIONS.avb_extra_args.get(partition)
|
|
|
|
if extra_args:
|
2017-12-24 19:37:38 +01:00
|
|
|
print('Setting extra AVB signing args for %s to "%s"' % (
|
|
|
|
partition, extra_args))
|
2020-06-23 21:06:58 +02:00
|
|
|
args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
|
|
|
|
partition,
|
|
|
|
# custom partition
|
|
|
|
"avb_{}_add_hashtree_footer_args".format(partition))
|
2017-06-20 00:48:02 +02:00
|
|
|
misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
|
|
|
|
|
|
|
|
for partition in AVB_FOOTER_ARGS_BY_PARTITION:
|
|
|
|
ReplaceAvbPartitionSigningKey(partition)
|
|
|
|
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
for custom_partition in misc_info.get(
|
2021-08-03 01:58:14 +02:00
|
|
|
"avb_custom_images_partition_list", "").strip().split():
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
ReplaceAvbPartitionSigningKey(custom_partition)
|
|
|
|
|
2017-06-20 00:48:02 +02:00
|
|
|
|
2019-10-09 09:04:28 +02:00
|
|
|
def RewriteAvbProps(misc_info):
|
|
|
|
"""Rewrites the props in AVB signing args."""
|
|
|
|
for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
|
|
|
|
args = misc_info.get(args_key)
|
|
|
|
if not args:
|
|
|
|
continue
|
|
|
|
|
|
|
|
tokens = []
|
|
|
|
changed = False
|
2022-06-21 04:36:12 +02:00
|
|
|
for token in args.split():
|
2019-10-09 09:04:28 +02:00
|
|
|
fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
|
|
|
|
if not token.startswith(fingerprint_key):
|
|
|
|
tokens.append(token)
|
|
|
|
continue
|
|
|
|
prefix, tag = token.rsplit('/', 1)
|
|
|
|
tokens.append('{}/{}'.format(prefix, EditTags(tag)))
|
|
|
|
changed = True
|
|
|
|
|
|
|
|
if changed:
|
|
|
|
result = ' '.join(tokens)
|
|
|
|
print('Rewriting AVB prop for {}:\n'.format(partition))
|
|
|
|
print(' replace: {}'.format(args))
|
|
|
|
print(' with: {}'.format(result))
|
|
|
|
misc_info[args_key] = result
|
|
|
|
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
def BuildKeyMap(misc_info, key_mapping_options):
|
|
|
|
for s, d in key_mapping_options:
|
|
|
|
if s is None: # -d option
|
|
|
|
devkey = misc_info.get("default_system_dev_certificate",
|
2019-04-10 06:35:37 +02:00
|
|
|
"build/make/target/product/security/testkey")
|
2015-03-24 03:13:21 +01:00
|
|
|
devkeydir = os.path.dirname(devkey)
|
|
|
|
|
|
|
|
OPTIONS.key_map.update({
|
|
|
|
devkeydir + "/testkey": d + "/releasekey",
|
|
|
|
devkeydir + "/devkey": d + "/releasekey",
|
|
|
|
devkeydir + "/media": d + "/media",
|
|
|
|
devkeydir + "/shared": d + "/shared",
|
|
|
|
devkeydir + "/platform": d + "/platform",
|
2019-12-10 11:58:54 +01:00
|
|
|
devkeydir + "/networkstack": d + "/networkstack",
|
2024-01-10 08:12:39 +01:00
|
|
|
devkeydir + "/sdk_sandbox": d + "/sdk_sandbox",
|
2021-08-03 01:58:14 +02:00
|
|
|
})
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
|
|
|
OPTIONS.key_map[s] = d
|
|
|
|
|
|
|
|
|
2016-01-13 19:32:47 +01:00
|
|
|
def GetApiLevelAndCodename(input_tf_zip):
|
2019-06-25 00:33:41 +02:00
|
|
|
data = input_tf_zip.read("SYSTEM/build.prop").decode()
|
2016-01-13 19:32:47 +01:00
|
|
|
api_level = None
|
|
|
|
codename = None
|
|
|
|
for line in data.split("\n"):
|
|
|
|
line = line.strip()
|
|
|
|
if line and line[0] != '#' and "=" in line:
|
|
|
|
key, value = line.split("=", 1)
|
|
|
|
key = key.strip()
|
|
|
|
if key == "ro.build.version.sdk":
|
|
|
|
api_level = int(value.strip())
|
|
|
|
elif key == "ro.build.version.codename":
|
|
|
|
codename = value.strip()
|
|
|
|
|
|
|
|
if api_level is None:
|
|
|
|
raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
|
|
|
|
if codename is None:
|
|
|
|
raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
|
|
|
|
|
|
|
|
return (api_level, codename)
|
|
|
|
|
|
|
|
|
|
|
|
def GetCodenameToApiLevelMap(input_tf_zip):
|
2019-06-25 00:33:41 +02:00
|
|
|
data = input_tf_zip.read("SYSTEM/build.prop").decode()
|
2016-01-13 19:32:47 +01:00
|
|
|
api_level = None
|
|
|
|
codenames = None
|
|
|
|
for line in data.split("\n"):
|
|
|
|
line = line.strip()
|
|
|
|
if line and line[0] != '#' and "=" in line:
|
|
|
|
key, value = line.split("=", 1)
|
|
|
|
key = key.strip()
|
|
|
|
if key == "ro.build.version.sdk":
|
|
|
|
api_level = int(value.strip())
|
|
|
|
elif key == "ro.build.version.all_codenames":
|
|
|
|
codenames = value.strip().split(",")
|
|
|
|
|
|
|
|
if api_level is None:
|
|
|
|
raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
|
|
|
|
if codenames is None:
|
|
|
|
raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
|
|
|
|
|
2019-06-25 00:33:41 +02:00
|
|
|
result = {}
|
2016-01-13 19:32:47 +01:00
|
|
|
for codename in codenames:
|
|
|
|
codename = codename.strip()
|
2019-03-15 17:33:43 +01:00
|
|
|
if codename:
|
2016-01-13 19:32:47 +01:00
|
|
|
result[codename] = api_level
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
def ReadApexKeysInfo(tf_zip):
|
|
|
|
"""Parses the APEX keys info from a given target-files zip.
|
|
|
|
|
2022-04-13 01:22:11 +02:00
|
|
|
Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
|
|
|
|
dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
|
|
|
|
tuple of (payload_key, container_key, sign_tool).
|
2019-03-15 17:37:01 +01:00
|
|
|
|
|
|
|
Args:
|
|
|
|
tf_zip: The input target_files ZipFile (already open).
|
|
|
|
|
|
|
|
Returns:
|
2022-04-13 01:22:11 +02:00
|
|
|
(payload_key, container_key, sign_tool):
|
2021-10-26 20:58:09 +02:00
|
|
|
- payload_key contains the path to the payload signing key
|
|
|
|
- container_key contains the path to the container signing key
|
|
|
|
- sign_tool is an apex-specific signing tool for its payload contents
|
2019-03-15 17:37:01 +01:00
|
|
|
"""
|
|
|
|
keys = {}
|
2019-06-25 00:33:41 +02:00
|
|
|
for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
|
2019-03-15 17:37:01 +01:00
|
|
|
line = line.strip()
|
|
|
|
if not line:
|
|
|
|
continue
|
|
|
|
matches = re.match(
|
|
|
|
r'^name="(?P<NAME>.*)"\s+'
|
|
|
|
r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
|
|
|
|
r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
|
|
|
|
r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
|
2020-04-04 00:36:23 +02:00
|
|
|
r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
|
2021-10-26 20:58:09 +02:00
|
|
|
r'(\s+partition="(?P<PARTITION>.*?)")?'
|
|
|
|
r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
|
2019-03-15 17:37:01 +01:00
|
|
|
line)
|
|
|
|
if not matches:
|
|
|
|
continue
|
|
|
|
|
|
|
|
name = matches.group('NAME')
|
|
|
|
payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
|
|
|
|
|
|
|
|
def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
|
|
|
|
pubkey_suffix_len = len(pubkey_suffix)
|
|
|
|
privkey_suffix_len = len(privkey_suffix)
|
|
|
|
return (pubkey.endswith(pubkey_suffix) and
|
|
|
|
privkey.endswith(privkey_suffix) and
|
|
|
|
pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
|
|
|
|
|
2020-07-28 15:31:06 +02:00
|
|
|
# Check the container key names, as we'll carry them without the
|
2019-03-26 20:59:25 +01:00
|
|
|
# extensions. This doesn't apply to payload keys though, which we will use
|
|
|
|
# full names only.
|
2019-03-15 17:37:01 +01:00
|
|
|
container_cert = matches.group("CONTAINER_CERT")
|
|
|
|
container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
|
2019-04-25 08:53:42 +02:00
|
|
|
if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
|
|
|
|
container_key = 'PRESIGNED'
|
|
|
|
elif CompareKeys(
|
2021-08-03 01:58:14 +02:00
|
|
|
container_cert, OPTIONS.public_key_suffix,
|
|
|
|
container_private_key, OPTIONS.private_key_suffix):
|
2019-04-25 08:53:42 +02:00
|
|
|
container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
|
|
|
|
else:
|
2022-04-13 01:22:11 +02:00
|
|
|
raise ValueError("Failed to parse container keys: \n{}".format(line))
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2021-10-26 20:58:09 +02:00
|
|
|
sign_tool = matches.group("SIGN_TOOL")
|
|
|
|
keys[name] = (payload_private_key, container_key, sign_tool)
|
2019-03-15 17:37:01 +01:00
|
|
|
|
2022-04-13 01:22:11 +02:00
|
|
|
return keys
|
2019-03-15 17:37:01 +01:00
|
|
|
|
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
def BuildVendorPartitions(output_zip_path):
|
|
|
|
"""Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
|
|
|
|
if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
|
|
|
|
logger.warning("Allowed --vendor_partitions: %s",
|
|
|
|
",".join(ALLOWED_VENDOR_PARTITIONS))
|
|
|
|
OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
|
|
|
|
OPTIONS.vendor_partitions)
|
|
|
|
|
|
|
|
logger.info("Building vendor partitions using vendor otatools.")
|
|
|
|
vendor_tempdir = common.UnzipTemp(output_zip_path, [
|
|
|
|
"META/*",
|
Fix build break for vendor freeze
1. Fix build break when rebuilding vendor images in
sign_target_files_apks, because of missing SYSTEM/build.prop:
File ".../add_img_to_target_files.py", line 999, in <module>
File ".../add_img_to_target_files.py", line 993, in main
File ".../add_img_to_target_files.py", line 854, in AddImagesToTargetFiles
File ".../add_img_to_target_files.py", line 229, in AddVendor
File ".../add_img_to_target_files.py", line 391, in CreateImage
File "add_img_to_target_files/common.py", line 394, in __init__
self._fingerprint = self.CalculateFingerprint()
File "add_img_to_target_files/common.py", line 537, in CalculateFingerprint
self.GetBuildProp("ro.build.version.release"),
File "add_img_to_target_files/common.py", line 457, in GetBuildProp
raise ExternalError("couldn't find %s in build.prop" % (prop,))
ExternalError: couldn't find ro.build.version.release in build.prop
2. Support more scenarios (non-AB, RADIO...)
Bug: 192422274
Change-Id: I792b0a2c2354ed9312730e322ce28df49b3c2f7f
2021-09-27 06:59:06 +02:00
|
|
|
"SYSTEM/build.prop",
|
2022-03-22 14:51:07 +01:00
|
|
|
"RECOVERY/*",
|
|
|
|
"BOOT/*",
|
|
|
|
"OTA/",
|
2021-09-14 19:29:38 +02:00
|
|
|
] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
|
|
|
|
|
|
|
|
# Disable various partitions that build based on misc_info fields.
|
|
|
|
# Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
|
|
|
|
# vendor otatools. These other partitions will be rebuilt using the main
|
|
|
|
# otatools if necessary.
|
|
|
|
vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
|
|
|
|
vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
|
2022-03-22 14:51:07 +01:00
|
|
|
# Ignore if not rebuilding recovery
|
|
|
|
if not OPTIONS.rebuild_recovery:
|
|
|
|
vendor_misc_info["no_boot"] = "true" # boot
|
|
|
|
vendor_misc_info["vendor_boot"] = "false" # vendor_boot
|
|
|
|
vendor_misc_info["no_recovery"] = "true" # recovery
|
2022-04-19 20:17:56 +02:00
|
|
|
vendor_misc_info["avb_enable"] = "false" # vbmeta
|
2022-03-22 14:51:07 +01:00
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
vendor_misc_info["has_dtbo"] = "false" # dtbo
|
|
|
|
vendor_misc_info["has_pvmfw"] = "false" # pvmfw
|
2023-06-27 05:44:46 +02:00
|
|
|
vendor_misc_info["avb_custom_images_partition_list"] = "" # avb custom images
|
2022-04-19 20:17:56 +02:00
|
|
|
vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
|
2023-06-27 05:44:46 +02:00
|
|
|
vendor_misc_info["custom_images_partition_list"] = "" # custom images
|
2021-09-14 19:29:38 +02:00
|
|
|
vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
|
|
|
|
vendor_misc_info["build_super_partition"] = "false" # super split
|
2022-09-16 08:55:17 +02:00
|
|
|
vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
|
2021-09-14 19:29:38 +02:00
|
|
|
with open(vendor_misc_info_path, "w") as output:
|
|
|
|
for key in sorted(vendor_misc_info):
|
|
|
|
output.write("{}={}\n".format(key, vendor_misc_info[key]))
|
|
|
|
|
Fix build break for vendor freeze
1. Fix build break when rebuilding vendor images in
sign_target_files_apks, because of missing SYSTEM/build.prop:
File ".../add_img_to_target_files.py", line 999, in <module>
File ".../add_img_to_target_files.py", line 993, in main
File ".../add_img_to_target_files.py", line 854, in AddImagesToTargetFiles
File ".../add_img_to_target_files.py", line 229, in AddVendor
File ".../add_img_to_target_files.py", line 391, in CreateImage
File "add_img_to_target_files/common.py", line 394, in __init__
self._fingerprint = self.CalculateFingerprint()
File "add_img_to_target_files/common.py", line 537, in CalculateFingerprint
self.GetBuildProp("ro.build.version.release"),
File "add_img_to_target_files/common.py", line 457, in GetBuildProp
raise ExternalError("couldn't find %s in build.prop" % (prop,))
ExternalError: couldn't find ro.build.version.release in build.prop
2. Support more scenarios (non-AB, RADIO...)
Bug: 192422274
Change-Id: I792b0a2c2354ed9312730e322ce28df49b3c2f7f
2021-09-27 06:59:06 +02:00
|
|
|
# Disable system partition by a placeholder of IMAGES/system.img,
|
|
|
|
# instead of removing SYSTEM folder.
|
|
|
|
# Because SYSTEM/build.prop is still needed for:
|
|
|
|
# add_img_to_target_files.CreateImage ->
|
|
|
|
# common.BuildInfo ->
|
|
|
|
# common.BuildInfo.CalculateFingerprint
|
|
|
|
vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
|
|
|
|
if not os.path.exists(vendor_images_path):
|
|
|
|
os.makedirs(vendor_images_path)
|
|
|
|
with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
|
|
|
|
pass
|
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
# Disable care_map.pb as not all ab_partitions are available when
|
|
|
|
# vendor otatools regenerates vendor images.
|
Fix build break for vendor freeze
1. Fix build break when rebuilding vendor images in
sign_target_files_apks, because of missing SYSTEM/build.prop:
File ".../add_img_to_target_files.py", line 999, in <module>
File ".../add_img_to_target_files.py", line 993, in main
File ".../add_img_to_target_files.py", line 854, in AddImagesToTargetFiles
File ".../add_img_to_target_files.py", line 229, in AddVendor
File ".../add_img_to_target_files.py", line 391, in CreateImage
File "add_img_to_target_files/common.py", line 394, in __init__
self._fingerprint = self.CalculateFingerprint()
File "add_img_to_target_files/common.py", line 537, in CalculateFingerprint
self.GetBuildProp("ro.build.version.release"),
File "add_img_to_target_files/common.py", line 457, in GetBuildProp
raise ExternalError("couldn't find %s in build.prop" % (prop,))
ExternalError: couldn't find ro.build.version.release in build.prop
2. Support more scenarios (non-AB, RADIO...)
Bug: 192422274
Change-Id: I792b0a2c2354ed9312730e322ce28df49b3c2f7f
2021-09-27 06:59:06 +02:00
|
|
|
if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
|
|
|
|
os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
|
|
|
|
# Disable RADIO images
|
|
|
|
if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
|
|
|
|
os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
|
2021-09-14 19:29:38 +02:00
|
|
|
|
|
|
|
# Build vendor images using vendor otatools.
|
2022-03-04 17:02:44 +01:00
|
|
|
# Accept either a zip file or extracted directory.
|
|
|
|
if os.path.isfile(OPTIONS.vendor_otatools):
|
|
|
|
vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
|
|
|
|
common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
|
|
|
|
else:
|
|
|
|
vendor_otatools_dir = OPTIONS.vendor_otatools
|
2021-09-14 19:29:38 +02:00
|
|
|
cmd = [
|
|
|
|
os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
|
|
|
|
"--is_signing",
|
Fix build break for vendor freeze
1. Fix build break when rebuilding vendor images in
sign_target_files_apks, because of missing SYSTEM/build.prop:
File ".../add_img_to_target_files.py", line 999, in <module>
File ".../add_img_to_target_files.py", line 993, in main
File ".../add_img_to_target_files.py", line 854, in AddImagesToTargetFiles
File ".../add_img_to_target_files.py", line 229, in AddVendor
File ".../add_img_to_target_files.py", line 391, in CreateImage
File "add_img_to_target_files/common.py", line 394, in __init__
self._fingerprint = self.CalculateFingerprint()
File "add_img_to_target_files/common.py", line 537, in CalculateFingerprint
self.GetBuildProp("ro.build.version.release"),
File "add_img_to_target_files/common.py", line 457, in GetBuildProp
raise ExternalError("couldn't find %s in build.prop" % (prop,))
ExternalError: couldn't find ro.build.version.release in build.prop
2. Support more scenarios (non-AB, RADIO...)
Bug: 192422274
Change-Id: I792b0a2c2354ed9312730e322ce28df49b3c2f7f
2021-09-27 06:59:06 +02:00
|
|
|
"--add_missing",
|
2021-09-14 19:29:38 +02:00
|
|
|
"--verbose",
|
|
|
|
vendor_tempdir,
|
|
|
|
]
|
2022-03-22 14:51:07 +01:00
|
|
|
if OPTIONS.rebuild_recovery:
|
|
|
|
cmd.insert(4, "--rebuild_recovery")
|
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
common.RunAndCheckOutput(cmd, verbose=True)
|
|
|
|
|
|
|
|
logger.info("Writing vendor partitions to output archive.")
|
|
|
|
with zipfile.ZipFile(
|
|
|
|
output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
|
|
|
|
allowZip64=True) as output_zip:
|
|
|
|
for p in OPTIONS.vendor_partitions:
|
2022-03-17 15:02:27 +01:00
|
|
|
img_file_path = "IMAGES/{}.img".format(p)
|
|
|
|
map_file_path = "IMAGES/{}.map".format(p)
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
|
2022-06-03 08:46:56 +02:00
|
|
|
if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
|
2022-04-19 20:17:56 +02:00
|
|
|
# copy recovery.img, boot.img, recovery patch & install.sh
|
2022-03-22 14:51:07 +01:00
|
|
|
if OPTIONS.rebuild_recovery:
|
2022-04-19 20:17:56 +02:00
|
|
|
recovery_img = "IMAGES/recovery.img"
|
|
|
|
boot_img = "IMAGES/boot.img"
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
|
2022-03-22 14:51:07 +01:00
|
|
|
recovery_patch_path = "VENDOR/recovery-from-boot.p"
|
|
|
|
recovery_sh_path = "VENDOR/bin/install-recovery.sh"
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
|
|
|
|
common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
|
2021-09-14 19:29:38 +02:00
|
|
|
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
def main(argv):
|
|
|
|
|
|
|
|
key_mapping_options = []
|
|
|
|
|
|
|
|
def option_handler(o, a):
|
|
|
|
if o in ("-e", "--extra_apks"):
|
|
|
|
names, key = a.split("=")
|
|
|
|
names = names.split(",")
|
|
|
|
for n in names:
|
|
|
|
OPTIONS.extra_apks[n] = key
|
2019-03-15 17:37:01 +01:00
|
|
|
elif o == "--extra_apex_payload_key":
|
2022-07-26 01:12:30 +02:00
|
|
|
apex_names, key = a.split("=")
|
2022-07-27 20:14:12 +02:00
|
|
|
for name in apex_names.split(","):
|
2022-07-26 01:12:30 +02:00
|
|
|
OPTIONS.extra_apex_payload_keys[name] = key
|
2018-06-19 21:19:35 +02:00
|
|
|
elif o == "--skip_apks_with_path_prefix":
|
2020-07-29 20:56:19 +02:00
|
|
|
# Check the prefix, which must be in all upper case.
|
2018-06-19 21:19:35 +02:00
|
|
|
prefix = a.split('/')[0]
|
|
|
|
if not prefix or prefix != prefix.upper():
|
|
|
|
raise ValueError("Invalid path prefix '%s'" % (a,))
|
|
|
|
OPTIONS.skip_apks_with_path_prefix.add(a)
|
2015-03-24 03:13:21 +01:00
|
|
|
elif o in ("-d", "--default_key_mappings"):
|
|
|
|
key_mapping_options.append((None, a))
|
|
|
|
elif o in ("-k", "--key_mapping"):
|
|
|
|
key_mapping_options.append(a.split("=", 1))
|
|
|
|
elif o in ("-o", "--replace_ota_keys"):
|
|
|
|
OPTIONS.replace_ota_keys = True
|
|
|
|
elif o in ("-t", "--tag_changes"):
|
|
|
|
new = []
|
|
|
|
for i in a.split(","):
|
|
|
|
i = i.strip()
|
|
|
|
if not i or i[0] not in "-+":
|
|
|
|
raise ValueError("Bad tag change '%s'" % (i,))
|
|
|
|
new.append(i[0] + i[1:].strip())
|
|
|
|
OPTIONS.tag_changes = tuple(new)
|
|
|
|
elif o == "--replace_verity_public_key":
|
2022-08-19 08:33:25 +02:00
|
|
|
raise ValueError("--replace_verity_public_key is no longer supported,"
|
|
|
|
" please switch to AVB")
|
2015-03-24 03:13:21 +01:00
|
|
|
elif o == "--replace_verity_private_key":
|
2022-08-19 08:33:25 +02:00
|
|
|
raise ValueError("--replace_verity_private_key is no longer supported,"
|
|
|
|
" please switch to AVB")
|
2016-06-17 04:58:44 +02:00
|
|
|
elif o == "--replace_verity_keyid":
|
2022-08-19 08:33:25 +02:00
|
|
|
raise ValueError("--replace_verity_keyid is no longer supported, please"
|
|
|
|
" switch to AVB")
|
2020-02-21 10:48:18 +01:00
|
|
|
elif o == "--remove_avb_public_keys":
|
|
|
|
OPTIONS.remove_avb_public_keys = a.split(",")
|
2017-06-20 00:48:02 +02:00
|
|
|
elif o == "--avb_vbmeta_key":
|
|
|
|
OPTIONS.avb_keys['vbmeta'] = a
|
|
|
|
elif o == "--avb_vbmeta_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['vbmeta'] = a
|
|
|
|
elif o == "--avb_vbmeta_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['vbmeta'] = a
|
|
|
|
elif o == "--avb_boot_key":
|
|
|
|
OPTIONS.avb_keys['boot'] = a
|
|
|
|
elif o == "--avb_boot_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['boot'] = a
|
|
|
|
elif o == "--avb_boot_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['boot'] = a
|
|
|
|
elif o == "--avb_dtbo_key":
|
|
|
|
OPTIONS.avb_keys['dtbo'] = a
|
|
|
|
elif o == "--avb_dtbo_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['dtbo'] = a
|
|
|
|
elif o == "--avb_dtbo_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['dtbo'] = a
|
2022-11-07 22:36:38 +01:00
|
|
|
elif o == "--avb_init_boot_key":
|
|
|
|
OPTIONS.avb_keys['init_boot'] = a
|
|
|
|
elif o == "--avb_init_boot_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['init_boot'] = a
|
|
|
|
elif o == "--avb_init_boot_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['init_boot'] = a
|
2021-12-11 23:03:10 +01:00
|
|
|
elif o == "--avb_recovery_key":
|
|
|
|
OPTIONS.avb_keys['recovery'] = a
|
|
|
|
elif o == "--avb_recovery_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['recovery'] = a
|
|
|
|
elif o == "--avb_recovery_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['recovery'] = a
|
2017-06-20 00:48:02 +02:00
|
|
|
elif o == "--avb_system_key":
|
|
|
|
OPTIONS.avb_keys['system'] = a
|
|
|
|
elif o == "--avb_system_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['system'] = a
|
|
|
|
elif o == "--avb_system_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['system'] = a
|
2019-02-27 03:15:51 +01:00
|
|
|
elif o == "--avb_system_other_key":
|
|
|
|
OPTIONS.avb_keys['system_other'] = a
|
|
|
|
elif o == "--avb_system_other_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['system_other'] = a
|
|
|
|
elif o == "--avb_system_other_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['system_other'] = a
|
2017-06-20 00:48:02 +02:00
|
|
|
elif o == "--avb_vendor_key":
|
|
|
|
OPTIONS.avb_keys['vendor'] = a
|
|
|
|
elif o == "--avb_vendor_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['vendor'] = a
|
|
|
|
elif o == "--avb_vendor_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['vendor'] = a
|
2019-05-06 21:55:42 +02:00
|
|
|
elif o == "--avb_vbmeta_system_key":
|
|
|
|
OPTIONS.avb_keys['vbmeta_system'] = a
|
|
|
|
elif o == "--avb_vbmeta_system_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['vbmeta_system'] = a
|
|
|
|
elif o == "--avb_vbmeta_system_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['vbmeta_system'] = a
|
|
|
|
elif o == "--avb_vbmeta_vendor_key":
|
|
|
|
OPTIONS.avb_keys['vbmeta_vendor'] = a
|
|
|
|
elif o == "--avb_vbmeta_vendor_algorithm":
|
|
|
|
OPTIONS.avb_algorithms['vbmeta_vendor'] = a
|
|
|
|
elif o == "--avb_vbmeta_vendor_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['vbmeta_vendor'] = a
|
2019-03-15 17:37:01 +01:00
|
|
|
elif o == "--avb_apex_extra_args":
|
|
|
|
OPTIONS.avb_extra_args['apex'] = a
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
elif o == "--avb_extra_custom_image_key":
|
|
|
|
partition, key = a.split("=")
|
|
|
|
OPTIONS.avb_keys[partition] = key
|
|
|
|
elif o == "--avb_extra_custom_image_algorithm":
|
|
|
|
partition, algorithm = a.split("=")
|
|
|
|
OPTIONS.avb_algorithms[partition] = algorithm
|
|
|
|
elif o == "--avb_extra_custom_image_extra_args":
|
2020-05-24 07:20:19 +02:00
|
|
|
# Setting the maxsplit parameter to one, which will return a list with
|
|
|
|
# two elements. e.g., the second '=' should not be splitted for
|
|
|
|
# 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
|
|
|
|
partition, extra_args = a.split("=", 1)
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
OPTIONS.avb_extra_args[partition] = extra_args
|
2021-09-14 19:29:38 +02:00
|
|
|
elif o == "--vendor_otatools":
|
|
|
|
OPTIONS.vendor_otatools = a
|
|
|
|
elif o == "--vendor_partitions":
|
|
|
|
OPTIONS.vendor_partitions = set(a.split(","))
|
2021-10-13 11:39:33 +02:00
|
|
|
elif o == "--allow_gsi_debug_sepolicy":
|
|
|
|
OPTIONS.allow_gsi_debug_sepolicy = True
|
2022-08-02 00:58:51 +02:00
|
|
|
elif o == "--override_apk_keys":
|
|
|
|
OPTIONS.override_apk_keys = a
|
|
|
|
elif o == "--override_apex_keys":
|
|
|
|
OPTIONS.override_apex_keys = a
|
2024-01-24 07:10:17 +01:00
|
|
|
elif o in ("--gki_signing_key", "--gki_signing_algorithm", "--gki_signing_extra_args"):
|
|
|
|
print(f"{o} is deprecated and does nothing")
|
2015-03-24 03:13:21 +01:00
|
|
|
else:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2017-06-20 00:48:02 +02:00
|
|
|
args = common.ParseOptions(
|
|
|
|
argv, __doc__,
|
|
|
|
extra_opts="e:d:k:ot:",
|
|
|
|
extra_long_opts=[
|
2017-12-24 19:37:38 +01:00
|
|
|
"extra_apks=",
|
2019-03-15 17:37:01 +01:00
|
|
|
"extra_apex_payload_key=",
|
2018-06-19 21:19:35 +02:00
|
|
|
"skip_apks_with_path_prefix=",
|
2017-12-24 19:37:38 +01:00
|
|
|
"default_key_mappings=",
|
|
|
|
"key_mapping=",
|
|
|
|
"replace_ota_keys",
|
|
|
|
"tag_changes=",
|
|
|
|
"replace_verity_public_key=",
|
|
|
|
"replace_verity_private_key=",
|
|
|
|
"replace_verity_keyid=",
|
2020-02-21 10:48:18 +01:00
|
|
|
"remove_avb_public_keys=",
|
2019-03-15 17:37:01 +01:00
|
|
|
"avb_apex_extra_args=",
|
2017-12-24 19:37:38 +01:00
|
|
|
"avb_vbmeta_algorithm=",
|
|
|
|
"avb_vbmeta_key=",
|
|
|
|
"avb_vbmeta_extra_args=",
|
|
|
|
"avb_boot_algorithm=",
|
|
|
|
"avb_boot_key=",
|
|
|
|
"avb_boot_extra_args=",
|
|
|
|
"avb_dtbo_algorithm=",
|
|
|
|
"avb_dtbo_key=",
|
|
|
|
"avb_dtbo_extra_args=",
|
2022-11-07 22:36:38 +01:00
|
|
|
"avb_init_boot_algorithm=",
|
|
|
|
"avb_init_boot_key=",
|
|
|
|
"avb_init_boot_extra_args=",
|
2021-12-11 23:03:10 +01:00
|
|
|
"avb_recovery_algorithm=",
|
|
|
|
"avb_recovery_key=",
|
|
|
|
"avb_recovery_extra_args=",
|
2017-12-24 19:37:38 +01:00
|
|
|
"avb_system_algorithm=",
|
|
|
|
"avb_system_key=",
|
|
|
|
"avb_system_extra_args=",
|
2019-02-27 03:15:51 +01:00
|
|
|
"avb_system_other_algorithm=",
|
|
|
|
"avb_system_other_key=",
|
|
|
|
"avb_system_other_extra_args=",
|
2017-12-24 19:37:38 +01:00
|
|
|
"avb_vendor_algorithm=",
|
|
|
|
"avb_vendor_key=",
|
|
|
|
"avb_vendor_extra_args=",
|
2019-05-06 21:55:42 +02:00
|
|
|
"avb_vbmeta_system_algorithm=",
|
|
|
|
"avb_vbmeta_system_key=",
|
|
|
|
"avb_vbmeta_system_extra_args=",
|
|
|
|
"avb_vbmeta_vendor_algorithm=",
|
|
|
|
"avb_vbmeta_vendor_key=",
|
|
|
|
"avb_vbmeta_vendor_extra_args=",
|
Add options to sign the prebuilt custom images.
The custom images are any images owned by OEMs and SoCs, oem images
mounted on /oem is an example. The oem images can be used to customize
devices for different carriers, like wallpaper, ringtones, and
carrier-specific apks. OEMs can generate multiple oem images, like
oem.img, oem-carrier1.img and oem-carrier2.img and flash different oem
images for different carriers. The oem images are only one case, OEMs
and SoCs can add more custom images and mount them to custom partitions.
This change enables custom images to be vbmeta.img chained partitions.
The following configuration in BoardConfig.mk is an exmaple. It has two
custom partitions: oem and test. They will be signed by different keys.
And they will be chained by vbmeta.img. The custom images here are
prebuilts, which can be built by `make custom_images` separately.
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST should include all custom images
to apply AVB signing. And to every custom partition, one image whose
name is partition name must be added in its
BOARD_AVB_<CUSTOM_PARTITION>_IMAGE_LIST.
BOARD_CUSTOMIMAGES_PARTITION_LIST := oem test
BOARD_AVB_OEM_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_OEM_ALGORITHM := SHA256_RSA4096
BOARD_AVB_OEM_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_OEM_ROLLBACK_INDEX_LOCATION := 1
BOARD_AVB_OEM_PARTITION_SIZE := 5242880
BOARD_AVB_OEM_IMAGE_LIST := \
device/xxxx/yyyy/oem/oem.img \
device/xxxx/yyyy/oem/oem1.img
BOARD_AVB_TEST_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_TEST_ALGORITHM := SHA256_RSA2048
BOARD_AVB_TEST_ADD_HASHTREE_FOOTER_ARGS :=
BOARD_AVB_TEST_ROLLBACK_INDEX_LOCATION := 2
BOARD_AVB_TEST_PARTITION_SIZE := 10485760
BOARD_AVB_TEST_IMAGE_LIST := \
device/xxxx/yyyy/test/test.img \
device/xxxx/yyyy/test/test1.img
To resign the custom images in the target zip file, the
avb_extra_custom_image_key, avb_extra_custom_image_algorithms and
avb_extra_custom_image_extra_args options are added to the
sign_target_files_apks tool too. The following test cases list some
examples about how to use them.
BUG: 154171021
Test: 1) "atest --host releasetools_test releasetools_py3_test -c"
2) Build images by 'make dist', sign and validate target files.
a) Test on dist w/ chained vbmeta_system and ome custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the oem images and vbmeta images in OUT and target zips by
avbtool.
b) Test on dist w/ chained vbmeta_system and oem and test custom images
sign_target_files_apks -d certs \
--avb_extra_custom_image_key oem=oem_rsa4096.pem \
--avb_extra_custom_image_algorithm oem=SHA256_RSA4096 \
--avb_extra_custom_image_extra_args oem=--do_not_generate_fec \
--avb_extra_custom_image_key test=test_rsa4096.pem \
--avb_extra_custom_image_algorithm test=SHA256_RSA4096 \
xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Verify the oem, test images and vbmeta images in OUT and target zips
by avbtool.
c) Test on dist w/o chained partition.
sign_target_files_apks -d certs xxx-target_xxx.zip signed.zip
validate_target_files.py signed.zip
Flash image and boot up.
Verify the vbmeta images in OUT and target zips by avbtool.
Change-Id: Ifccfee5e8909697eef6ccda0cc352fa16a9f6db6
2020-04-28 03:36:36 +02:00
|
|
|
"avb_extra_custom_image_key=",
|
|
|
|
"avb_extra_custom_image_algorithm=",
|
|
|
|
"avb_extra_custom_image_extra_args=",
|
2023-12-01 08:02:17 +01:00
|
|
|
"gki_signing_key=",
|
|
|
|
"gki_signing_algorithm=",
|
|
|
|
"gki_signing_extra_args=",
|
2021-09-14 19:29:38 +02:00
|
|
|
"vendor_partitions=",
|
|
|
|
"vendor_otatools=",
|
2021-10-13 11:39:33 +02:00
|
|
|
"allow_gsi_debug_sepolicy",
|
2022-08-02 00:58:51 +02:00
|
|
|
"override_apk_keys=",
|
|
|
|
"override_apex_keys=",
|
2017-06-20 00:48:02 +02:00
|
|
|
],
|
2023-11-06 19:53:41 +01:00
|
|
|
extra_option_handler=[option_handler, payload_signer.signer_options])
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
if len(args) != 2:
|
|
|
|
common.Usage(__doc__)
|
|
|
|
sys.exit(1)
|
|
|
|
|
2019-03-15 17:33:43 +01:00
|
|
|
common.InitLogging()
|
|
|
|
|
2020-09-22 22:15:57 +02:00
|
|
|
input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
|
2017-06-13 21:54:58 +02:00
|
|
|
output_zip = zipfile.ZipFile(args[1], "w",
|
|
|
|
compression=zipfile.ZIP_DEFLATED,
|
|
|
|
allowZip64=True)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
misc_info = common.LoadInfoDict(input_zip)
|
2023-11-06 19:53:41 +01:00
|
|
|
if OPTIONS.package_key is None:
|
|
|
|
OPTIONS.package_key = misc_info.get(
|
|
|
|
"default_system_dev_certificate",
|
|
|
|
"build/make/target/product/security/testkey")
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
BuildKeyMap(misc_info, key_mapping_options)
|
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
|
|
|
|
apk_keys = GetApkCerts(apk_keys_info)
|
|
|
|
|
2022-04-13 01:22:11 +02:00
|
|
|
apex_keys_info = ReadApexKeysInfo(input_zip)
|
2019-03-15 17:37:01 +01:00
|
|
|
apex_keys = GetApexKeys(apex_keys_info, apk_keys)
|
|
|
|
|
2020-01-23 19:47:54 +01:00
|
|
|
# TODO(xunchang) check for the apks inside the apex files, and abort early if
|
|
|
|
# the keys are not available.
|
2019-03-15 17:37:01 +01:00
|
|
|
CheckApkAndApexKeysAvailable(
|
|
|
|
input_zip,
|
|
|
|
set(apk_keys.keys()) | set(apex_keys.keys()),
|
2019-03-19 20:24:03 +01:00
|
|
|
compressed_extension,
|
|
|
|
apex_keys)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2019-03-15 17:37:01 +01:00
|
|
|
key_passwords = common.GetKeyPasswords(
|
|
|
|
set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
|
2016-09-30 02:53:56 +02:00
|
|
|
platform_api_level, _ = GetApiLevelAndCodename(input_zip)
|
2016-01-13 19:32:47 +01:00
|
|
|
codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
|
|
|
|
|
2015-03-24 03:13:21 +01:00
|
|
|
ProcessTargetFiles(input_zip, output_zip, misc_info,
|
2019-03-15 17:37:01 +01:00
|
|
|
apk_keys, apex_keys, key_passwords,
|
|
|
|
platform_api_level, codename_to_api_level_map,
|
2022-04-13 01:22:11 +02:00
|
|
|
compressed_extension)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2023-04-14 23:32:54 +02:00
|
|
|
common.ZipClose(input_zip)
|
|
|
|
common.ZipClose(output_zip)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2021-09-14 19:29:38 +02:00
|
|
|
if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
|
|
|
|
BuildVendorPartitions(args[1])
|
|
|
|
|
2016-08-04 04:21:52 +02:00
|
|
|
# Skip building userdata.img and cache.img when signing the target files.
|
2021-09-14 19:29:38 +02:00
|
|
|
new_args = ["--is_signing", "--add_missing", "--verbose"]
|
2017-05-23 23:51:02 +02:00
|
|
|
# add_img_to_target_files builds the system image from scratch, so the
|
|
|
|
# recovery patch is guaranteed to be regenerated there.
|
|
|
|
if OPTIONS.rebuild_recovery:
|
|
|
|
new_args.append("--rebuild_recovery")
|
|
|
|
new_args.append(args[1])
|
2016-08-04 04:21:52 +02:00
|
|
|
add_img_to_target_files.main(new_args)
|
2015-03-24 03:13:21 +01:00
|
|
|
|
2017-12-24 19:37:38 +01:00
|
|
|
print("done.")
|
2015-03-24 03:13:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
try:
|
|
|
|
main(sys.argv[1:])
|
2017-06-20 00:48:02 +02:00
|
|
|
finally:
|
|
|
|
common.Cleanup()
|