blob: 7b497c1f93ab226a0dbe6bd9ec81bd3583c13675 [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>
127 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
128 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
129 in info dict.
130
131 --gki_signing_extra_args <args>
132 Specify any additional args that are needed to generate 'boot signature'
133 (e.g. --prop foo:bar). The args will be appended to the existing ones
134 in info dict.
135
Tianjie Xu88a759d2020-01-23 10:47:54 -0800136 --android_jar_path <path>
137 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800138
139 --allow_gsi_debug_sepolicy
140 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
141 (/system/system_ext|/system_ext)/etc/selinux.
142 If not set, error out when the file exists.
Kelvin Zhange50bb512022-08-01 15:58:51 -0700143
144 --override_apk_keys <path>
145 Replace all APK keys with this private key
146
147 --override_apex_keys <path>
148 Replace all APEX keys with this private key
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800149
150 -k (--package_key) <key>
151 Key to use to sign the package (default is the value of
152 default_system_dev_certificate from the input target-files's
153 META/misc_info.txt, or "build/make/target/product/security/testkey" if
154 that value is not specified).
155
156 For incremental OTAs, the default value is based on the source
157 target-file, not the target build.
158
159 --payload_signer <signer>
160 Specify the signer when signing the payload and metadata for A/B OTAs.
161 By default (i.e. without this flag), it calls 'openssl pkeyutl' to sign
162 with the package private key. If the private key cannot be accessed
163 directly, a payload signer that knows how to do that should be specified.
164 The signer will be supplied with "-inkey <path_to_key>",
165 "-in <input_file>" and "-out <output_file>" parameters.
166
167 --payload_signer_args <args>
168 Specify the arguments needed for payload signer.
169
170 --payload_signer_maximum_signature_size <signature_size>
171 The maximum signature size (in bytes) that would be generated by the given
172 payload signer. Only meaningful when custom payload signer is specified
173 via '--payload_signer'.
174 If the signer uses a RSA key, this should be the number of bytes to
175 represent the modulus. If it uses an EC key, this is the size of a
176 DER-encoded ECDSA signature.
Doug Zongkereef39442009-04-02 12:14:19 -0700177"""
178
Tao Bao0c28d2d2017-12-24 10:37:38 -0800179from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700180
Robert Craig817c5742013-04-19 10:59:22 -0400181import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700182import copy
Robert Craig817c5742013-04-19 10:59:22 -0400183import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100184import gzip
Tao Baobb733882019-07-24 23:31:19 -0700185import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700186import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700187import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700188import os
189import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100190import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700191import stat
Tao Bao0c28d2d2017-12-24 10:37:38 -0800192import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700193import tempfile
194import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800195from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700196
Doug Zongker3c84f562014-07-31 11:06:30 -0700197import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700198import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700199import common
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800200import payload_signer
201from payload_signer import SignOtaPackage, PAYLOAD_BIN
Doug Zongkereef39442009-04-02 12:14:19 -0700202
Tao Bao0c28d2d2017-12-24 10:37:38 -0800203
204if sys.hexversion < 0x02070000:
205 print("Python 2.7 or newer is required.", file=sys.stderr)
206 sys.exit(1)
207
208
Tao Baobadceb22019-03-15 09:33:43 -0700209logger = logging.getLogger(__name__)
210
Doug Zongkereef39442009-04-02 12:14:19 -0700211OPTIONS = common.OPTIONS
212
213OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700214OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700215OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700216OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700217OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700218OPTIONS.replace_ota_keys = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800219OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700220OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700221OPTIONS.avb_keys = {}
222OPTIONS.avb_algorithms = {}
223OPTIONS.avb_extra_args = {}
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000224OPTIONS.gki_signing_key = None
225OPTIONS.gki_signing_algorithm = None
226OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800227OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700228OPTIONS.vendor_partitions = set()
229OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800230OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700231OPTIONS.override_apk_keys = None
232OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700233
Tao Bao0c28d2d2017-12-24 10:37:38 -0800234
Tao Bao19b02fe2019-10-09 00:04:28 -0700235AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800236 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000237 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800238 'dtbo': 'avb_dtbo_add_hash_footer_args',
239 'product': 'avb_product_add_hashtree_footer_args',
240 'recovery': 'avb_recovery_add_hash_footer_args',
241 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000242 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800243 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
244 'system_other': 'avb_system_other_add_hashtree_footer_args',
245 'odm': 'avb_odm_add_hashtree_footer_args',
246 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
247 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
248 'vendor': 'avb_vendor_add_hashtree_footer_args',
249 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800250 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800251 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
252 'vbmeta': 'avb_vbmeta_args',
253 'vbmeta_system': 'avb_vbmeta_system_args',
254 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700255}
256
257
Tianjiebf0b8a82021-03-03 17:31:04 -0800258# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
259for partition in common.AVB_PARTITIONS:
260 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
261 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
262
Daniel Norman78554ea2021-09-14 10:29:38 -0700263# Partitions that can be regenerated after signing using a separate
264# vendor otatools package.
265ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
266
Tianjiebf0b8a82021-03-03 17:31:04 -0800267
Tianjie4d48d502021-06-11 17:03:43 -0700268def IsApexFile(filename):
269 return filename.endswith(".apex") or filename.endswith(".capex")
270
271
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800272def IsOtaPackage(fp):
273 with zipfile.ZipFile(fp) as zfp:
274 if not PAYLOAD_BIN in zfp.namelist():
275 return False
276 with zfp.open(PAYLOAD_BIN, "r") as payload:
277 magic = payload.read(4)
278 return magic == b"CrAU"
279
280
281def IsEntryOtaPackage(input_zip, filename):
282 with input_zip.open(filename, "r") as fp:
283 return IsOtaPackage(fp)
284
285
Tianjie4d48d502021-06-11 17:03:43 -0700286def GetApexFilename(filename):
287 name = os.path.basename(filename)
288 # Replace the suffix for compressed apex
289 if name.endswith(".capex"):
290 return name.replace(".capex", ".apex")
291 return name
292
293
Narayan Kamatha07bf042017-08-14 14:49:21 +0100294def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700295 if OPTIONS.override_apk_keys is not None:
296 for apk in certmap.keys():
297 certmap[apk] = OPTIONS.override_apk_keys
298
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800299 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700300 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800301 certmap[apk] = OPTIONS.key_map.get(cert, cert)
302
303 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700304 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800305 if not cert:
306 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700307 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800308
Doug Zongkereef39442009-04-02 12:14:19 -0700309 return certmap
310
311
Tao Baoaa7e9932019-03-15 09:37:01 -0700312def GetApexKeys(keys_info, key_map):
313 """Gets APEX payload and container signing keys by applying the mapping rules.
314
Tao Baoe1343992019-03-19 12:24:03 -0700315 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700316
317 Args:
318 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900319 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700320 key_map: A dict that overrides the keys, specified via command-line input.
321
322 Returns:
323 A dict that contains the updated APEX key mapping, which should be used for
324 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700325
326 Raises:
327 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700328 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700329 if OPTIONS.override_apex_keys is not None:
330 for apex in keys_info.keys():
331 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
332
333 if OPTIONS.override_apk_keys is not None:
334 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
335 for apex in keys_info.keys():
336 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
337
Tao Baoaa7e9932019-03-15 09:37:01 -0700338 # Apply all the --extra_apex_payload_key options to override the payload
339 # signing keys in the given keys_info.
340 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700341 if not key:
342 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700343 if apex not in keys_info:
344 logger.warning('Failed to find %s in target_files; Ignored', apex)
345 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900346 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700347
348 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900349 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
350 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700351
352 # Apply all the --extra_apks options to override the container keys.
353 for apex, key in OPTIONS.extra_apks.items():
354 # Skip non-APEX containers.
355 if apex not in keys_info:
356 continue
Tao Baoe1343992019-03-19 12:24:03 -0700357 if not key:
358 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900359 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700360
Tao Baof98fa102019-04-24 14:51:25 -0700361 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
362 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
363 # (overridden via commandline) indicates a config error, which should not be
364 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900365 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700366 if container_key != 'PRESIGNED':
367 continue
368 if apex in OPTIONS.extra_apex_payload_keys:
369 payload_override = OPTIONS.extra_apex_payload_keys[apex]
370 assert payload_override == '', \
371 ("Invalid APEX key overrides: {} has PRESIGNED container but "
372 "non-PRESIGNED payload key {}").format(apex, payload_override)
373 if payload_key != 'PRESIGNED':
374 print(
375 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
376 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900377 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700378
Tao Baoaa7e9932019-03-15 09:37:01 -0700379 return keys_info
380
381
Tao Bao93c2a012018-06-19 12:19:35 -0700382def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700383 """Returns the APK info based on the given filename.
384
385 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700386 compressed extension into consideration. If it appears to be an APK file,
387 further checks if the APK file should be skipped when signing, based on the
388 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700389
390 Args:
391 filename: Path to the file.
392 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
393 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700394 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700395
396 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700397 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
398 given filename is an APK file. is_compressed indicates whether the APK file
399 is compressed (only meaningful when is_apk is True). should_be_skipped
400 indicates whether the filename matches any of the given prefixes to be
401 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700402
403 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700404 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700405 """
406 assert compressed_extension is None or compressed_extension.startswith('.'), \
407 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
408
Tao Bao93c2a012018-06-19 12:19:35 -0700409 # skipped_prefixes should be one of set/list/tuple types. Other types such as
410 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700411 assert isinstance(skipped_prefixes, (set, list, tuple)), \
412 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700413
Tao Bao11f955c2018-06-19 12:19:35 -0700414 compressed_apk_extension = (
415 ".apk" + compressed_extension if compressed_extension else None)
416 is_apk = (filename.endswith(".apk") or
417 (compressed_apk_extension and
418 filename.endswith(compressed_apk_extension)))
419 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700420 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700421
422 is_compressed = (compressed_apk_extension and
423 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700424 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
425 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700426
427
Tao Baoaa7e9932019-03-15 09:37:01 -0700428def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700429 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700430 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700431
432 Args:
433 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700434 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700435 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700436 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700437 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900438 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700439
440 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700441 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700442 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700443 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700444 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800445 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700446 if IsApexFile(info.filename):
447 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700448 if name not in known_keys:
449 unknown_files.append(name)
450 continue
451
452 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700453 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
454 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
455 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700456 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700457
Tao Bao11f955c2018-06-19 12:19:35 -0700458 name = os.path.basename(info.filename)
459 if is_compressed:
460 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700461 if name not in known_keys:
462 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700463
Tao Baoaa7e9932019-03-15 09:37:01 -0700464 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700465 ("No key specified for:\n {}\n"
466 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700467 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700468
Tao Baoe1343992019-03-19 12:24:03 -0700469 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700470 # one of the payload / container keys set. Note that non-PRESIGNED container
471 # with PRESIGNED payload could be allowed but currently unsupported. It would
472 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700473 if not apex_keys:
474 return
475
476 invalid_apexes = []
477 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700478 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700479 continue
480
Tianjie4d48d502021-06-11 17:03:43 -0700481 name = GetApexFilename(info.filename)
482
Jooyung Han8caba5e2021-10-27 03:58:09 +0900483 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700484 if ((payload_key in common.SPECIAL_CERT_STRINGS and
485 container_key not in common.SPECIAL_CERT_STRINGS) or
486 (payload_key not in common.SPECIAL_CERT_STRINGS and
487 container_key in common.SPECIAL_CERT_STRINGS)):
488 invalid_apexes.append(
489 "{}: payload_key {}, container_key {}".format(
490 name, payload_key, container_key))
491
492 assert not invalid_apexes, \
493 "Invalid APEX keys specified:\n {}\n".format(
494 "\n ".join(invalid_apexes))
495
Doug Zongkereb338ef2009-05-20 16:50:49 -0700496
Narayan Kamatha07bf042017-08-14 14:49:21 +0100497def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700498 is_compressed, apk_name):
499 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700500 unsigned.write(data)
501 unsigned.flush()
502
Narayan Kamatha07bf042017-08-14 14:49:21 +0100503 if is_compressed:
504 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800505 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400506 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100507 shutil.copyfileobj(in_file, out_file)
508
509 # Finally, close the "unsigned" file (which is gzip compressed), and then
510 # replace it with the uncompressed version.
511 #
512 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
513 # we could just gzip / gunzip in-memory buffers instead.
514 unsigned.close()
515 unsigned = uncompressed
516
Oleg Aravin8046cb02020-06-02 16:02:38 -0700517 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700518
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800519 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
520 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
521 # didn't change, we don't want its signature to change due to the switch
522 # from SHA-1 to SHA-256.
523 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
524 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
525 # that the APK's minSdkVersion is 1.
526 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
527 # determine whether to use SHA-256.
528 min_api_level = None
529 if platform_api_level > 23:
530 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
531 # minSdkVersion attribute
532 min_api_level = None
533 else:
534 # Force APK signer to use SHA-1
535 min_api_level = 1
536
537 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800538 min_api_level=min_api_level,
539 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700540
Tao Bao0c28d2d2017-12-24 10:37:38 -0800541 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100542 if is_compressed:
543 # Recompress the file after it has been signed.
544 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800545 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400546 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100547 shutil.copyfileobj(in_file, out_file)
548
549 data = compressed.read()
550 compressed.close()
551 else:
552 data = signed.read()
553
Doug Zongkereef39442009-04-02 12:14:19 -0700554 unsigned.close()
555 signed.close()
556
557 return data
558
Tianjie5bd03952021-02-18 23:02:36 -0800559
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800560
Kelvin Zhang119f2792021-02-10 12:45:24 -0500561def IsBuildPropFile(filename):
562 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400563 "SYSTEM/etc/prop.default",
564 "BOOT/RAMDISK/prop.default",
565 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500566
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400567 "VENDOR_BOOT/RAMDISK/default.prop",
568 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500569
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400570 # ROOT/default.prop is a legacy path, but may still exist for upgrading
571 # devices that don't support `property_overrides_split_enabled`.
572 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500573
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400574 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
575 # as a symlink in the current code. So it's a no-op here. Keeping the
576 # path here for clarity.
Kelvin Zhang30669e62023-01-10 21:02:02 -0800577 # Some build props might be stored under path
Hongguang Chen1a732332023-01-29 10:51:19 -0800578 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
579 # default.prop can be a symbolic link to prop.default, so overwrite all
580 # files that ends with build.prop, default.prop or prop.default
Kelvin Zhang30669e62023-01-10 21:02:02 -0800581 "RECOVERY/RAMDISK/default.prop") or \
582 filename.endswith("build.prop") or \
Hongguang Chen1a732332023-01-29 10:51:19 -0800583 filename.endswith("/default.prop") or \
584 filename.endswith("/prop.default")
Doug Zongkereef39442009-04-02 12:14:19 -0700585
Tianjie5bd03952021-02-18 23:02:36 -0800586
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800587def ProcessTargetFiles(input_tf_zip: zipfile.ZipFile, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700588 apk_keys, apex_keys, key_passwords,
589 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000590 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700591 # maxsize measures the maximum filename length, including the ones to be
592 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800593 try:
594 maxsize = max(
595 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
596 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
597 except ValueError:
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000598 # Sets this to zero for targets without APK files, e.g., gki_arm64.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800599 maxsize = 0
600
Doug Zongkereef39442009-04-02 12:14:19 -0700601 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700602 filename = info.filename
603 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700604 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700605
Tao Bao04808502019-07-25 23:11:41 -0700606 # Skip OTA-specific images (e.g. split super images), which will be
607 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800608 if filename.startswith("OTA/") and filename.endswith(".img"):
609 continue
610
Tao Bao11f955c2018-06-19 12:19:35 -0700611 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700612 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700613 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
614 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
615
616 if is_apk and should_be_skipped:
617 # Copy skipped APKs verbatim.
618 print(
619 "NOT signing: %s\n"
620 " (skipped due to matching prefix)" % (filename,))
621 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800622
Tao Baof2cffbd2015-07-22 12:33:18 -0700623 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700624 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700625 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100626 if is_compressed:
627 name = name[:-len(compressed_extension)]
628
Tao Baoaa7e9932019-03-15 09:37:01 -0700629 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800630 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800631 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800632 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700633 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700634 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700635 else:
636 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700637 print(
638 "NOT signing: %s\n"
639 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700640 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700641
Tianjie5bd03952021-02-18 23:02:36 -0800642 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700643 elif IsApexFile(filename):
644 name = GetApexFilename(filename)
645
Jooyung Han8caba5e2021-10-27 03:58:09 +0900646 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700647
Tao Baoe1343992019-03-19 12:24:03 -0700648 # We've asserted not having a case with only one of them PRESIGNED.
649 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400650 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700651 print(" signing: %-*s container (%s)" % (
652 maxsize, name, container_key))
653 print(" : %-*s payload (%s)" % (
654 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700655
Tao Baoe7354ba2019-05-09 16:54:15 -0700656 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700657 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700658 data,
659 payload_key,
660 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300661 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800662 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700663 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400664 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900665 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000666 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700667 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700668
Tao Baoe1343992019-03-19 12:24:03 -0700669 else:
670 print(
671 "NOT signing: %s\n"
672 " (skipped due to special cert string)" % (name,))
673 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700674
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -0800675 elif filename.endswith(".zip") and IsEntryOtaPackage(input_tf_zip, filename):
676 logger.info("Re-signing OTA package {}".format(filename))
677 with tempfile.NamedTemporaryFile() as input_ota, tempfile.NamedTemporaryFile() as output_ota:
678 with input_tf_zip.open(filename, "r") as in_fp:
679 shutil.copyfileobj(in_fp, input_ota)
680 input_ota.flush()
681 SignOtaPackage(input_ota.name, output_ota.name)
682 common.ZipWrite(output_tf_zip, output_ota.name, filename,
683 compress_type=zipfile.ZIP_STORED)
Tao Baoa80ed222016-06-16 14:41:24 -0700684 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500685 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700686 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800687 if stat.S_ISLNK(info.external_attr >> 16):
688 new_data = data
689 else:
Tao Baoa3705452019-06-24 15:33:41 -0700690 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700691 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700692
Tao Bao66472632017-12-04 17:16:36 -0800693 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900694 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700695 elif filename.endswith("mac_permissions.xml"):
696 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700697 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700698 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700699
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700700 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700701 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100702 "VENDOR/recovery-from-boot.p",
703
Tao Bao11f955c2018-06-19 12:19:35 -0700704 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100705 "VENDOR/etc/recovery.img",
706
707 "SYSTEM/bin/install-recovery.sh",
708 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700709 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700710
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700711 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700712 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500713 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800714 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700715
Tao Bao46a59992017-06-05 11:55:16 -0700716 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700717 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700718 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700719
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800720 elif (OPTIONS.remove_avb_public_keys and
721 (filename.startswith("BOOT/RAMDISK/avb/") or
722 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400723 matched_removal = False
724 for key_to_remove in OPTIONS.remove_avb_public_keys:
725 if filename.endswith(key_to_remove):
726 matched_removal = True
727 print("Removing AVB public key from ramdisk: %s" % filename)
728 break
729 if not matched_removal:
730 # Copy it verbatim if we don't want to remove it.
731 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700732
Tianjiebbde59f2021-05-03 21:18:56 -0700733 # Skip the vbmeta digest as we will recalculate it.
734 elif filename == "META/vbmeta_digest.txt":
735 pass
736
Tianjie Xu4f099002016-08-11 18:04:27 -0700737 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400738 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700739 pass
740
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500741 # Skip apex_info.pb because we sign/modify apexes
742 elif filename == "META/apex_info.pb":
743 pass
744
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800745 # Updates system_other.avbpubkey in /product/etc/.
746 elif filename in (
747 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800748 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800749 # Only update system_other's public key, if the corresponding signing
750 # key is specified via --avb_system_other_key.
751 signing_key = OPTIONS.avb_keys.get("system_other")
752 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700753 public_key = common.ExtractAvbPublicKey(
754 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800755 print(" Rewriting AVB public key of system_other in /product")
756 common.ZipWrite(output_tf_zip, public_key, filename)
757
Andrew Scullbbc930b2022-02-17 22:34:27 +0000758 # Updates pvmfw embedded public key with the virt APEX payload key.
759 elif filename == "PREBUILT_IMAGES/pvmfw.img":
760 # Find the name of the virt APEX in the target files.
761 namelist = input_tf_zip.namelist()
762 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
763 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
764 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
765 if not virt_apex:
766 print("Removing %s from ramdisk: virt APEX not found" % filename)
767 else:
768 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
769 # Get the current and new embedded keys.
770 payload_key, container_key, sign_tool = apex_keys[virt_apex]
771 new_pubkey_path = common.ExtractAvbPublicKey(
772 misc_info['avb_avbtool'], payload_key)
773 with open(new_pubkey_path, 'rb') as f:
774 new_pubkey = f.read()
775 pubkey_info = copy.copy(
776 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
777 old_pubkey = input_tf_zip.read(pubkey_info.filename)
778 # Validate the keys and image.
779 if len(old_pubkey) != len(new_pubkey):
780 raise common.ExternalError("pvmfw embedded public key size mismatch")
781 pos = data.find(old_pubkey)
782 if pos == -1:
783 raise common.ExternalError("pvmfw embedded public key not found")
784 # Replace the key and copy new files.
785 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
786 common.ZipWriteStr(output_tf_zip, out_info, new_data)
787 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
788 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
789 pass
790
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800791 # Should NOT sign boot-debug.img.
792 elif filename in (
793 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800794 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800795 raise common.ExternalError("debuggable boot.img cannot be signed")
796
Bowgo Tsai2a781692021-10-13 17:39:33 +0800797 # Should NOT sign userdebug sepolicy file.
798 elif filename in (
799 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
800 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
801 if not OPTIONS.allow_gsi_debug_sepolicy:
802 raise common.ExternalError("debug sepolicy shouldn't be included")
803 else:
804 # Copy it verbatim if we allow the file to exist.
805 common.ZipWriteStr(output_tf_zip, out_info, data)
806
Tao Baoa80ed222016-06-16 14:41:24 -0700807 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700808 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700809 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700810
Doug Zongker412c02f2014-02-13 10:58:24 -0800811 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700812 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800813
Tao Bao639118f2017-06-19 15:48:02 -0700814 # Replace the AVB signing keys, if any.
815 ReplaceAvbSigningKeys(misc_info)
816
Tao Bao19b02fe2019-10-09 00:04:28 -0700817 # Rewrite the props in AVB signing args.
818 if misc_info.get('avb_enable') == 'true':
819 RewriteAvbProps(misc_info)
820
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000821 # Replace the GKI signing key for boot.img, if any.
822 ReplaceGkiSigningKey(misc_info)
823
Tao Bao46a59992017-06-05 11:55:16 -0700824 # Write back misc_info with the latest values.
825 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
826
Doug Zongker8e931bf2009-04-06 15:21:45 -0700827
Robert Craig817c5742013-04-19 10:59:22 -0400828def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800829 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400830
Tao Bao66472632017-12-04 17:16:36 -0800831 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
832 be skipped. After the replacement, it additionally checks for duplicate
833 entries, which would otherwise fail the policy loading code in
834 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
835
836 Args:
837 data: Input string that contains a set of X.509 certs.
838
839 Returns:
840 A string after the replacement.
841
842 Raises:
843 AssertionError: On finding duplicate entries.
844 """
Tao Baoa3705452019-06-24 15:33:41 -0700845 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800846 if OPTIONS.verbose:
847 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
848
849 try:
850 with open(old + ".x509.pem") as old_fp:
851 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700852 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800853 with open(new + ".x509.pem") as new_fp:
854 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700855 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800856 except IOError as e:
857 if OPTIONS.verbose or e.errno != errno.ENOENT:
858 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
859 "%s.x509.pem." % (e.filename, e.strerror, old, new))
860 continue
861
862 # Only match entire certs.
863 pattern = "\\b" + old_cert16 + "\\b"
864 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
865
866 if OPTIONS.verbose:
867 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
868 num, old, new))
869
870 # Verify that there're no duplicate entries after the replacement. Note that
871 # it's only checking entries with global seinfo at the moment (i.e. ignoring
872 # the ones with inner packages). (Bug: 69479366)
873 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400874 signatures = [signer.attrib['signature']
875 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800876 assert len(signatures) == len(set(signatures)), \
877 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400878
879 return data
880
881
Doug Zongkerc09abc82010-01-11 13:09:15 -0800882def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800883 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
884
885 Args:
886 tags: The input string that contains comma-separated tags.
887
888 Returns:
889 The updated tags (comma-separated and sorted).
890 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800891 tags = set(tags.split(","))
892 for ch in OPTIONS.tag_changes:
893 if ch[0] == "-":
894 tags.discard(ch[1:])
895 elif ch[0] == "+":
896 tags.add(ch[1:])
897 return ",".join(sorted(tags))
898
899
Tao Baoa7054ee2017-12-08 14:42:16 -0800900def RewriteProps(data):
901 """Rewrites the system properties in the given string.
902
903 Each property is expected in 'key=value' format. The properties that contain
904 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
905 EditTags().
906
907 Args:
908 data: Input string, separated by newlines.
909
910 Returns:
911 The string with modified properties.
912 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700913 output = []
914 for line in data.split("\n"):
915 line = line.strip()
916 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700917 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700918 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200919 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400920 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800921 pieces = value.split("/")
922 pieces[-1] = EditTags(pieces[-1])
923 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700924 elif key == "ro.bootimage.build.fingerprint":
925 pieces = value.split("/")
926 pieces[-1] = EditTags(pieces[-1])
927 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700928 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800929 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500930 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800931 pieces[-1] = EditTags(pieces[-1])
932 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200933 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800934 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700935 elif key == "ro.build.display.id":
936 # change, eg, "JWR66N dev-keys" to "JWR66N"
937 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700938 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800939 value.pop()
940 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800941 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700942 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800943 print(" replace: ", original_line)
944 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700945 output.append(line)
946 return "\n".join(output) + "\n"
947
948
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700949def WriteOtacerts(output_zip, filename, keys):
950 """Constructs a zipfile from given keys; and writes it to output_zip.
951
952 Args:
953 output_zip: The output target_files zip.
954 filename: The archive name in the output zip.
955 keys: A list of public keys to use during OTA package verification.
956 """
Tao Baobb733882019-07-24 23:31:19 -0700957 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400958 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700959 for k in keys:
960 common.ZipWrite(certs_zip, k)
Kelvin Zhangf92f7f02023-04-14 21:32:54 +0000961 common.ZipClose(certs_zip)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700962 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
963
964
Doug Zongker831840e2011-09-22 10:28:04 -0700965def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700966 try:
967 keylist = input_tf_zip.read("META/otakeys.txt").split()
968 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700969 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700970
Jacky Liubeb0b692021-12-29 16:29:05 +0800971 extra_ota_keys_info = misc_info.get("extra_ota_keys")
972 if extra_ota_keys_info:
973 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
974 for k in extra_ota_keys_info.split()]
975 print("extra ota key(s): " + ", ".join(extra_ota_keys))
976 else:
977 extra_ota_keys = []
978 for k in extra_ota_keys:
979 if not os.path.isfile(k):
980 raise common.ExternalError(k + " does not exist or is not a file")
981
982 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
983 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800984 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800985 for k in extra_recovery_keys_info.split()]
986 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800987 else:
988 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800989 for k in extra_recovery_keys:
990 if not os.path.isfile(k):
991 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800992
Doug Zongker8e931bf2009-04-06 15:21:45 -0700993 mapped_keys = []
994 for k in keylist:
995 m = re.match(r"^(.*)\.x509\.pem$", k)
996 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800997 raise common.ExternalError(
998 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700999 k = m.group(1)
1000 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
1001
Doug Zongkere05628c2009-08-20 17:38:42 -07001002 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001003 print("using:\n ", "\n ".join(mapped_keys))
1004 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -07001005 else:
Doug Zongker831840e2011-09-22 10:28:04 -07001006 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001007 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -08001008 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
1009 if mapped_devkey != devkey:
1010 misc_info["default_system_dev_certificate"] = mapped_devkey
1011 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -07001012 print("META/otakeys.txt has no keys; using %s for OTA package"
1013 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +08001014 for k in mapped_keys:
1015 if not os.path.isfile(k):
1016 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -07001017
Kelvin Zhang9f781ff2021-02-11 19:10:44 -05001018 otacerts = [info
1019 for info in input_tf_zip.infolist()
1020 if info.filename.endswith("/otacerts.zip")]
1021 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +08001022 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
1023 extra_keys = extra_recovery_keys
1024 else:
1025 extra_keys = extra_ota_keys
1026 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
1027 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -07001028
Tao Baoa80ed222016-06-16 14:41:24 -07001029
Tao Bao46a59992017-06-05 11:55:16 -07001030def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1031 """Replaces META/misc_info.txt.
1032
1033 Only writes back the ones in the original META/misc_info.txt. Because the
1034 current in-memory dict contains additional items computed at runtime.
1035 """
1036 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001037 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001038 items = []
1039 for key in sorted(misc_info):
1040 if key in misc_info_old:
1041 items.append('%s=%s' % (key, misc_info[key]))
1042 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001043
Tao Bao8adcfd12016-06-17 17:01:22 -07001044
Tao Bao639118f2017-06-19 15:48:02 -07001045def ReplaceAvbSigningKeys(misc_info):
1046 """Replaces the AVB signing keys."""
1047
Tao Bao639118f2017-06-19 15:48:02 -07001048 def ReplaceAvbPartitionSigningKey(partition):
1049 key = OPTIONS.avb_keys.get(partition)
1050 if not key:
1051 return
1052
1053 algorithm = OPTIONS.avb_algorithms.get(partition)
1054 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1055
Tao Bao0c28d2d2017-12-24 10:37:38 -08001056 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1057 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001058 misc_info['avb_' + partition + '_algorithm'] = algorithm
1059 misc_info['avb_' + partition + '_key_path'] = key
1060
1061 extra_args = OPTIONS.avb_extra_args.get(partition)
1062 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001063 print('Setting extra AVB signing args for %s to "%s"' % (
1064 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001065 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1066 partition,
1067 # custom partition
1068 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001069 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1070
1071 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1072 ReplaceAvbPartitionSigningKey(partition)
1073
Hongguang Chenf23364d2020-04-27 18:36:36 -07001074 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001075 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001076 ReplaceAvbPartitionSigningKey(custom_partition)
1077
Tao Bao639118f2017-06-19 15:48:02 -07001078
Tao Bao19b02fe2019-10-09 00:04:28 -07001079def RewriteAvbProps(misc_info):
1080 """Rewrites the props in AVB signing args."""
1081 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1082 args = misc_info.get(args_key)
1083 if not args:
1084 continue
1085
1086 tokens = []
1087 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001088 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001089 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1090 if not token.startswith(fingerprint_key):
1091 tokens.append(token)
1092 continue
1093 prefix, tag = token.rsplit('/', 1)
1094 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1095 changed = True
1096
1097 if changed:
1098 result = ' '.join(tokens)
1099 print('Rewriting AVB prop for {}:\n'.format(partition))
1100 print(' replace: {}'.format(args))
1101 print(' with: {}'.format(result))
1102 misc_info[args_key] = result
1103
1104
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001105def ReplaceGkiSigningKey(misc_info):
1106 """Replaces the GKI signing key."""
1107
1108 key = OPTIONS.gki_signing_key
1109 if not key:
1110 return
1111
1112 algorithm = OPTIONS.gki_signing_algorithm
1113 if not algorithm:
1114 raise ValueError("Missing --gki_signing_algorithm")
1115
1116 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1117 misc_info["gki_signing_algorithm"] = algorithm
1118 misc_info["gki_signing_key_path"] = key
1119
1120 extra_args = OPTIONS.gki_signing_extra_args
1121 if extra_args:
1122 print('Setting GKI signing args: "%s"' % (extra_args))
1123 misc_info["gki_signing_signature_args"] = extra_args
1124
1125
Doug Zongker831840e2011-09-22 10:28:04 -07001126def BuildKeyMap(misc_info, key_mapping_options):
1127 for s, d in key_mapping_options:
1128 if s is None: # -d option
1129 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001130 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001131 devkeydir = os.path.dirname(devkey)
1132
1133 OPTIONS.key_map.update({
1134 devkeydir + "/testkey": d + "/releasekey",
1135 devkeydir + "/devkey": d + "/releasekey",
1136 devkeydir + "/media": d + "/media",
1137 devkeydir + "/shared": d + "/shared",
1138 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001139 devkeydir + "/networkstack": d + "/networkstack",
Cloud You0dbd8772024-01-10 15:12:39 +08001140 devkeydir + "/sdk_sandbox": d + "/sdk_sandbox",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001141 })
Doug Zongker831840e2011-09-22 10:28:04 -07001142 else:
1143 OPTIONS.key_map[s] = d
1144
1145
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001146def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001147 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001148 api_level = None
1149 codename = None
1150 for line in data.split("\n"):
1151 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001152 if line and line[0] != '#' and "=" in line:
1153 key, value = line.split("=", 1)
1154 key = key.strip()
1155 if key == "ro.build.version.sdk":
1156 api_level = int(value.strip())
1157 elif key == "ro.build.version.codename":
1158 codename = value.strip()
1159
1160 if api_level is None:
1161 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1162 if codename is None:
1163 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1164
1165 return (api_level, codename)
1166
1167
1168def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001169 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001170 api_level = None
1171 codenames = None
1172 for line in data.split("\n"):
1173 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001174 if line and line[0] != '#' and "=" in line:
1175 key, value = line.split("=", 1)
1176 key = key.strip()
1177 if key == "ro.build.version.sdk":
1178 api_level = int(value.strip())
1179 elif key == "ro.build.version.all_codenames":
1180 codenames = value.strip().split(",")
1181
1182 if api_level is None:
1183 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1184 if codenames is None:
1185 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1186
Tao Baoa3705452019-06-24 15:33:41 -07001187 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001188 for codename in codenames:
1189 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001190 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001191 result[codename] = api_level
1192 return result
1193
1194
Tao Baoaa7e9932019-03-15 09:37:01 -07001195def ReadApexKeysInfo(tf_zip):
1196 """Parses the APEX keys info from a given target-files zip.
1197
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001198 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1199 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1200 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001201
1202 Args:
1203 tf_zip: The input target_files ZipFile (already open).
1204
1205 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001206 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001207 - payload_key contains the path to the payload signing key
1208 - container_key contains the path to the container signing key
1209 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001210 """
1211 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001212 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001213 line = line.strip()
1214 if not line:
1215 continue
1216 matches = re.match(
1217 r'^name="(?P<NAME>.*)"\s+'
1218 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1219 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1220 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001221 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001222 r'(\s+partition="(?P<PARTITION>.*?)")?'
1223 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001224 line)
1225 if not matches:
1226 continue
1227
1228 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001229 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1230
1231 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1232 pubkey_suffix_len = len(pubkey_suffix)
1233 privkey_suffix_len = len(privkey_suffix)
1234 return (pubkey.endswith(pubkey_suffix) and
1235 privkey.endswith(privkey_suffix) and
1236 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1237
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001238 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001239 # extensions. This doesn't apply to payload keys though, which we will use
1240 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001241 container_cert = matches.group("CONTAINER_CERT")
1242 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001243 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1244 container_key = 'PRESIGNED'
1245 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001246 container_cert, OPTIONS.public_key_suffix,
1247 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001248 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1249 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001250 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001251
Jooyung Han8caba5e2021-10-27 03:58:09 +09001252 sign_tool = matches.group("SIGN_TOOL")
1253 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001254
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001255 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001256
1257
Daniel Norman78554ea2021-09-14 10:29:38 -07001258def BuildVendorPartitions(output_zip_path):
1259 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1260 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1261 logger.warning("Allowed --vendor_partitions: %s",
1262 ",".join(ALLOWED_VENDOR_PARTITIONS))
1263 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1264 OPTIONS.vendor_partitions)
1265
1266 logger.info("Building vendor partitions using vendor otatools.")
1267 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1268 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001269 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001270 "RECOVERY/*",
1271 "BOOT/*",
1272 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001273 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1274
1275 # Disable various partitions that build based on misc_info fields.
1276 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1277 # vendor otatools. These other partitions will be rebuilt using the main
1278 # otatools if necessary.
1279 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1280 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001281 # Ignore if not rebuilding recovery
1282 if not OPTIONS.rebuild_recovery:
1283 vendor_misc_info["no_boot"] = "true" # boot
1284 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1285 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001286 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001287
Daniel Norman78554ea2021-09-14 10:29:38 -07001288 vendor_misc_info["has_dtbo"] = "false" # dtbo
1289 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001290 vendor_misc_info["avb_custom_images_partition_list"] = "" # avb custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001291 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001292 vendor_misc_info["custom_images_partition_list"] = "" # custom images
Daniel Norman78554ea2021-09-14 10:29:38 -07001293 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1294 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001295 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001296 with open(vendor_misc_info_path, "w") as output:
1297 for key in sorted(vendor_misc_info):
1298 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1299
Po Hu0663ae42021-09-27 12:59:06 +08001300 # Disable system partition by a placeholder of IMAGES/system.img,
1301 # instead of removing SYSTEM folder.
1302 # Because SYSTEM/build.prop is still needed for:
1303 # add_img_to_target_files.CreateImage ->
1304 # common.BuildInfo ->
1305 # common.BuildInfo.CalculateFingerprint
1306 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1307 if not os.path.exists(vendor_images_path):
1308 os.makedirs(vendor_images_path)
1309 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1310 pass
1311
Daniel Norman78554ea2021-09-14 10:29:38 -07001312 # Disable care_map.pb as not all ab_partitions are available when
1313 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001314 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1315 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1316 # Disable RADIO images
1317 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1318 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001319
1320 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001321 # Accept either a zip file or extracted directory.
1322 if os.path.isfile(OPTIONS.vendor_otatools):
1323 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1324 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1325 else:
1326 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001327 cmd = [
1328 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1329 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001330 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001331 "--verbose",
1332 vendor_tempdir,
1333 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001334 if OPTIONS.rebuild_recovery:
1335 cmd.insert(4, "--rebuild_recovery")
1336
Daniel Norman78554ea2021-09-14 10:29:38 -07001337 common.RunAndCheckOutput(cmd, verbose=True)
1338
1339 logger.info("Writing vendor partitions to output archive.")
1340 with zipfile.ZipFile(
1341 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1342 allowZip64=True) as output_zip:
1343 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001344 img_file_path = "IMAGES/{}.img".format(p)
1345 map_file_path = "IMAGES/{}.map".format(p)
1346 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001347 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1348 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001349 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001350 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001351 recovery_img = "IMAGES/recovery.img"
1352 boot_img = "IMAGES/boot.img"
1353 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1354 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001355 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1356 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1357 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1358 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001359
1360
Doug Zongkereef39442009-04-02 12:14:19 -07001361def main(argv):
1362
Doug Zongker831840e2011-09-22 10:28:04 -07001363 key_mapping_options = []
1364
Doug Zongkereef39442009-04-02 12:14:19 -07001365 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001366 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001367 names, key = a.split("=")
1368 names = names.split(",")
1369 for n in names:
1370 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001371 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001372 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001373 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001374 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001375 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001376 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001377 prefix = a.split('/')[0]
1378 if not prefix or prefix != prefix.upper():
1379 raise ValueError("Invalid path prefix '%s'" % (a,))
1380 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001381 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001382 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001383 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001384 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001385 elif o in ("-o", "--replace_ota_keys"):
1386 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001387 elif o in ("-t", "--tag_changes"):
1388 new = []
1389 for i in a.split(","):
1390 i = i.strip()
1391 if not i or i[0] not in "-+":
1392 raise ValueError("Bad tag change '%s'" % (i,))
1393 new.append(i[0] + i[1:].strip())
1394 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001395 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001396 raise ValueError("--replace_verity_public_key is no longer supported,"
1397 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001398 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001399 raise ValueError("--replace_verity_private_key is no longer supported,"
1400 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001401 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001402 raise ValueError("--replace_verity_keyid is no longer supported, please"
1403 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001404 elif o == "--remove_avb_public_keys":
1405 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001406 elif o == "--avb_vbmeta_key":
1407 OPTIONS.avb_keys['vbmeta'] = a
1408 elif o == "--avb_vbmeta_algorithm":
1409 OPTIONS.avb_algorithms['vbmeta'] = a
1410 elif o == "--avb_vbmeta_extra_args":
1411 OPTIONS.avb_extra_args['vbmeta'] = a
1412 elif o == "--avb_boot_key":
1413 OPTIONS.avb_keys['boot'] = a
1414 elif o == "--avb_boot_algorithm":
1415 OPTIONS.avb_algorithms['boot'] = a
1416 elif o == "--avb_boot_extra_args":
1417 OPTIONS.avb_extra_args['boot'] = a
1418 elif o == "--avb_dtbo_key":
1419 OPTIONS.avb_keys['dtbo'] = a
1420 elif o == "--avb_dtbo_algorithm":
1421 OPTIONS.avb_algorithms['dtbo'] = a
1422 elif o == "--avb_dtbo_extra_args":
1423 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001424 elif o == "--avb_init_boot_key":
1425 OPTIONS.avb_keys['init_boot'] = a
1426 elif o == "--avb_init_boot_algorithm":
1427 OPTIONS.avb_algorithms['init_boot'] = a
1428 elif o == "--avb_init_boot_extra_args":
1429 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001430 elif o == "--avb_recovery_key":
1431 OPTIONS.avb_keys['recovery'] = a
1432 elif o == "--avb_recovery_algorithm":
1433 OPTIONS.avb_algorithms['recovery'] = a
1434 elif o == "--avb_recovery_extra_args":
1435 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001436 elif o == "--avb_system_key":
1437 OPTIONS.avb_keys['system'] = a
1438 elif o == "--avb_system_algorithm":
1439 OPTIONS.avb_algorithms['system'] = a
1440 elif o == "--avb_system_extra_args":
1441 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001442 elif o == "--avb_system_other_key":
1443 OPTIONS.avb_keys['system_other'] = a
1444 elif o == "--avb_system_other_algorithm":
1445 OPTIONS.avb_algorithms['system_other'] = a
1446 elif o == "--avb_system_other_extra_args":
1447 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001448 elif o == "--avb_vendor_key":
1449 OPTIONS.avb_keys['vendor'] = a
1450 elif o == "--avb_vendor_algorithm":
1451 OPTIONS.avb_algorithms['vendor'] = a
1452 elif o == "--avb_vendor_extra_args":
1453 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001454 elif o == "--avb_vbmeta_system_key":
1455 OPTIONS.avb_keys['vbmeta_system'] = a
1456 elif o == "--avb_vbmeta_system_algorithm":
1457 OPTIONS.avb_algorithms['vbmeta_system'] = a
1458 elif o == "--avb_vbmeta_system_extra_args":
1459 OPTIONS.avb_extra_args['vbmeta_system'] = a
1460 elif o == "--avb_vbmeta_vendor_key":
1461 OPTIONS.avb_keys['vbmeta_vendor'] = a
1462 elif o == "--avb_vbmeta_vendor_algorithm":
1463 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1464 elif o == "--avb_vbmeta_vendor_extra_args":
1465 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001466 elif o == "--avb_apex_extra_args":
1467 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001468 elif o == "--avb_extra_custom_image_key":
1469 partition, key = a.split("=")
1470 OPTIONS.avb_keys[partition] = key
1471 elif o == "--avb_extra_custom_image_algorithm":
1472 partition, algorithm = a.split("=")
1473 OPTIONS.avb_algorithms[partition] = algorithm
1474 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001475 # Setting the maxsplit parameter to one, which will return a list with
1476 # two elements. e.g., the second '=' should not be splitted for
1477 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1478 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001479 OPTIONS.avb_extra_args[partition] = extra_args
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001480 elif o == "--gki_signing_key":
1481 OPTIONS.gki_signing_key = a
1482 elif o == "--gki_signing_algorithm":
1483 OPTIONS.gki_signing_algorithm = a
1484 elif o == "--gki_signing_extra_args":
1485 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001486 elif o == "--vendor_otatools":
1487 OPTIONS.vendor_otatools = a
1488 elif o == "--vendor_partitions":
1489 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001490 elif o == "--allow_gsi_debug_sepolicy":
1491 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001492 elif o == "--override_apk_keys":
1493 OPTIONS.override_apk_keys = a
1494 elif o == "--override_apex_keys":
1495 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001496 else:
1497 return False
1498 return True
1499
Tao Bao639118f2017-06-19 15:48:02 -07001500 args = common.ParseOptions(
1501 argv, __doc__,
1502 extra_opts="e:d:k:ot:",
1503 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001504 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001505 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001506 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001507 "default_key_mappings=",
1508 "key_mapping=",
1509 "replace_ota_keys",
1510 "tag_changes=",
1511 "replace_verity_public_key=",
1512 "replace_verity_private_key=",
1513 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001514 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001515 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001516 "avb_vbmeta_algorithm=",
1517 "avb_vbmeta_key=",
1518 "avb_vbmeta_extra_args=",
1519 "avb_boot_algorithm=",
1520 "avb_boot_key=",
1521 "avb_boot_extra_args=",
1522 "avb_dtbo_algorithm=",
1523 "avb_dtbo_key=",
1524 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001525 "avb_init_boot_algorithm=",
1526 "avb_init_boot_key=",
1527 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001528 "avb_recovery_algorithm=",
1529 "avb_recovery_key=",
1530 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001531 "avb_system_algorithm=",
1532 "avb_system_key=",
1533 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001534 "avb_system_other_algorithm=",
1535 "avb_system_other_key=",
1536 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001537 "avb_vendor_algorithm=",
1538 "avb_vendor_key=",
1539 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001540 "avb_vbmeta_system_algorithm=",
1541 "avb_vbmeta_system_key=",
1542 "avb_vbmeta_system_extra_args=",
1543 "avb_vbmeta_vendor_algorithm=",
1544 "avb_vbmeta_vendor_key=",
1545 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001546 "avb_extra_custom_image_key=",
1547 "avb_extra_custom_image_algorithm=",
1548 "avb_extra_custom_image_extra_args=",
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001549 "gki_signing_key=",
1550 "gki_signing_algorithm=",
1551 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001552 "vendor_partitions=",
1553 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001554 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001555 "override_apk_keys=",
1556 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001557 ],
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001558 extra_option_handler=[option_handler, payload_signer.signer_options])
Doug Zongkereef39442009-04-02 12:14:19 -07001559
1560 if len(args) != 2:
1561 common.Usage(__doc__)
1562 sys.exit(1)
1563
Tao Baobadceb22019-03-15 09:33:43 -07001564 common.InitLogging()
1565
Kelvin Zhang928c2342020-09-22 16:15:57 -04001566 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001567 output_zip = zipfile.ZipFile(args[1], "w",
1568 compression=zipfile.ZIP_DEFLATED,
1569 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001570
Doug Zongker831840e2011-09-22 10:28:04 -07001571 misc_info = common.LoadInfoDict(input_zip)
Kelvin Zhangb84d2aa2023-11-06 10:53:41 -08001572 if OPTIONS.package_key is None:
1573 OPTIONS.package_key = misc_info.get(
1574 "default_system_dev_certificate",
1575 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001576
1577 BuildKeyMap(misc_info, key_mapping_options)
1578
Tao Baoaa7e9932019-03-15 09:37:01 -07001579 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1580 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001581
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001582 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001583 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1584
Tianjie Xu88a759d2020-01-23 10:47:54 -08001585 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1586 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001587 CheckApkAndApexKeysAvailable(
1588 input_zip,
1589 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001590 compressed_extension,
1591 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001592
1593 key_passwords = common.GetKeyPasswords(
1594 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001595 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001596 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001597
Doug Zongker412c02f2014-02-13 10:58:24 -08001598 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001599 apk_keys, apex_keys, key_passwords,
1600 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001601 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001602
Kelvin Zhangf92f7f02023-04-14 21:32:54 +00001603 common.ZipClose(input_zip)
1604 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001605
Daniel Norman78554ea2021-09-14 10:29:38 -07001606 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1607 BuildVendorPartitions(args[1])
1608
Tianjie Xub48589a2016-08-03 19:21:52 -07001609 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001610 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001611 # add_img_to_target_files builds the system image from scratch, so the
1612 # recovery patch is guaranteed to be regenerated there.
1613 if OPTIONS.rebuild_recovery:
1614 new_args.append("--rebuild_recovery")
1615 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001616 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001617
Tao Bao0c28d2d2017-12-24 10:37:38 -08001618 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001619
1620
1621if __name__ == '__main__':
1622 try:
1623 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001624 finally:
1625 common.Cleanup()