blob: b8f848fb2bdfb986df1342e1e5618906c239ca49 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Signs all the APK files in a target-files zipfile, producing a new
19target-files zip.
20
21Usage: sign_target_files_apks [flags] input_target_files output_target_files
22
Doug Zongkereef39442009-04-02 12:14:19 -070023 -e (--extra_apks) <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070024 Add extra APK/APEX name/key pairs as though they appeared in apkcerts.txt
25 or apexkeys.txt (so mappings specified by -k and -d are applied). Keys
26 specified in -e override any value for that app contained in the
27 apkcerts.txt file, or the container key for an APEX. Option may be
28 repeated to give multiple extra packages.
29
Kelvin Zhang085b6f32022-07-25 16:12:30 -070030 --extra_apex_payload_key <name,name,...=key>
Tao Baoaa7e9932019-03-15 09:37:01 -070031 Add a mapping for APEX package name to payload signing key, which will
32 override the default payload signing key in apexkeys.txt. Note that the
33 container key should be overridden via the `--extra_apks` flag above.
34 Option may be repeated for multiple APEXes.
Doug Zongkereef39442009-04-02 12:14:19 -070035
Tao Bao93c2a012018-06-19 12:19:35 -070036 --skip_apks_with_path_prefix <prefix>
37 Skip signing an APK if it has the matching prefix in its path. The prefix
38 should be matching the entry name, which has partition names in upper
39 case, e.g. "VENDOR/app/", or "SYSTEM_OTHER/preloads/". Option may be
40 repeated to give multiple prefixes.
41
Doug Zongkereef39442009-04-02 12:14:19 -070042 -k (--key_mapping) <src_key=dest_key>
43 Add a mapping from the key name as specified in apkcerts.txt (the
44 src_key) to the real key you wish to sign the package with
45 (dest_key). Option may be repeated to give multiple key
46 mappings.
47
48 -d (--default_key_mappings) <dir>
49 Set up the following key mappings:
50
Doug Zongker831840e2011-09-22 10:28:04 -070051 $devkey/devkey ==> $dir/releasekey
52 $devkey/testkey ==> $dir/releasekey
53 $devkey/media ==> $dir/media
54 $devkey/shared ==> $dir/shared
55 $devkey/platform ==> $dir/platform
56
57 where $devkey is the directory part of the value of
58 default_system_dev_certificate from the input target-files's
Dan Willemsen0ab1be62019-04-09 21:35:37 -070059 META/misc_info.txt. (Defaulting to "build/make/target/product/security"
Doug Zongker831840e2011-09-22 10:28:04 -070060 if the value is not present in misc_info.
Doug Zongkereef39442009-04-02 12:14:19 -070061
62 -d and -k options are added to the set of mappings in the order
63 in which they appear on the command line.
Doug Zongker8e931bf2009-04-06 15:21:45 -070064
65 -o (--replace_ota_keys)
Tao Baoa80ed222016-06-16 14:41:24 -070066 Replace the certificate (public key) used by OTA package verification
67 with the ones specified in the input target_files zip (in the
68 META/otakeys.txt file). Key remapping (-k and -d) is performed on the
69 keys. For A/B devices, the payload verification key will be replaced
70 as well. If there're multiple OTA keys, only the first one will be used
71 for payload verification.
Doug Zongker17aa9442009-04-17 10:15:58 -070072
Doug Zongkerae877012009-04-21 10:04:51 -070073 -t (--tag_changes) <+tag>,<-tag>,...
74 Comma-separated list of changes to make to the set of tags (in
75 the last component of the build fingerprint). Prefix each with
76 '+' or '-' to indicate whether that tag should be added or
77 removed. Changes are processed in the order they appear.
Doug Zongker831840e2011-09-22 10:28:04 -070078 Default value is "-test-keys,-dev-keys,+release-keys".
Doug Zongkerae877012009-04-21 10:04:51 -070079
Tao Bao8adcfd12016-06-17 17:01:22 -070080 --replace_verity_private_key <key>
81 Replace the private key used for verity signing. It expects a filename
82 WITHOUT the extension (e.g. verity_key).
83
84 --replace_verity_public_key <key>
85 Replace the certificate (public key) used for verity verification. The
Yi-Yo Chiang18650c72022-10-12 18:29:14 +080086 key file replaces the one at BOOT/RAMDISK/verity_key. It expects the key
87 filename WITH the extension (e.g. verity_key.pub).
Tao Bao8adcfd12016-06-17 17:01:22 -070088
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070089 --replace_verity_keyid <path_to_X509_PEM_cert_file>
90 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070091 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070092
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080093 --remove_avb_public_keys <key1>,<key2>,...
94 Remove AVB public keys from the first-stage ramdisk. The key file to
95 remove is located at either of the following dirs:
96 - BOOT/RAMDISK/avb/ or
97 - BOOT/RAMDISK/first_stage_ramdisk/avb/
98 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
99 set to true.
100
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800101 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
102 vbmeta_system,vbmeta_vendor}_algorithm <algorithm>
103 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
104 vbmeta_system,vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -0700105 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
106 the specified image. Otherwise it uses the existing values in info dict.
107
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800108 --avb_{apex,init_boot,boot,recovery,system,system_other,vendor,dtbo,vbmeta,
Ben Fennema6082d0a2021-12-11 14:03:10 -0800109 vbmeta_system,vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700110 Specify any additional args that are needed to AVB-sign the image
111 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
112 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800113
Hongguang Chenf23364d2020-04-27 18:36:36 -0700114 --avb_extra_custom_image_key <partition=key>
115 --avb_extra_custom_image_algorithm <partition=algorithm>
116 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
117 the specified custom images mounted on the partition. Otherwise it uses
118 the existing values in info dict.
119
120 --avb_extra_custom_image_extra_args <partition=extra_args>
121 Specify any additional args that are needed to AVB-sign the custom images
122 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
123 args will be appended to the existing ones in info dict.
124
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000125 --gki_signing_algorithm <algorithm>
126 --gki_signing_key <key>
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000127 --gki_signing_extra_args <args>
Yi-Yo Chianga4d5f432024-01-24 14:10:17 +0800128 DEPRECATED Does nothing.
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000129
Tianjie Xu88a759d2020-01-23 10:47:54 -0800130 --android_jar_path <path>
131 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800132
133 --allow_gsi_debug_sepolicy
134 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
135 (/system/system_ext|/system_ext)/etc/selinux.
136 If not set, error out when the file exists.
Kelvin Zhange50bb512022-08-01 15:58:51 -0700137
138 --override_apk_keys <path>
139 Replace all APK keys with this private key
140
141 --override_apex_keys <path>
142 Replace all APEX keys with this private key
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800143
144 -k (--package_key) <key>
145 Key to use to sign the package (default is the value of
146 default_system_dev_certificate from the input target-files's
147 META/misc_info.txt, or "build/make/target/product/security/testkey" if
148 that value is not specified).
149
150 For incremental OTAs, the default value is based on the source
151 target-file, not the target build.
152
153 --payload_signer <signer>
154 Specify the signer when signing the payload and metadata for A/B OTAs.
155 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
156 with the package private key. If the private key cannot be accessed
157 directly, a payload signer that knows how to do that should be specified.
158 The signer will be supplied with "-inkey <path_to_key>",
159 "-in <input_file>" and "-out <output_file>" parameters.
160
161 --payload_signer_args <args>
162 Specify the arguments needed for payload signer.
163
164 --payload_signer_maximum_signature_size <signature_size>
165 The maximum signature size (in bytes) that would be generated by the given
166 payload signer. Only meaningful when custom payload signer is specified
167 via '--payload_signer'.
168 If the signer uses a RSA key, this should be the number of bytes to
169 represent the modulus. If it uses an EC key, this is the size of a
170 DER-encoded ECDSA signature.
Doug Zongkereef39442009-04-02 12:14:19 -0700171"""
172
Tao Bao0c28d2d2017-12-24 10:37:38 -0800173from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700174
Robert Craig817c5742013-04-19 10:59:22 -0400175import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700176import copy
Robert Craig817c5742013-04-19 10:59:22 -0400177import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100178import gzip
Tao Baobb733882019-07-24 23:31:19 -0700179import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700180import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700181import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700182import os
183import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100184import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700185import stat
Tao Bao0c28d2d2017-12-24 10:37:38 -0800186import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700187import tempfile
188import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800189from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700190
Doug Zongker3c84f562014-07-31 11:06:30 -0700191import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700192import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700193import common
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800194import payload_signer
195from payload_signer import SignOtaPackage, PAYLOAD_BIN
Doug Zongkereef39442009-04-02 12:14:19 -0700196
Tao Bao0c28d2d2017-12-24 10:37:38 -0800197
198if sys.hexversion < 0x02070000:
199 print("Python 2.7 or newer is required.", file=sys.stderr)
200 sys.exit(1)
201
202
Tao Baobadceb22019-03-15 09:33:43 -0700203logger = logging.getLogger(__name__)
204
Doug Zongkereef39442009-04-02 12:14:19 -0700205OPTIONS = common.OPTIONS
206
207OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700208OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700209OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700210OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700211OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700212OPTIONS.replace_ota_keys = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800213OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700214OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700215OPTIONS.avb_keys = {}
216OPTIONS.avb_algorithms = {}
217OPTIONS.avb_extra_args = {}
Tianjie Xu88a759d2020-01-23 10:47:54 -0800218OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700219OPTIONS.vendor_partitions = set()
220OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800221OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700222OPTIONS.override_apk_keys = None
223OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700224
Tao Bao0c28d2d2017-12-24 10:37:38 -0800225
Tao Bao19b02fe2019-10-09 00:04:28 -0700226AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800227 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000228 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800229 'dtbo': 'avb_dtbo_add_hash_footer_args',
230 'product': 'avb_product_add_hashtree_footer_args',
231 'recovery': 'avb_recovery_add_hash_footer_args',
232 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000233 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800234 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
235 'system_other': 'avb_system_other_add_hashtree_footer_args',
236 'odm': 'avb_odm_add_hashtree_footer_args',
237 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
238 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
239 'vendor': 'avb_vendor_add_hashtree_footer_args',
240 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800241 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800242 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
243 'vbmeta': 'avb_vbmeta_args',
244 'vbmeta_system': 'avb_vbmeta_system_args',
245 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700246}
247
248
Tianjiebf0b8a82021-03-03 17:31:04 -0800249# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
250for partition in common.AVB_PARTITIONS:
251 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
252 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
253
Daniel Norman78554ea2021-09-14 10:29:38 -0700254# Partitions that can be regenerated after signing using a separate
255# vendor otatools package.
256ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
257
Tianjiebf0b8a82021-03-03 17:31:04 -0800258
Tianjie4d48d502021-06-11 17:03:43 -0700259def IsApexFile(filename):
260 return filename.endswith(".apex") or filename.endswith(".capex")
261
262
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800263def IsOtaPackage(fp):
264 with zipfile.ZipFile(fp) as zfp:
265 if not PAYLOAD_BIN in zfp.namelist():
266 return False
267 with zfp.open(PAYLOAD_BIN, "r") as payload:
268 magic = payload.read(4)
269 return magic == b"CrAU"
270
271
272def IsEntryOtaPackage(input_zip, filename):
273 with input_zip.open(filename, "r") as fp:
LuK1337fc51de42024-03-24 20:52:45 +0100274 external_attr = input_zip.getinfo(filename).external_attr
275 if stat.S_ISLNK(external_attr >> 16):
276 return IsEntryOtaPackage(input_zip,
277 os.path.join(os.path.dirname(filename), fp.read().decode()))
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800278 return IsOtaPackage(fp)
279
280
Tianjie4d48d502021-06-11 17:03:43 -0700281def GetApexFilename(filename):
282 name = os.path.basename(filename)
283 # Replace the suffix for compressed apex
284 if name.endswith(".capex"):
285 return name.replace(".capex", ".apex")
286 return name
287
288
Narayan Kamatha07bf042017-08-14 14:49:21 +0100289def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700290 if OPTIONS.override_apk_keys is not None:
291 for apk in certmap.keys():
292 certmap[apk] = OPTIONS.override_apk_keys
293
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800294 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700295 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800296 certmap[apk] = OPTIONS.key_map.get(cert, cert)
297
298 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700299 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800300 if not cert:
301 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700302 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800303
Doug Zongkereef39442009-04-02 12:14:19 -0700304 return certmap
305
306
Tao Baoaa7e9932019-03-15 09:37:01 -0700307def GetApexKeys(keys_info, key_map):
308 """Gets APEX payload and container signing keys by applying the mapping rules.
309
Tao Baoe1343992019-03-19 12:24:03 -0700310 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700311
312 Args:
313 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900314 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700315 key_map: A dict that overrides the keys, specified via command-line input.
316
317 Returns:
318 A dict that contains the updated APEX key mapping, which should be used for
319 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700320
321 Raises:
322 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700323 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700324 if OPTIONS.override_apex_keys is not None:
325 for apex in keys_info.keys():
326 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
327
328 if OPTIONS.override_apk_keys is not None:
329 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
330 for apex in keys_info.keys():
331 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
332
Tao Baoaa7e9932019-03-15 09:37:01 -0700333 # Apply all the --extra_apex_payload_key options to override the payload
334 # signing keys in the given keys_info.
335 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700336 if not key:
337 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700338 if apex not in keys_info:
339 logger.warning('Failed to find %s in target_files; Ignored', apex)
340 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900341 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700342
343 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900344 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
345 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700346
347 # Apply all the --extra_apks options to override the container keys.
348 for apex, key in OPTIONS.extra_apks.items():
349 # Skip non-APEX containers.
350 if apex not in keys_info:
351 continue
Tao Baoe1343992019-03-19 12:24:03 -0700352 if not key:
353 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900354 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700355
Tao Baof98fa102019-04-24 14:51:25 -0700356 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
357 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
358 # (overridden via commandline) indicates a config error, which should not be
359 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900360 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700361 if container_key != 'PRESIGNED':
362 continue
363 if apex in OPTIONS.extra_apex_payload_keys:
364 payload_override = OPTIONS.extra_apex_payload_keys[apex]
365 assert payload_override == '', \
366 ("Invalid APEX key overrides: {} has PRESIGNED container but "
367 "non-PRESIGNED payload key {}").format(apex, payload_override)
368 if payload_key != 'PRESIGNED':
369 print(
370 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
371 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900372 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700373
Tao Baoaa7e9932019-03-15 09:37:01 -0700374 return keys_info
375
376
Tao Bao93c2a012018-06-19 12:19:35 -0700377def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700378 """Returns the APK info based on the given filename.
379
380 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700381 compressed extension into consideration. If it appears to be an APK file,
382 further checks if the APK file should be skipped when signing, based on the
383 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700384
385 Args:
386 filename: Path to the file.
387 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
388 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700389 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700390
391 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700392 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
393 given filename is an APK file. is_compressed indicates whether the APK file
394 is compressed (only meaningful when is_apk is True). should_be_skipped
395 indicates whether the filename matches any of the given prefixes to be
396 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700397
398 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700399 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700400 """
401 assert compressed_extension is None or compressed_extension.startswith('.'), \
402 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
403
Tao Bao93c2a012018-06-19 12:19:35 -0700404 # skipped_prefixes should be one of set/list/tuple types. Other types such as
405 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700406 assert isinstance(skipped_prefixes, (set, list, tuple)), \
407 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700408
Tao Bao11f955c2018-06-19 12:19:35 -0700409 compressed_apk_extension = (
410 ".apk" + compressed_extension if compressed_extension else None)
411 is_apk = (filename.endswith(".apk") or
412 (compressed_apk_extension and
413 filename.endswith(compressed_apk_extension)))
414 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700415 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700416
417 is_compressed = (compressed_apk_extension and
418 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700419 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
420 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700421
422
Tao Baoaa7e9932019-03-15 09:37:01 -0700423def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700424 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700426
427 Args:
428 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700429 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700430 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700431 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700432 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900433 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700434
435 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700436 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700437 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700438 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700439 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800440 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700441 if IsApexFile(info.filename):
442 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700443 if name not in known_keys:
444 unknown_files.append(name)
445 continue
446
447 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700448 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
449 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
450 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700451 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700452
Tao Bao11f955c2018-06-19 12:19:35 -0700453 name = os.path.basename(info.filename)
454 if is_compressed:
455 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700456 if name not in known_keys:
457 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700458
Tao Baoaa7e9932019-03-15 09:37:01 -0700459 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700460 ("No key specified for:\n {}\n"
461 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700462 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700463
Tao Baoe1343992019-03-19 12:24:03 -0700464 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700465 # one of the payload / container keys set. Note that non-PRESIGNED container
466 # with PRESIGNED payload could be allowed but currently unsupported. It would
467 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700468 if not apex_keys:
469 return
470
471 invalid_apexes = []
472 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700473 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700474 continue
475
Tianjie4d48d502021-06-11 17:03:43 -0700476 name = GetApexFilename(info.filename)
477
Jooyung Han8caba5e2021-10-27 03:58:09 +0900478 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700479 if ((payload_key in common.SPECIAL_CERT_STRINGS and
480 container_key not in common.SPECIAL_CERT_STRINGS) or
481 (payload_key not in common.SPECIAL_CERT_STRINGS and
482 container_key in common.SPECIAL_CERT_STRINGS)):
483 invalid_apexes.append(
484 "{}: payload_key {}, container_key {}".format(
485 name, payload_key, container_key))
486
487 assert not invalid_apexes, \
488 "Invalid APEX keys specified:\n {}\n".format(
489 "\n ".join(invalid_apexes))
490
Doug Zongkereb338ef2009-05-20 16:50:49 -0700491
Narayan Kamatha07bf042017-08-14 14:49:21 +0100492def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700493 is_compressed, apk_name):
494 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700495 unsigned.write(data)
496 unsigned.flush()
497
Narayan Kamatha07bf042017-08-14 14:49:21 +0100498 if is_compressed:
499 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800500 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400501 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100502 shutil.copyfileobj(in_file, out_file)
503
504 # Finally, close the "unsigned" file (which is gzip compressed), and then
505 # replace it with the uncompressed version.
506 #
507 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
508 # we could just gzip / gunzip in-memory buffers instead.
509 unsigned.close()
510 unsigned = uncompressed
511
Oleg Aravin8046cb02020-06-02 16:02:38 -0700512 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700513
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800514 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
515 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
516 # didn't change, we don't want its signature to change due to the switch
517 # from SHA-1 to SHA-256.
518 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
519 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
520 # that the APK's minSdkVersion is 1.
521 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
522 # determine whether to use SHA-256.
523 min_api_level = None
524 if platform_api_level > 23:
525 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
526 # minSdkVersion attribute
527 min_api_level = None
528 else:
529 # Force APK signer to use SHA-1
530 min_api_level = 1
531
532 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800533 min_api_level=min_api_level,
534 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700535
Tao Bao0c28d2d2017-12-24 10:37:38 -0800536 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100537 if is_compressed:
538 # Recompress the file after it has been signed.
539 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800540 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400541 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100542 shutil.copyfileobj(in_file, out_file)
543
544 data = compressed.read()
545 compressed.close()
546 else:
547 data = signed.read()
548
Doug Zongkereef39442009-04-02 12:14:19 -0700549 unsigned.close()
550 signed.close()
551
552 return data
553
Tianjie5bd03952021-02-18 23:02:36 -0800554
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800555
Kelvin Zhang119f2792021-02-10 12:45:24 -0500556def IsBuildPropFile(filename):
557 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400558 "SYSTEM/etc/prop.default",
559 "BOOT/RAMDISK/prop.default",
560 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500561
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400562 "VENDOR_BOOT/RAMDISK/default.prop",
563 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500564
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400565 # ROOT/default.prop is a legacy path, but may still exist for upgrading
566 # devices that don't support `property_overrides_split_enabled`.
567 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500568
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400569 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
570 # as a symlink in the current code. So it's a no-op here. Keeping the
571 # path here for clarity.
Kelvin Zhang30669e62023-01-10 21:02:02 -0800572 # Some build props might be stored under path
Hongguang Chen1a732332023-01-29 10:51:19 -0800573 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
574 # default.prop can be a symbolic link to prop.default, so overwrite all
575 # files that ends with build.prop, default.prop or prop.default
Kelvin Zhang30669e62023-01-10 21:02:02 -0800576 "RECOVERY/RAMDISK/default.prop") or \
577 filename.endswith("build.prop") or \
Hongguang Chen1a732332023-01-29 10:51:19 -0800578 filename.endswith("/default.prop") or \
579 filename.endswith("/prop.default")
Doug Zongkereef39442009-04-02 12:14:19 -0700580
Tianjie5bd03952021-02-18 23:02:36 -0800581
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800582def ProcessTargetFiles(input_tf_zip: zipfile.ZipFile, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700583 apk_keys, apex_keys, key_passwords,
584 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000585 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700586 # maxsize measures the maximum filename length, including the ones to be
587 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800588 try:
589 maxsize = max(
590 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
591 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
592 except ValueError:
Yi-Yo Chianga4d5f432024-01-24 14:10:17 +0800593 # Sets this to zero for targets without APK files.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800594 maxsize = 0
595
Doug Zongkereef39442009-04-02 12:14:19 -0700596 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700597 filename = info.filename
598 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700599 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700600
Tao Bao04808502019-07-25 23:11:41 -0700601 # Skip OTA-specific images (e.g. split super images), which will be
602 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800603 if filename.startswith("OTA/") and filename.endswith(".img"):
604 continue
605
Tao Bao11f955c2018-06-19 12:19:35 -0700606 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700607 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700608 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
609 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
610
611 if is_apk and should_be_skipped:
612 # Copy skipped APKs verbatim.
613 print(
614 "NOT signing: %s\n"
615 " (skipped due to matching prefix)" % (filename,))
616 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800617
Tao Baof2cffbd2015-07-22 12:33:18 -0700618 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700619 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700620 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100621 if is_compressed:
622 name = name[:-len(compressed_extension)]
623
Tao Baoaa7e9932019-03-15 09:37:01 -0700624 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800625 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800626 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800627 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700628 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700629 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700630 else:
631 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700632 print(
633 "NOT signing: %s\n"
634 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700635 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700636
Tianjie5bd03952021-02-18 23:02:36 -0800637 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700638 elif IsApexFile(filename):
639 name = GetApexFilename(filename)
640
Jooyung Han8caba5e2021-10-27 03:58:09 +0900641 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700642
Tao Baoe1343992019-03-19 12:24:03 -0700643 # We've asserted not having a case with only one of them PRESIGNED.
644 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400645 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700646 print(" signing: %-*s container (%s)" % (
647 maxsize, name, container_key))
648 print(" : %-*s payload (%s)" % (
649 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700650
Tao Baoe7354ba2019-05-09 16:54:15 -0700651 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700652 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700653 data,
654 payload_key,
655 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300656 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800657 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700658 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400659 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900660 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000661 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700662 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700663
Tao Baoe1343992019-03-19 12:24:03 -0700664 else:
665 print(
666 "NOT signing: %s\n"
667 " (skipped due to special cert string)" % (name,))
668 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700669
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800670 elif filename.endswith(".zip") and IsEntryOtaPackage(input_tf_zip, filename):
671 logger.info("Re-signing OTA package {}".format(filename))
672 with tempfile.NamedTemporaryFile() as input_ota, tempfile.NamedTemporaryFile() as output_ota:
673 with input_tf_zip.open(filename, "r") as in_fp:
674 shutil.copyfileobj(in_fp, input_ota)
675 input_ota.flush()
676 SignOtaPackage(input_ota.name, output_ota.name)
677 common.ZipWrite(output_tf_zip, output_ota.name, filename,
678 compress_type=zipfile.ZIP_STORED)
Tao Baoa80ed222016-06-16 14:41:24 -0700679 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500680 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700681 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800682 if stat.S_ISLNK(info.external_attr >> 16):
683 new_data = data
684 else:
Tao Baoa3705452019-06-24 15:33:41 -0700685 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700686 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700687
Tao Bao66472632017-12-04 17:16:36 -0800688 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900689 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700690 elif filename.endswith("mac_permissions.xml"):
691 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700692 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700693 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700694
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700695 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700696 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100697 "VENDOR/recovery-from-boot.p",
698
Tao Bao11f955c2018-06-19 12:19:35 -0700699 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100700 "VENDOR/etc/recovery.img",
701
702 "SYSTEM/bin/install-recovery.sh",
703 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700704 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700705
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700706 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700707 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500708 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800709 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700710
Tao Bao46a59992017-06-05 11:55:16 -0700711 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700712 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700713 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700714
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800715 elif (OPTIONS.remove_avb_public_keys and
716 (filename.startswith("BOOT/RAMDISK/avb/") or
717 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400718 matched_removal = False
719 for key_to_remove in OPTIONS.remove_avb_public_keys:
720 if filename.endswith(key_to_remove):
721 matched_removal = True
722 print("Removing AVB public key from ramdisk: %s" % filename)
723 break
724 if not matched_removal:
725 # Copy it verbatim if we don't want to remove it.
726 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700727
Tianjiebbde59f2021-05-03 21:18:56 -0700728 # Skip the vbmeta digest as we will recalculate it.
729 elif filename == "META/vbmeta_digest.txt":
730 pass
731
Tianjie Xu4f099002016-08-11 18:04:27 -0700732 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400733 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700734 pass
735
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500736 # Skip apex_info.pb because we sign/modify apexes
737 elif filename == "META/apex_info.pb":
738 pass
739
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800740 # Updates system_other.avbpubkey in /product/etc/.
741 elif filename in (
742 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800743 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800744 # Only update system_other's public key, if the corresponding signing
745 # key is specified via --avb_system_other_key.
746 signing_key = OPTIONS.avb_keys.get("system_other")
747 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700748 public_key = common.ExtractAvbPublicKey(
749 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800750 print(" Rewriting AVB public key of system_other in /product")
751 common.ZipWrite(output_tf_zip, public_key, filename)
752
Andrew Scullbbc930b2022-02-17 22:34:27 +0000753 # Updates pvmfw embedded public key with the virt APEX payload key.
754 elif filename == "PREBUILT_IMAGES/pvmfw.img":
755 # Find the name of the virt APEX in the target files.
756 namelist = input_tf_zip.namelist()
757 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
758 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
759 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
760 if not virt_apex:
761 print("Removing %s from ramdisk: virt APEX not found" % filename)
762 else:
763 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
764 # Get the current and new embedded keys.
765 payload_key, container_key, sign_tool = apex_keys[virt_apex]
766 new_pubkey_path = common.ExtractAvbPublicKey(
767 misc_info['avb_avbtool'], payload_key)
768 with open(new_pubkey_path, 'rb') as f:
769 new_pubkey = f.read()
770 pubkey_info = copy.copy(
771 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
772 old_pubkey = input_tf_zip.read(pubkey_info.filename)
773 # Validate the keys and image.
774 if len(old_pubkey) != len(new_pubkey):
775 raise common.ExternalError("pvmfw embedded public key size mismatch")
776 pos = data.find(old_pubkey)
777 if pos == -1:
778 raise common.ExternalError("pvmfw embedded public key not found")
779 # Replace the key and copy new files.
780 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
781 common.ZipWriteStr(output_tf_zip, out_info, new_data)
782 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
783 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
784 pass
785
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800786 # Should NOT sign boot-debug.img.
787 elif filename in (
788 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800789 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800790 raise common.ExternalError("debuggable boot.img cannot be signed")
791
Bowgo Tsai2a781692021-10-13 17:39:33 +0800792 # Should NOT sign userdebug sepolicy file.
793 elif filename in (
794 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
795 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
796 if not OPTIONS.allow_gsi_debug_sepolicy:
797 raise common.ExternalError("debug sepolicy shouldn't be included")
798 else:
799 # Copy it verbatim if we allow the file to exist.
800 common.ZipWriteStr(output_tf_zip, out_info, data)
801
Seungjae Yoo97603562024-02-22 15:34:08 +0900802 # Sign microdroid_vendor.img.
803 elif filename == "VENDOR/etc/avf/microdroid/microdroid_vendor.img":
804 vendor_key = OPTIONS.avb_keys.get("vendor")
805 vendor_algorithm = OPTIONS.avb_algorithms.get("vendor")
806 with tempfile.NamedTemporaryFile() as image:
807 image.write(data)
808 image.flush()
809 ReplaceKeyInAvbHashtreeFooter(image, vendor_key, vendor_algorithm,
810 misc_info)
811 common.ZipWrite(output_tf_zip, image.name, filename)
Tao Baoa80ed222016-06-16 14:41:24 -0700812 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700813 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700814 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700815
Doug Zongker412c02f2014-02-13 10:58:24 -0800816 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700817 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800818
Tao Bao639118f2017-06-19 15:48:02 -0700819 # Replace the AVB signing keys, if any.
820 ReplaceAvbSigningKeys(misc_info)
821
Tao Bao19b02fe2019-10-09 00:04:28 -0700822 # Rewrite the props in AVB signing args.
823 if misc_info.get('avb_enable') == 'true':
824 RewriteAvbProps(misc_info)
825
Tao Bao46a59992017-06-05 11:55:16 -0700826 # Write back misc_info with the latest values.
827 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
828
Seungjae Yoob3456512024-03-11 14:41:22 +0900829# Parse string output of `avbtool info_image`.
830def ParseAvbInfo(info_raw):
831 # line_matcher is for parsing each output line of `avbtool info_image`.
832 # example string input: " Hash Algorithm: sha1"
833 # example matched input: (" ", "Hash Algorithm", "sha1")
834 line_matcher = re.compile(r'^(\s*)([^:]+):\s*(.*)$')
835 # prop_matcher is for parsing value part of 'Prop' in `avbtool info_image`.
836 # example string input: "example_prop_key -> 'example_prop_value'"
837 # example matched output: ("example_prop_key", "example_prop_value")
838 prop_matcher = re.compile(r"(.+)\s->\s'(.+)'")
839 info = {}
840 indent_stack = [[-1, info]]
841 for line_info_raw in info_raw.split('\n'):
842 # Parse the line
843 line_info_parsed = line_matcher.match(line_info_raw)
844 if not line_info_parsed:
845 continue
846 indent = len(line_info_parsed.group(1))
847 key = line_info_parsed.group(2).strip()
848 value = line_info_parsed.group(3).strip()
849
850 # Pop indentation stack
851 while indent <= indent_stack[-1][0]:
852 del indent_stack[-1]
853
854 # Insert information into 'info'.
855 cur_info = indent_stack[-1][1]
856 if value == "":
857 if key == "Descriptors":
858 empty_list = []
859 cur_info[key] = empty_list
860 indent_stack.append([indent, empty_list])
861 else:
862 empty_dict = {}
863 cur_info.append({key:empty_dict})
864 indent_stack.append([indent, empty_dict])
865 elif key == "Prop":
866 prop_parsed = prop_matcher.match(value)
867 if not prop_parsed:
868 raise ValueError(
869 "Failed to parse prop while getting avb information.")
870 cur_info.append({key:{prop_parsed.group(1):prop_parsed.group(2)}})
871 else:
872 cur_info[key] = value
873 return info
874
Seungjae Yoo97603562024-02-22 15:34:08 +0900875def ReplaceKeyInAvbHashtreeFooter(image, new_key, new_algorithm, misc_info):
876 # Get avb information about the image by parsing avbtool info_image.
877 def GetAvbInfo(avbtool, image_name):
878 # Get information with raw string by `avbtool info_image`.
879 info_raw = common.RunAndCheckOutput([
880 avbtool, 'info_image',
881 '--image', image_name
882 ])
Seungjae Yoob3456512024-03-11 14:41:22 +0900883 return ParseAvbInfo(info_raw)
Seungjae Yoo97603562024-02-22 15:34:08 +0900884
885 # Get hashtree descriptor from info
886 def GetAvbHashtreeDescriptor(avb_info):
887 hashtree_descriptors = tuple(filter(lambda x: "Hashtree descriptor" in x,
888 info.get('Descriptors')))
889 if len(hashtree_descriptors) != 1:
890 raise ValueError("The number of hashtree descriptor is not 1.")
891 return hashtree_descriptors[0]["Hashtree descriptor"]
892
893 # Get avb info
894 avbtool = misc_info['avb_avbtool']
895 info = GetAvbInfo(avbtool, image.name)
896 hashtree_descriptor = GetAvbHashtreeDescriptor(info)
897
898 # Generate command
899 cmd = [avbtool, 'add_hashtree_footer',
900 '--key', new_key,
901 '--algorithm', new_algorithm,
902 '--partition_name', hashtree_descriptor.get("Partition Name"),
903 '--partition_size', info.get("Image size").removesuffix(" bytes"),
904 '--hash_algorithm', hashtree_descriptor.get("Hash Algorithm"),
905 '--salt', hashtree_descriptor.get("Salt"),
906 '--do_not_generate_fec',
907 '--image', image.name
908 ]
909
910 # Append properties into command
911 props = map(lambda x: x.get("Prop"), filter(lambda x: "Prop" in x,
912 info.get('Descriptors')))
913 for prop_wrapped in props:
914 prop = tuple(prop_wrapped.items())
915 if len(prop) != 1:
916 raise ValueError("The number of property is not 1.")
917 cmd.append('--prop')
918 cmd.append(prop[0][0] + ':' + prop[0][1])
919
920 # Replace Hashtree Footer with new key
921 common.RunAndCheckOutput(cmd)
922
923 # Check root digest is not changed
924 new_info = GetAvbInfo(avbtool, image.name)
925 new_hashtree_descriptor = GetAvbHashtreeDescriptor(info)
926 root_digest = hashtree_descriptor.get("Root Digest")
927 new_root_digest = new_hashtree_descriptor.get("Root Digest")
928 assert root_digest == new_root_digest, \
929 ("Root digest in hashtree descriptor shouldn't be changed. Old: {}, New: "
930 "{}").format(root_digest, new_root_digest)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700931
Robert Craig817c5742013-04-19 10:59:22 -0400932def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800933 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400934
Tao Bao66472632017-12-04 17:16:36 -0800935 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
936 be skipped. After the replacement, it additionally checks for duplicate
937 entries, which would otherwise fail the policy loading code in
938 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
939
940 Args:
941 data: Input string that contains a set of X.509 certs.
942
943 Returns:
944 A string after the replacement.
945
946 Raises:
947 AssertionError: On finding duplicate entries.
948 """
Tao Baoa3705452019-06-24 15:33:41 -0700949 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800950 if OPTIONS.verbose:
951 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
952
953 try:
954 with open(old + ".x509.pem") as old_fp:
955 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700956 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800957 with open(new + ".x509.pem") as new_fp:
958 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700959 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800960 except IOError as e:
961 if OPTIONS.verbose or e.errno != errno.ENOENT:
962 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
963 "%s.x509.pem." % (e.filename, e.strerror, old, new))
964 continue
965
966 # Only match entire certs.
967 pattern = "\\b" + old_cert16 + "\\b"
968 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
969
970 if OPTIONS.verbose:
971 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
972 num, old, new))
973
974 # Verify that there're no duplicate entries after the replacement. Note that
975 # it's only checking entries with global seinfo at the moment (i.e. ignoring
976 # the ones with inner packages). (Bug: 69479366)
977 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400978 signatures = [signer.attrib['signature']
979 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800980 assert len(signatures) == len(set(signatures)), \
981 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400982
983 return data
984
985
Doug Zongkerc09abc82010-01-11 13:09:15 -0800986def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800987 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
988
989 Args:
990 tags: The input string that contains comma-separated tags.
991
992 Returns:
993 The updated tags (comma-separated and sorted).
994 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800995 tags = set(tags.split(","))
996 for ch in OPTIONS.tag_changes:
997 if ch[0] == "-":
998 tags.discard(ch[1:])
999 elif ch[0] == "+":
1000 tags.add(ch[1:])
1001 return ",".join(sorted(tags))
1002
1003
Tao Baoa7054ee2017-12-08 14:42:16 -08001004def RewriteProps(data):
1005 """Rewrites the system properties in the given string.
1006
1007 Each property is expected in 'key=value' format. The properties that contain
1008 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
1009 EditTags().
1010
1011 Args:
1012 data: Input string, separated by newlines.
1013
1014 Returns:
1015 The string with modified properties.
1016 """
Doug Zongker17aa9442009-04-17 10:15:58 -07001017 output = []
1018 for line in data.split("\n"):
1019 line = line.strip()
1020 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -07001021 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -07001022 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +02001023 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001024 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -08001025 pieces = value.split("/")
1026 pieces[-1] = EditTags(pieces[-1])
1027 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -07001028 elif key == "ro.bootimage.build.fingerprint":
1029 pieces = value.split("/")
1030 pieces[-1] = EditTags(pieces[-1])
1031 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -07001032 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +08001033 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -05001034 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -08001035 pieces[-1] = EditTags(pieces[-1])
1036 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +02001037 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -08001038 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -07001039 elif key == "ro.build.display.id":
1040 # change, eg, "JWR66N dev-keys" to "JWR66N"
1041 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -07001042 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -08001043 value.pop()
1044 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -08001045 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -07001046 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001047 print(" replace: ", original_line)
1048 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -07001049 output.append(line)
1050 return "\n".join(output) + "\n"
1051
1052
Tianjie Xuffbe6b92018-10-19 14:34:15 -07001053def WriteOtacerts(output_zip, filename, keys):
1054 """Constructs a zipfile from given keys; and writes it to output_zip.
1055
1056 Args:
1057 output_zip: The output target_files zip.
1058 filename: The archive name in the output zip.
1059 keys: A list of public keys to use during OTA package verification.
1060 """
Tao Baobb733882019-07-24 23:31:19 -07001061 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -04001062 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -07001063 for k in keys:
1064 common.ZipWrite(certs_zip, k)
Kelvin Zhangf92f7f02023-04-14 21:32:54 +00001065 common.ZipClose(certs_zip)
Tianjie Xuffbe6b92018-10-19 14:34:15 -07001066 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
1067
1068
Doug Zongker831840e2011-09-22 10:28:04 -07001069def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -07001070 try:
1071 keylist = input_tf_zip.read("META/otakeys.txt").split()
1072 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -07001073 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001074
Jacky Liubeb0b692021-12-29 16:29:05 +08001075 extra_ota_keys_info = misc_info.get("extra_ota_keys")
1076 if extra_ota_keys_info:
1077 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
1078 for k in extra_ota_keys_info.split()]
1079 print("extra ota key(s): " + ", ".join(extra_ota_keys))
1080 else:
1081 extra_ota_keys = []
1082 for k in extra_ota_keys:
1083 if not os.path.isfile(k):
1084 raise common.ExternalError(k + " does not exist or is not a file")
1085
1086 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
1087 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -08001088 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +08001089 for k in extra_recovery_keys_info.split()]
1090 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -08001091 else:
1092 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +08001093 for k in extra_recovery_keys:
1094 if not os.path.isfile(k):
1095 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -08001096
Doug Zongker8e931bf2009-04-06 15:21:45 -07001097 mapped_keys = []
1098 for k in keylist:
1099 m = re.match(r"^(.*)\.x509\.pem$", k)
1100 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -08001101 raise common.ExternalError(
1102 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001103 k = m.group(1)
1104 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1105
Doug Zongkere05628c2009-08-20 17:38:42 -07001106 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001107 print("using:\n ", "\n ".join(mapped_keys))
1108 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -07001109 else:
Doug Zongker831840e2011-09-22 10:28:04 -07001110 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001111 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -08001112 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
1113 if mapped_devkey != devkey:
1114 misc_info["default_system_dev_certificate"] = mapped_devkey
1115 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -07001116 print("META/otakeys.txt has no keys; using %s for OTA package"
1117 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +08001118 for k in mapped_keys:
1119 if not os.path.isfile(k):
1120 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001121
Kelvin Zhang9f781ff2021-02-11 19:10:44 -05001122 otacerts = [info
1123 for info in input_tf_zip.infolist()
1124 if info.filename.endswith("/otacerts.zip")]
1125 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +08001126 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
1127 extra_keys = extra_recovery_keys
1128 else:
1129 extra_keys = extra_ota_keys
1130 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1131 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001132
Tao Baoa80ed222016-06-16 14:41:24 -07001133
Tao Bao46a59992017-06-05 11:55:16 -07001134def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1135 """Replaces META/misc_info.txt.
1136
1137 Only writes back the ones in the original META/misc_info.txt. Because the
1138 current in-memory dict contains additional items computed at runtime.
1139 """
1140 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001141 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001142 items = []
1143 for key in sorted(misc_info):
1144 if key in misc_info_old:
1145 items.append('%s=%s' % (key, misc_info[key]))
1146 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001147
Tao Bao8adcfd12016-06-17 17:01:22 -07001148
Tao Bao639118f2017-06-19 15:48:02 -07001149def ReplaceAvbSigningKeys(misc_info):
1150 """Replaces the AVB signing keys."""
1151
Tao Bao639118f2017-06-19 15:48:02 -07001152 def ReplaceAvbPartitionSigningKey(partition):
1153 key = OPTIONS.avb_keys.get(partition)
1154 if not key:
1155 return
1156
1157 algorithm = OPTIONS.avb_algorithms.get(partition)
1158 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1159
Tao Bao0c28d2d2017-12-24 10:37:38 -08001160 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1161 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001162 misc_info['avb_' + partition + '_algorithm'] = algorithm
1163 misc_info['avb_' + partition + '_key_path'] = key
1164
1165 extra_args = OPTIONS.avb_extra_args.get(partition)
1166 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001167 print('Setting extra AVB signing args for %s to "%s"' % (
1168 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001169 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1170 partition,
1171 # custom partition
1172 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001173 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1174
1175 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1176 ReplaceAvbPartitionSigningKey(partition)
1177
Hongguang Chenf23364d2020-04-27 18:36:36 -07001178 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001179 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001180 ReplaceAvbPartitionSigningKey(custom_partition)
1181
Tao Bao639118f2017-06-19 15:48:02 -07001182
Tao Bao19b02fe2019-10-09 00:04:28 -07001183def RewriteAvbProps(misc_info):
1184 """Rewrites the props in AVB signing args."""
1185 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1186 args = misc_info.get(args_key)
1187 if not args:
1188 continue
1189
1190 tokens = []
1191 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001192 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001193 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1194 if not token.startswith(fingerprint_key):
1195 tokens.append(token)
1196 continue
1197 prefix, tag = token.rsplit('/', 1)
1198 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1199 changed = True
1200
1201 if changed:
1202 result = ' '.join(tokens)
1203 print('Rewriting AVB prop for {}:\n'.format(partition))
1204 print(' replace: {}'.format(args))
1205 print(' with: {}'.format(result))
1206 misc_info[args_key] = result
1207
1208
Doug Zongker831840e2011-09-22 10:28:04 -07001209def BuildKeyMap(misc_info, key_mapping_options):
1210 for s, d in key_mapping_options:
1211 if s is None: # -d option
1212 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001213 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001214 devkeydir = os.path.dirname(devkey)
1215
1216 OPTIONS.key_map.update({
1217 devkeydir + "/testkey": d + "/releasekey",
1218 devkeydir + "/devkey": d + "/releasekey",
1219 devkeydir + "/media": d + "/media",
1220 devkeydir + "/shared": d + "/shared",
1221 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001222 devkeydir + "/networkstack": d + "/networkstack",
Cloud You0dbd8772024-01-10 15:12:39 +08001223 devkeydir + "/sdk_sandbox": d + "/sdk_sandbox",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001224 })
Doug Zongker831840e2011-09-22 10:28:04 -07001225 else:
1226 OPTIONS.key_map[s] = d
1227
1228
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001229def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001230 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001231 api_level = None
1232 codename = None
1233 for line in data.split("\n"):
1234 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001235 if line and line[0] != '#' and "=" in line:
1236 key, value = line.split("=", 1)
1237 key = key.strip()
1238 if key == "ro.build.version.sdk":
1239 api_level = int(value.strip())
1240 elif key == "ro.build.version.codename":
1241 codename = value.strip()
1242
1243 if api_level is None:
1244 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1245 if codename is None:
1246 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1247
1248 return (api_level, codename)
1249
1250
1251def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001252 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001253 api_level = None
1254 codenames = None
1255 for line in data.split("\n"):
1256 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001257 if line and line[0] != '#' and "=" in line:
1258 key, value = line.split("=", 1)
1259 key = key.strip()
1260 if key == "ro.build.version.sdk":
1261 api_level = int(value.strip())
1262 elif key == "ro.build.version.all_codenames":
1263 codenames = value.strip().split(",")
1264
1265 if api_level is None:
1266 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1267 if codenames is None:
1268 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1269
Tao Baoa3705452019-06-24 15:33:41 -07001270 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001271 for codename in codenames:
1272 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001273 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001274 result[codename] = api_level
1275 return result
1276
1277
Tao Baoaa7e9932019-03-15 09:37:01 -07001278def ReadApexKeysInfo(tf_zip):
1279 """Parses the APEX keys info from a given target-files zip.
1280
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001281 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1282 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1283 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001284
1285 Args:
1286 tf_zip: The input target_files ZipFile (already open).
1287
1288 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001289 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001290 - payload_key contains the path to the payload signing key
1291 - container_key contains the path to the container signing key
1292 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001293 """
1294 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001295 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001296 line = line.strip()
1297 if not line:
1298 continue
1299 matches = re.match(
1300 r'^name="(?P<NAME>.*)"\s+'
1301 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1302 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1303 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001304 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001305 r'(\s+partition="(?P<PARTITION>.*?)")?'
1306 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001307 line)
1308 if not matches:
1309 continue
1310
1311 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001312 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1313
1314 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1315 pubkey_suffix_len = len(pubkey_suffix)
1316 privkey_suffix_len = len(privkey_suffix)
1317 return (pubkey.endswith(pubkey_suffix) and
1318 privkey.endswith(privkey_suffix) and
1319 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1320
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001321 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001322 # extensions. This doesn't apply to payload keys though, which we will use
1323 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001324 container_cert = matches.group("CONTAINER_CERT")
1325 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001326 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1327 container_key = 'PRESIGNED'
1328 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001329 container_cert, OPTIONS.public_key_suffix,
1330 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001331 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1332 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001333 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001334
Jooyung Han8caba5e2021-10-27 03:58:09 +09001335 sign_tool = matches.group("SIGN_TOOL")
1336 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001337
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001338 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001339
1340
Daniel Norman78554ea2021-09-14 10:29:38 -07001341def BuildVendorPartitions(output_zip_path):
1342 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1343 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1344 logger.warning("Allowed --vendor_partitions: %s",
1345 ",".join(ALLOWED_VENDOR_PARTITIONS))
1346 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1347 OPTIONS.vendor_partitions)
1348
1349 logger.info("Building vendor partitions using vendor otatools.")
1350 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1351 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001352 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001353 "RECOVERY/*",
1354 "BOOT/*",
1355 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001356 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1357
1358 # Disable various partitions that build based on misc_info fields.
1359 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1360 # vendor otatools. These other partitions will be rebuilt using the main
1361 # otatools if necessary.
1362 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1363 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001364 # Ignore if not rebuilding recovery
1365 if not OPTIONS.rebuild_recovery:
1366 vendor_misc_info["no_boot"] = "true" # boot
1367 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1368 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001369 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001370
Daniel Norman78554ea2021-09-14 10:29:38 -07001371 vendor_misc_info["has_dtbo"] = "false" # dtbo
1372 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001373 vendor_misc_info["avb_custom_images_partition_list"] = "" # avb custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001374 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001375 vendor_misc_info["custom_images_partition_list"] = "" # custom images
Daniel Norman78554ea2021-09-14 10:29:38 -07001376 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1377 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001378 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001379 with open(vendor_misc_info_path, "w") as output:
1380 for key in sorted(vendor_misc_info):
1381 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1382
Po Hu0663ae42021-09-27 12:59:06 +08001383 # Disable system partition by a placeholder of IMAGES/system.img,
1384 # instead of removing SYSTEM folder.
1385 # Because SYSTEM/build.prop is still needed for:
1386 # add_img_to_target_files.CreateImage ->
1387 # common.BuildInfo ->
1388 # common.BuildInfo.CalculateFingerprint
1389 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1390 if not os.path.exists(vendor_images_path):
1391 os.makedirs(vendor_images_path)
1392 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1393 pass
1394
Daniel Norman78554ea2021-09-14 10:29:38 -07001395 # Disable care_map.pb as not all ab_partitions are available when
1396 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001397 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1398 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1399 # Disable RADIO images
1400 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1401 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001402
1403 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001404 # Accept either a zip file or extracted directory.
1405 if os.path.isfile(OPTIONS.vendor_otatools):
1406 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1407 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1408 else:
1409 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001410 cmd = [
1411 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1412 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001413 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001414 "--verbose",
1415 vendor_tempdir,
1416 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001417 if OPTIONS.rebuild_recovery:
1418 cmd.insert(4, "--rebuild_recovery")
1419
Daniel Norman78554ea2021-09-14 10:29:38 -07001420 common.RunAndCheckOutput(cmd, verbose=True)
1421
1422 logger.info("Writing vendor partitions to output archive.")
1423 with zipfile.ZipFile(
1424 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1425 allowZip64=True) as output_zip:
1426 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001427 img_file_path = "IMAGES/{}.img".format(p)
1428 map_file_path = "IMAGES/{}.map".format(p)
1429 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001430 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1431 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001432 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001433 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001434 recovery_img = "IMAGES/recovery.img"
1435 boot_img = "IMAGES/boot.img"
1436 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1437 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001438 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1439 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1440 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1441 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001442
1443
Doug Zongkereef39442009-04-02 12:14:19 -07001444def main(argv):
1445
Doug Zongker831840e2011-09-22 10:28:04 -07001446 key_mapping_options = []
1447
Doug Zongkereef39442009-04-02 12:14:19 -07001448 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001449 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001450 names, key = a.split("=")
1451 names = names.split(",")
1452 for n in names:
1453 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001454 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001455 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001456 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001457 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001458 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001459 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001460 prefix = a.split('/')[0]
1461 if not prefix or prefix != prefix.upper():
1462 raise ValueError("Invalid path prefix '%s'" % (a,))
1463 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001464 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001465 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001466 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001467 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001468 elif o in ("-o", "--replace_ota_keys"):
1469 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001470 elif o in ("-t", "--tag_changes"):
1471 new = []
1472 for i in a.split(","):
1473 i = i.strip()
1474 if not i or i[0] not in "-+":
1475 raise ValueError("Bad tag change '%s'" % (i,))
1476 new.append(i[0] + i[1:].strip())
1477 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001478 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001479 raise ValueError("--replace_verity_public_key is no longer supported,"
1480 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001481 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001482 raise ValueError("--replace_verity_private_key is no longer supported,"
1483 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001484 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001485 raise ValueError("--replace_verity_keyid is no longer supported, please"
1486 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001487 elif o == "--remove_avb_public_keys":
1488 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001489 elif o == "--avb_vbmeta_key":
1490 OPTIONS.avb_keys['vbmeta'] = a
1491 elif o == "--avb_vbmeta_algorithm":
1492 OPTIONS.avb_algorithms['vbmeta'] = a
1493 elif o == "--avb_vbmeta_extra_args":
1494 OPTIONS.avb_extra_args['vbmeta'] = a
1495 elif o == "--avb_boot_key":
1496 OPTIONS.avb_keys['boot'] = a
1497 elif o == "--avb_boot_algorithm":
1498 OPTIONS.avb_algorithms['boot'] = a
1499 elif o == "--avb_boot_extra_args":
1500 OPTIONS.avb_extra_args['boot'] = a
1501 elif o == "--avb_dtbo_key":
1502 OPTIONS.avb_keys['dtbo'] = a
1503 elif o == "--avb_dtbo_algorithm":
1504 OPTIONS.avb_algorithms['dtbo'] = a
1505 elif o == "--avb_dtbo_extra_args":
1506 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001507 elif o == "--avb_init_boot_key":
1508 OPTIONS.avb_keys['init_boot'] = a
1509 elif o == "--avb_init_boot_algorithm":
1510 OPTIONS.avb_algorithms['init_boot'] = a
1511 elif o == "--avb_init_boot_extra_args":
1512 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001513 elif o == "--avb_recovery_key":
1514 OPTIONS.avb_keys['recovery'] = a
1515 elif o == "--avb_recovery_algorithm":
1516 OPTIONS.avb_algorithms['recovery'] = a
1517 elif o == "--avb_recovery_extra_args":
1518 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001519 elif o == "--avb_system_key":
1520 OPTIONS.avb_keys['system'] = a
1521 elif o == "--avb_system_algorithm":
1522 OPTIONS.avb_algorithms['system'] = a
1523 elif o == "--avb_system_extra_args":
1524 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001525 elif o == "--avb_system_other_key":
1526 OPTIONS.avb_keys['system_other'] = a
1527 elif o == "--avb_system_other_algorithm":
1528 OPTIONS.avb_algorithms['system_other'] = a
1529 elif o == "--avb_system_other_extra_args":
1530 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001531 elif o == "--avb_vendor_key":
1532 OPTIONS.avb_keys['vendor'] = a
1533 elif o == "--avb_vendor_algorithm":
1534 OPTIONS.avb_algorithms['vendor'] = a
1535 elif o == "--avb_vendor_extra_args":
1536 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001537 elif o == "--avb_vbmeta_system_key":
1538 OPTIONS.avb_keys['vbmeta_system'] = a
1539 elif o == "--avb_vbmeta_system_algorithm":
1540 OPTIONS.avb_algorithms['vbmeta_system'] = a
1541 elif o == "--avb_vbmeta_system_extra_args":
1542 OPTIONS.avb_extra_args['vbmeta_system'] = a
1543 elif o == "--avb_vbmeta_vendor_key":
1544 OPTIONS.avb_keys['vbmeta_vendor'] = a
1545 elif o == "--avb_vbmeta_vendor_algorithm":
1546 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1547 elif o == "--avb_vbmeta_vendor_extra_args":
1548 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001549 elif o == "--avb_apex_extra_args":
1550 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001551 elif o == "--avb_extra_custom_image_key":
1552 partition, key = a.split("=")
1553 OPTIONS.avb_keys[partition] = key
1554 elif o == "--avb_extra_custom_image_algorithm":
1555 partition, algorithm = a.split("=")
1556 OPTIONS.avb_algorithms[partition] = algorithm
1557 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001558 # Setting the maxsplit parameter to one, which will return a list with
1559 # two elements. e.g., the second '=' should not be splitted for
1560 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1561 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001562 OPTIONS.avb_extra_args[partition] = extra_args
Daniel Norman78554ea2021-09-14 10:29:38 -07001563 elif o == "--vendor_otatools":
1564 OPTIONS.vendor_otatools = a
1565 elif o == "--vendor_partitions":
1566 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001567 elif o == "--allow_gsi_debug_sepolicy":
1568 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001569 elif o == "--override_apk_keys":
1570 OPTIONS.override_apk_keys = a
1571 elif o == "--override_apex_keys":
1572 OPTIONS.override_apex_keys = a
Yi-Yo Chianga4d5f432024-01-24 14:10:17 +08001573 elif o in ("--gki_signing_key", "--gki_signing_algorithm", "--gki_signing_extra_args"):
1574 print(f"{o} is deprecated and does nothing")
Doug Zongkereef39442009-04-02 12:14:19 -07001575 else:
1576 return False
1577 return True
1578
Tao Bao639118f2017-06-19 15:48:02 -07001579 args = common.ParseOptions(
1580 argv, __doc__,
1581 extra_opts="e:d:k:ot:",
1582 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001583 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001584 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001585 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001586 "default_key_mappings=",
1587 "key_mapping=",
1588 "replace_ota_keys",
1589 "tag_changes=",
1590 "replace_verity_public_key=",
1591 "replace_verity_private_key=",
1592 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001593 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001594 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001595 "avb_vbmeta_algorithm=",
1596 "avb_vbmeta_key=",
1597 "avb_vbmeta_extra_args=",
1598 "avb_boot_algorithm=",
1599 "avb_boot_key=",
1600 "avb_boot_extra_args=",
1601 "avb_dtbo_algorithm=",
1602 "avb_dtbo_key=",
1603 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001604 "avb_init_boot_algorithm=",
1605 "avb_init_boot_key=",
1606 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001607 "avb_recovery_algorithm=",
1608 "avb_recovery_key=",
1609 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001610 "avb_system_algorithm=",
1611 "avb_system_key=",
1612 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001613 "avb_system_other_algorithm=",
1614 "avb_system_other_key=",
1615 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001616 "avb_vendor_algorithm=",
1617 "avb_vendor_key=",
1618 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001619 "avb_vbmeta_system_algorithm=",
1620 "avb_vbmeta_system_key=",
1621 "avb_vbmeta_system_extra_args=",
1622 "avb_vbmeta_vendor_algorithm=",
1623 "avb_vbmeta_vendor_key=",
1624 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001625 "avb_extra_custom_image_key=",
1626 "avb_extra_custom_image_algorithm=",
1627 "avb_extra_custom_image_extra_args=",
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001628 "gki_signing_key=",
1629 "gki_signing_algorithm=",
1630 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001631 "vendor_partitions=",
1632 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001633 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001634 "override_apk_keys=",
1635 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001636 ],
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001637 extra_option_handler=[option_handler, payload_signer.signer_options])
Doug Zongkereef39442009-04-02 12:14:19 -07001638
1639 if len(args) != 2:
1640 common.Usage(__doc__)
1641 sys.exit(1)
1642
Tao Baobadceb22019-03-15 09:33:43 -07001643 common.InitLogging()
1644
Kelvin Zhang928c2342020-09-22 16:15:57 -04001645 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001646 output_zip = zipfile.ZipFile(args[1], "w",
1647 compression=zipfile.ZIP_DEFLATED,
1648 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001649
Doug Zongker831840e2011-09-22 10:28:04 -07001650 misc_info = common.LoadInfoDict(input_zip)
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001651 if OPTIONS.package_key is None:
1652 OPTIONS.package_key = misc_info.get(
1653 "default_system_dev_certificate",
1654 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001655
1656 BuildKeyMap(misc_info, key_mapping_options)
1657
Tao Baoaa7e9932019-03-15 09:37:01 -07001658 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1659 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001660
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001661 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001662 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1663
Tianjie Xu88a759d2020-01-23 10:47:54 -08001664 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1665 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001666 CheckApkAndApexKeysAvailable(
1667 input_zip,
1668 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001669 compressed_extension,
1670 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001671
1672 key_passwords = common.GetKeyPasswords(
1673 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001674 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001675 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001676
Doug Zongker412c02f2014-02-13 10:58:24 -08001677 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001678 apk_keys, apex_keys, key_passwords,
1679 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001680 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001681
Kelvin Zhangf92f7f02023-04-14 21:32:54 +00001682 common.ZipClose(input_zip)
1683 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001684
Daniel Norman78554ea2021-09-14 10:29:38 -07001685 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1686 BuildVendorPartitions(args[1])
1687
Tianjie Xub48589a2016-08-03 19:21:52 -07001688 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001689 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001690 # add_img_to_target_files builds the system image from scratch, so the
1691 # recovery patch is guaranteed to be regenerated there.
1692 if OPTIONS.rebuild_recovery:
1693 new_args.append("--rebuild_recovery")
1694 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001695 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001696
Tao Bao0c28d2d2017-12-24 10:37:38 -08001697 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001698
1699
1700if __name__ == '__main__':
1701 try:
1702 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001703 finally:
1704 common.Cleanup()