blob: 5867c6fd2d21896982fa370b83721971b8d42e65 [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
Doug Zongkereef39442009-04-02 12:14:19 -0700149"""
150
Tao Bao0c28d2d2017-12-24 10:37:38 -0800151from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700152
Robert Craig817c5742013-04-19 10:59:22 -0400153import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700154import copy
Robert Craig817c5742013-04-19 10:59:22 -0400155import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100156import gzip
Tao Baobb733882019-07-24 23:31:19 -0700157import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700158import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700159import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700160import os
161import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100162import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700163import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700164import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800165import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700166import tempfile
167import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800168from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700169
Doug Zongker3c84f562014-07-31 11:06:30 -0700170import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700171import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700172import common
173
Tao Bao0c28d2d2017-12-24 10:37:38 -0800174
175if sys.hexversion < 0x02070000:
176 print("Python 2.7 or newer is required.", file=sys.stderr)
177 sys.exit(1)
178
179
Tao Baobadceb22019-03-15 09:33:43 -0700180logger = logging.getLogger(__name__)
181
Doug Zongkereef39442009-04-02 12:14:19 -0700182OPTIONS = common.OPTIONS
183
184OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700185OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700186OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700187OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700188OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700189OPTIONS.replace_ota_keys = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800190OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700191OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700192OPTIONS.avb_keys = {}
193OPTIONS.avb_algorithms = {}
194OPTIONS.avb_extra_args = {}
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000195OPTIONS.gki_signing_key = None
196OPTIONS.gki_signing_algorithm = None
197OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800198OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700199OPTIONS.vendor_partitions = set()
200OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800201OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700202OPTIONS.override_apk_keys = None
203OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700204
Tao Bao0c28d2d2017-12-24 10:37:38 -0800205
Tao Bao19b02fe2019-10-09 00:04:28 -0700206AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800207 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000208 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800209 'dtbo': 'avb_dtbo_add_hash_footer_args',
210 'product': 'avb_product_add_hashtree_footer_args',
211 'recovery': 'avb_recovery_add_hash_footer_args',
212 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000213 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800214 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
215 'system_other': 'avb_system_other_add_hashtree_footer_args',
216 'odm': 'avb_odm_add_hashtree_footer_args',
217 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
218 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
219 'vendor': 'avb_vendor_add_hashtree_footer_args',
220 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800221 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800222 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
223 'vbmeta': 'avb_vbmeta_args',
224 'vbmeta_system': 'avb_vbmeta_system_args',
225 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700226}
227
228
Tianjiebf0b8a82021-03-03 17:31:04 -0800229# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
230for partition in common.AVB_PARTITIONS:
231 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
232 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
233
Daniel Norman78554ea2021-09-14 10:29:38 -0700234# Partitions that can be regenerated after signing using a separate
235# vendor otatools package.
236ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
237
Tianjiebf0b8a82021-03-03 17:31:04 -0800238
Tianjie4d48d502021-06-11 17:03:43 -0700239def IsApexFile(filename):
240 return filename.endswith(".apex") or filename.endswith(".capex")
241
242
243def GetApexFilename(filename):
244 name = os.path.basename(filename)
245 # Replace the suffix for compressed apex
246 if name.endswith(".capex"):
247 return name.replace(".capex", ".apex")
248 return name
249
250
Narayan Kamatha07bf042017-08-14 14:49:21 +0100251def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700252 if OPTIONS.override_apk_keys is not None:
253 for apk in certmap.keys():
254 certmap[apk] = OPTIONS.override_apk_keys
255
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800256 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700257 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800258 certmap[apk] = OPTIONS.key_map.get(cert, cert)
259
260 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700261 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800262 if not cert:
263 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700264 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800265
Doug Zongkereef39442009-04-02 12:14:19 -0700266 return certmap
267
268
Tao Baoaa7e9932019-03-15 09:37:01 -0700269def GetApexKeys(keys_info, key_map):
270 """Gets APEX payload and container signing keys by applying the mapping rules.
271
Tao Baoe1343992019-03-19 12:24:03 -0700272 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700273
274 Args:
275 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900276 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700277 key_map: A dict that overrides the keys, specified via command-line input.
278
279 Returns:
280 A dict that contains the updated APEX key mapping, which should be used for
281 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700282
283 Raises:
284 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700285 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700286 if OPTIONS.override_apex_keys is not None:
287 for apex in keys_info.keys():
288 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
289
290 if OPTIONS.override_apk_keys is not None:
291 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
292 for apex in keys_info.keys():
293 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
294
Tao Baoaa7e9932019-03-15 09:37:01 -0700295 # Apply all the --extra_apex_payload_key options to override the payload
296 # signing keys in the given keys_info.
297 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700298 if not key:
299 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700300 if apex not in keys_info:
301 logger.warning('Failed to find %s in target_files; Ignored', apex)
302 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900303 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700304
305 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900306 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
307 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700308
309 # Apply all the --extra_apks options to override the container keys.
310 for apex, key in OPTIONS.extra_apks.items():
311 # Skip non-APEX containers.
312 if apex not in keys_info:
313 continue
Tao Baoe1343992019-03-19 12:24:03 -0700314 if not key:
315 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900316 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700317
Tao Baof98fa102019-04-24 14:51:25 -0700318 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
319 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
320 # (overridden via commandline) indicates a config error, which should not be
321 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900322 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700323 if container_key != 'PRESIGNED':
324 continue
325 if apex in OPTIONS.extra_apex_payload_keys:
326 payload_override = OPTIONS.extra_apex_payload_keys[apex]
327 assert payload_override == '', \
328 ("Invalid APEX key overrides: {} has PRESIGNED container but "
329 "non-PRESIGNED payload key {}").format(apex, payload_override)
330 if payload_key != 'PRESIGNED':
331 print(
332 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
333 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900334 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700335
Tao Baoaa7e9932019-03-15 09:37:01 -0700336 return keys_info
337
338
Tao Bao93c2a012018-06-19 12:19:35 -0700339def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700340 """Returns the APK info based on the given filename.
341
342 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700343 compressed extension into consideration. If it appears to be an APK file,
344 further checks if the APK file should be skipped when signing, based on the
345 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700346
347 Args:
348 filename: Path to the file.
349 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
350 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700351 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700352
353 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700354 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
355 given filename is an APK file. is_compressed indicates whether the APK file
356 is compressed (only meaningful when is_apk is True). should_be_skipped
357 indicates whether the filename matches any of the given prefixes to be
358 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700359
360 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700361 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700362 """
363 assert compressed_extension is None or compressed_extension.startswith('.'), \
364 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
365
Tao Bao93c2a012018-06-19 12:19:35 -0700366 # skipped_prefixes should be one of set/list/tuple types. Other types such as
367 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700368 assert isinstance(skipped_prefixes, (set, list, tuple)), \
369 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700370
Tao Bao11f955c2018-06-19 12:19:35 -0700371 compressed_apk_extension = (
372 ".apk" + compressed_extension if compressed_extension else None)
373 is_apk = (filename.endswith(".apk") or
374 (compressed_apk_extension and
375 filename.endswith(compressed_apk_extension)))
376 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700377 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700378
379 is_compressed = (compressed_apk_extension and
380 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700381 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
382 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700383
384
Tao Baoaa7e9932019-03-15 09:37:01 -0700385def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700386 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700387 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700388
389 Args:
390 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700391 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700392 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700393 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700394 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900395 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700396
397 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700398 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700399 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700400 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700401 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800402 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700403 if IsApexFile(info.filename):
404 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700405 if name not in known_keys:
406 unknown_files.append(name)
407 continue
408
409 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700410 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
411 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
412 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700413 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700414
Tao Bao11f955c2018-06-19 12:19:35 -0700415 name = os.path.basename(info.filename)
416 if is_compressed:
417 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700418 if name not in known_keys:
419 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700420
Tao Baoaa7e9932019-03-15 09:37:01 -0700421 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700422 ("No key specified for:\n {}\n"
423 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700424 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700425
Tao Baoe1343992019-03-19 12:24:03 -0700426 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700427 # one of the payload / container keys set. Note that non-PRESIGNED container
428 # with PRESIGNED payload could be allowed but currently unsupported. It would
429 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700430 if not apex_keys:
431 return
432
433 invalid_apexes = []
434 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700435 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700436 continue
437
Tianjie4d48d502021-06-11 17:03:43 -0700438 name = GetApexFilename(info.filename)
439
Jooyung Han8caba5e2021-10-27 03:58:09 +0900440 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700441 if ((payload_key in common.SPECIAL_CERT_STRINGS and
442 container_key not in common.SPECIAL_CERT_STRINGS) or
443 (payload_key not in common.SPECIAL_CERT_STRINGS and
444 container_key in common.SPECIAL_CERT_STRINGS)):
445 invalid_apexes.append(
446 "{}: payload_key {}, container_key {}".format(
447 name, payload_key, container_key))
448
449 assert not invalid_apexes, \
450 "Invalid APEX keys specified:\n {}\n".format(
451 "\n ".join(invalid_apexes))
452
Doug Zongkereb338ef2009-05-20 16:50:49 -0700453
Narayan Kamatha07bf042017-08-14 14:49:21 +0100454def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700455 is_compressed, apk_name):
456 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700457 unsigned.write(data)
458 unsigned.flush()
459
Narayan Kamatha07bf042017-08-14 14:49:21 +0100460 if is_compressed:
461 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800462 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400463 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100464 shutil.copyfileobj(in_file, out_file)
465
466 # Finally, close the "unsigned" file (which is gzip compressed), and then
467 # replace it with the uncompressed version.
468 #
469 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
470 # we could just gzip / gunzip in-memory buffers instead.
471 unsigned.close()
472 unsigned = uncompressed
473
Oleg Aravin8046cb02020-06-02 16:02:38 -0700474 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700475
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800476 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
477 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
478 # didn't change, we don't want its signature to change due to the switch
479 # from SHA-1 to SHA-256.
480 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
481 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
482 # that the APK's minSdkVersion is 1.
483 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
484 # determine whether to use SHA-256.
485 min_api_level = None
486 if platform_api_level > 23:
487 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
488 # minSdkVersion attribute
489 min_api_level = None
490 else:
491 # Force APK signer to use SHA-1
492 min_api_level = 1
493
494 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800495 min_api_level=min_api_level,
496 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700497
Tao Bao0c28d2d2017-12-24 10:37:38 -0800498 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100499 if is_compressed:
500 # Recompress the file after it has been signed.
501 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800502 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400503 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100504 shutil.copyfileobj(in_file, out_file)
505
506 data = compressed.read()
507 compressed.close()
508 else:
509 data = signed.read()
510
Doug Zongkereef39442009-04-02 12:14:19 -0700511 unsigned.close()
512 signed.close()
513
514 return data
515
Tianjie5bd03952021-02-18 23:02:36 -0800516
Kelvin Zhang119f2792021-02-10 12:45:24 -0500517def IsBuildPropFile(filename):
518 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400519 "SYSTEM/etc/prop.default",
520 "BOOT/RAMDISK/prop.default",
521 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500522
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400523 "VENDOR_BOOT/RAMDISK/default.prop",
524 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500525
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400526 # ROOT/default.prop is a legacy path, but may still exist for upgrading
527 # devices that don't support `property_overrides_split_enabled`.
528 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500529
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400530 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
531 # as a symlink in the current code. So it's a no-op here. Keeping the
532 # path here for clarity.
Kelvin Zhang30669e62023-01-10 21:02:02 -0800533 # Some build props might be stored under path
Hongguang Chen1a732332023-01-29 10:51:19 -0800534 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
535 # default.prop can be a symbolic link to prop.default, so overwrite all
536 # files that ends with build.prop, default.prop or prop.default
Kelvin Zhang30669e62023-01-10 21:02:02 -0800537 "RECOVERY/RAMDISK/default.prop") or \
538 filename.endswith("build.prop") or \
Hongguang Chen1a732332023-01-29 10:51:19 -0800539 filename.endswith("/default.prop") or \
540 filename.endswith("/prop.default")
Doug Zongkereef39442009-04-02 12:14:19 -0700541
Tianjie5bd03952021-02-18 23:02:36 -0800542
Doug Zongker412c02f2014-02-13 10:58:24 -0800543def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700544 apk_keys, apex_keys, key_passwords,
545 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000546 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700547 # maxsize measures the maximum filename length, including the ones to be
548 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800549 try:
550 maxsize = max(
551 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
552 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
553 except ValueError:
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000554 # Sets this to zero for targets without APK files, e.g., gki_arm64.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800555 maxsize = 0
556
Doug Zongkereef39442009-04-02 12:14:19 -0700557 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700558 filename = info.filename
559 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700560 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700561
Tao Bao04808502019-07-25 23:11:41 -0700562 # Skip OTA-specific images (e.g. split super images), which will be
563 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800564 if filename.startswith("OTA/") and filename.endswith(".img"):
565 continue
566
Tao Bao11f955c2018-06-19 12:19:35 -0700567 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700568 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700569 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
570 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
571
572 if is_apk and should_be_skipped:
573 # Copy skipped APKs verbatim.
574 print(
575 "NOT signing: %s\n"
576 " (skipped due to matching prefix)" % (filename,))
577 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800578
Tao Baof2cffbd2015-07-22 12:33:18 -0700579 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700580 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700581 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100582 if is_compressed:
583 name = name[:-len(compressed_extension)]
584
Tao Baoaa7e9932019-03-15 09:37:01 -0700585 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800586 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800587 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800588 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700589 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700590 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700591 else:
592 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700593 print(
594 "NOT signing: %s\n"
595 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700596 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700597
Tianjie5bd03952021-02-18 23:02:36 -0800598 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700599 elif IsApexFile(filename):
600 name = GetApexFilename(filename)
601
Jooyung Han8caba5e2021-10-27 03:58:09 +0900602 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700603
Tao Baoe1343992019-03-19 12:24:03 -0700604 # We've asserted not having a case with only one of them PRESIGNED.
605 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400606 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700607 print(" signing: %-*s container (%s)" % (
608 maxsize, name, container_key))
609 print(" : %-*s payload (%s)" % (
610 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700611
Tao Baoe7354ba2019-05-09 16:54:15 -0700612 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700613 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700614 data,
615 payload_key,
616 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300617 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800618 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700619 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400620 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900621 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000622 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700623 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700624
Tao Baoe1343992019-03-19 12:24:03 -0700625 else:
626 print(
627 "NOT signing: %s\n"
628 " (skipped due to special cert string)" % (name,))
629 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700630
Tao Baoa80ed222016-06-16 14:41:24 -0700631 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500632 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700633 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800634 if stat.S_ISLNK(info.external_attr >> 16):
635 new_data = data
636 else:
Tao Baoa3705452019-06-24 15:33:41 -0700637 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700638 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700639
Tao Bao66472632017-12-04 17:16:36 -0800640 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900641 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700642 elif filename.endswith("mac_permissions.xml"):
643 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700644 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700645 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700646
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700647 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700648 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100649 "VENDOR/recovery-from-boot.p",
650
Tao Bao11f955c2018-06-19 12:19:35 -0700651 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100652 "VENDOR/etc/recovery.img",
653
654 "SYSTEM/bin/install-recovery.sh",
655 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700656 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700657
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700658 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700659 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500660 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800661 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700662
Tao Bao46a59992017-06-05 11:55:16 -0700663 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700664 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700665 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700666
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800667 elif (OPTIONS.remove_avb_public_keys and
668 (filename.startswith("BOOT/RAMDISK/avb/") or
669 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400670 matched_removal = False
671 for key_to_remove in OPTIONS.remove_avb_public_keys:
672 if filename.endswith(key_to_remove):
673 matched_removal = True
674 print("Removing AVB public key from ramdisk: %s" % filename)
675 break
676 if not matched_removal:
677 # Copy it verbatim if we don't want to remove it.
678 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700679
Tianjiebbde59f2021-05-03 21:18:56 -0700680 # Skip the vbmeta digest as we will recalculate it.
681 elif filename == "META/vbmeta_digest.txt":
682 pass
683
Tianjie Xu4f099002016-08-11 18:04:27 -0700684 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400685 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700686 pass
687
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500688 # Skip apex_info.pb because we sign/modify apexes
689 elif filename == "META/apex_info.pb":
690 pass
691
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800692 # Updates system_other.avbpubkey in /product/etc/.
693 elif filename in (
694 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800695 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800696 # Only update system_other's public key, if the corresponding signing
697 # key is specified via --avb_system_other_key.
698 signing_key = OPTIONS.avb_keys.get("system_other")
699 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700700 public_key = common.ExtractAvbPublicKey(
701 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800702 print(" Rewriting AVB public key of system_other in /product")
703 common.ZipWrite(output_tf_zip, public_key, filename)
704
Andrew Scullbbc930b2022-02-17 22:34:27 +0000705 # Updates pvmfw embedded public key with the virt APEX payload key.
706 elif filename == "PREBUILT_IMAGES/pvmfw.img":
707 # Find the name of the virt APEX in the target files.
708 namelist = input_tf_zip.namelist()
709 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
710 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
711 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
712 if not virt_apex:
713 print("Removing %s from ramdisk: virt APEX not found" % filename)
714 else:
715 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
716 # Get the current and new embedded keys.
717 payload_key, container_key, sign_tool = apex_keys[virt_apex]
718 new_pubkey_path = common.ExtractAvbPublicKey(
719 misc_info['avb_avbtool'], payload_key)
720 with open(new_pubkey_path, 'rb') as f:
721 new_pubkey = f.read()
722 pubkey_info = copy.copy(
723 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
724 old_pubkey = input_tf_zip.read(pubkey_info.filename)
725 # Validate the keys and image.
726 if len(old_pubkey) != len(new_pubkey):
727 raise common.ExternalError("pvmfw embedded public key size mismatch")
728 pos = data.find(old_pubkey)
729 if pos == -1:
730 raise common.ExternalError("pvmfw embedded public key not found")
731 # Replace the key and copy new files.
732 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
733 common.ZipWriteStr(output_tf_zip, out_info, new_data)
734 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
735 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
736 pass
737
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800738 # Should NOT sign boot-debug.img.
739 elif filename in (
740 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800741 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800742 raise common.ExternalError("debuggable boot.img cannot be signed")
743
Bowgo Tsai2a781692021-10-13 17:39:33 +0800744 # Should NOT sign userdebug sepolicy file.
745 elif filename in (
746 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
747 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
748 if not OPTIONS.allow_gsi_debug_sepolicy:
749 raise common.ExternalError("debug sepolicy shouldn't be included")
750 else:
751 # Copy it verbatim if we allow the file to exist.
752 common.ZipWriteStr(output_tf_zip, out_info, data)
753
Tao Baoa80ed222016-06-16 14:41:24 -0700754 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700755 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700756 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700757
Doug Zongker412c02f2014-02-13 10:58:24 -0800758 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700759 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800760
Tao Bao639118f2017-06-19 15:48:02 -0700761 # Replace the AVB signing keys, if any.
762 ReplaceAvbSigningKeys(misc_info)
763
Tao Bao19b02fe2019-10-09 00:04:28 -0700764 # Rewrite the props in AVB signing args.
765 if misc_info.get('avb_enable') == 'true':
766 RewriteAvbProps(misc_info)
767
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +0000768 # Replace the GKI signing key for boot.img, if any.
769 ReplaceGkiSigningKey(misc_info)
770
Tao Bao46a59992017-06-05 11:55:16 -0700771 # Write back misc_info with the latest values.
772 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
773
Doug Zongker8e931bf2009-04-06 15:21:45 -0700774
Robert Craig817c5742013-04-19 10:59:22 -0400775def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800776 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400777
Tao Bao66472632017-12-04 17:16:36 -0800778 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
779 be skipped. After the replacement, it additionally checks for duplicate
780 entries, which would otherwise fail the policy loading code in
781 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
782
783 Args:
784 data: Input string that contains a set of X.509 certs.
785
786 Returns:
787 A string after the replacement.
788
789 Raises:
790 AssertionError: On finding duplicate entries.
791 """
Tao Baoa3705452019-06-24 15:33:41 -0700792 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800793 if OPTIONS.verbose:
794 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
795
796 try:
797 with open(old + ".x509.pem") as old_fp:
798 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700799 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800800 with open(new + ".x509.pem") as new_fp:
801 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700802 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800803 except IOError as e:
804 if OPTIONS.verbose or e.errno != errno.ENOENT:
805 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
806 "%s.x509.pem." % (e.filename, e.strerror, old, new))
807 continue
808
809 # Only match entire certs.
810 pattern = "\\b" + old_cert16 + "\\b"
811 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
812
813 if OPTIONS.verbose:
814 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
815 num, old, new))
816
817 # Verify that there're no duplicate entries after the replacement. Note that
818 # it's only checking entries with global seinfo at the moment (i.e. ignoring
819 # the ones with inner packages). (Bug: 69479366)
820 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400821 signatures = [signer.attrib['signature']
822 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800823 assert len(signatures) == len(set(signatures)), \
824 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400825
826 return data
827
828
Doug Zongkerc09abc82010-01-11 13:09:15 -0800829def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800830 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
831
832 Args:
833 tags: The input string that contains comma-separated tags.
834
835 Returns:
836 The updated tags (comma-separated and sorted).
837 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800838 tags = set(tags.split(","))
839 for ch in OPTIONS.tag_changes:
840 if ch[0] == "-":
841 tags.discard(ch[1:])
842 elif ch[0] == "+":
843 tags.add(ch[1:])
844 return ",".join(sorted(tags))
845
846
Tao Baoa7054ee2017-12-08 14:42:16 -0800847def RewriteProps(data):
848 """Rewrites the system properties in the given string.
849
850 Each property is expected in 'key=value' format. The properties that contain
851 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
852 EditTags().
853
854 Args:
855 data: Input string, separated by newlines.
856
857 Returns:
858 The string with modified properties.
859 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700860 output = []
861 for line in data.split("\n"):
862 line = line.strip()
863 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700864 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700865 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200866 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400867 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800868 pieces = value.split("/")
869 pieces[-1] = EditTags(pieces[-1])
870 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700871 elif key == "ro.bootimage.build.fingerprint":
872 pieces = value.split("/")
873 pieces[-1] = EditTags(pieces[-1])
874 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700875 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800876 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500877 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800878 pieces[-1] = EditTags(pieces[-1])
879 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200880 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800881 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700882 elif key == "ro.build.display.id":
883 # change, eg, "JWR66N dev-keys" to "JWR66N"
884 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700885 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800886 value.pop()
887 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800888 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700889 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800890 print(" replace: ", original_line)
891 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700892 output.append(line)
893 return "\n".join(output) + "\n"
894
895
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700896def WriteOtacerts(output_zip, filename, keys):
897 """Constructs a zipfile from given keys; and writes it to output_zip.
898
899 Args:
900 output_zip: The output target_files zip.
901 filename: The archive name in the output zip.
902 keys: A list of public keys to use during OTA package verification.
903 """
Tao Baobb733882019-07-24 23:31:19 -0700904 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400905 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700906 for k in keys:
907 common.ZipWrite(certs_zip, k)
Kelvin Zhangf92f7f02023-04-14 21:32:54 +0000908 common.ZipClose(certs_zip)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700909 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
910
911
Doug Zongker831840e2011-09-22 10:28:04 -0700912def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700913 try:
914 keylist = input_tf_zip.read("META/otakeys.txt").split()
915 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700916 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700917
Jacky Liubeb0b692021-12-29 16:29:05 +0800918 extra_ota_keys_info = misc_info.get("extra_ota_keys")
919 if extra_ota_keys_info:
920 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
921 for k in extra_ota_keys_info.split()]
922 print("extra ota key(s): " + ", ".join(extra_ota_keys))
923 else:
924 extra_ota_keys = []
925 for k in extra_ota_keys:
926 if not os.path.isfile(k):
927 raise common.ExternalError(k + " does not exist or is not a file")
928
929 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
930 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800931 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800932 for k in extra_recovery_keys_info.split()]
933 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800934 else:
935 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800936 for k in extra_recovery_keys:
937 if not os.path.isfile(k):
938 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800939
Doug Zongker8e931bf2009-04-06 15:21:45 -0700940 mapped_keys = []
941 for k in keylist:
942 m = re.match(r"^(.*)\.x509\.pem$", k)
943 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800944 raise common.ExternalError(
945 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700946 k = m.group(1)
947 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
948
Doug Zongkere05628c2009-08-20 17:38:42 -0700949 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800950 print("using:\n ", "\n ".join(mapped_keys))
951 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700952 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700953 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700954 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800955 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
956 if mapped_devkey != devkey:
957 misc_info["default_system_dev_certificate"] = mapped_devkey
958 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700959 print("META/otakeys.txt has no keys; using %s for OTA package"
960 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800961 for k in mapped_keys:
962 if not os.path.isfile(k):
963 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700964
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500965 otacerts = [info
966 for info in input_tf_zip.infolist()
967 if info.filename.endswith("/otacerts.zip")]
968 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800969 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
970 extra_keys = extra_recovery_keys
971 else:
972 extra_keys = extra_ota_keys
973 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
974 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700975
Tao Baoa80ed222016-06-16 14:41:24 -0700976
Tao Bao46a59992017-06-05 11:55:16 -0700977def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
978 """Replaces META/misc_info.txt.
979
980 Only writes back the ones in the original META/misc_info.txt. Because the
981 current in-memory dict contains additional items computed at runtime.
982 """
983 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700984 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700985 items = []
986 for key in sorted(misc_info):
987 if key in misc_info_old:
988 items.append('%s=%s' % (key, misc_info[key]))
989 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700990
Tao Bao8adcfd12016-06-17 17:01:22 -0700991
Tao Bao639118f2017-06-19 15:48:02 -0700992def ReplaceAvbSigningKeys(misc_info):
993 """Replaces the AVB signing keys."""
994
Tao Bao639118f2017-06-19 15:48:02 -0700995 def ReplaceAvbPartitionSigningKey(partition):
996 key = OPTIONS.avb_keys.get(partition)
997 if not key:
998 return
999
1000 algorithm = OPTIONS.avb_algorithms.get(partition)
1001 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1002
Tao Bao0c28d2d2017-12-24 10:37:38 -08001003 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1004 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001005 misc_info['avb_' + partition + '_algorithm'] = algorithm
1006 misc_info['avb_' + partition + '_key_path'] = key
1007
1008 extra_args = OPTIONS.avb_extra_args.get(partition)
1009 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001010 print('Setting extra AVB signing args for %s to "%s"' % (
1011 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001012 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1013 partition,
1014 # custom partition
1015 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001016 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1017
1018 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1019 ReplaceAvbPartitionSigningKey(partition)
1020
Hongguang Chenf23364d2020-04-27 18:36:36 -07001021 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001022 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001023 ReplaceAvbPartitionSigningKey(custom_partition)
1024
Tao Bao639118f2017-06-19 15:48:02 -07001025
Tao Bao19b02fe2019-10-09 00:04:28 -07001026def RewriteAvbProps(misc_info):
1027 """Rewrites the props in AVB signing args."""
1028 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1029 args = misc_info.get(args_key)
1030 if not args:
1031 continue
1032
1033 tokens = []
1034 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001035 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001036 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1037 if not token.startswith(fingerprint_key):
1038 tokens.append(token)
1039 continue
1040 prefix, tag = token.rsplit('/', 1)
1041 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1042 changed = True
1043
1044 if changed:
1045 result = ' '.join(tokens)
1046 print('Rewriting AVB prop for {}:\n'.format(partition))
1047 print(' replace: {}'.format(args))
1048 print(' with: {}'.format(result))
1049 misc_info[args_key] = result
1050
1051
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001052def ReplaceGkiSigningKey(misc_info):
1053 """Replaces the GKI signing key."""
1054
1055 key = OPTIONS.gki_signing_key
1056 if not key:
1057 return
1058
1059 algorithm = OPTIONS.gki_signing_algorithm
1060 if not algorithm:
1061 raise ValueError("Missing --gki_signing_algorithm")
1062
1063 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1064 misc_info["gki_signing_algorithm"] = algorithm
1065 misc_info["gki_signing_key_path"] = key
1066
1067 extra_args = OPTIONS.gki_signing_extra_args
1068 if extra_args:
1069 print('Setting GKI signing args: "%s"' % (extra_args))
1070 misc_info["gki_signing_signature_args"] = extra_args
1071
1072
Doug Zongker831840e2011-09-22 10:28:04 -07001073def BuildKeyMap(misc_info, key_mapping_options):
1074 for s, d in key_mapping_options:
1075 if s is None: # -d option
1076 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001077 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001078 devkeydir = os.path.dirname(devkey)
1079
1080 OPTIONS.key_map.update({
1081 devkeydir + "/testkey": d + "/releasekey",
1082 devkeydir + "/devkey": d + "/releasekey",
1083 devkeydir + "/media": d + "/media",
1084 devkeydir + "/shared": d + "/shared",
1085 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001086 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001087 })
Doug Zongker831840e2011-09-22 10:28:04 -07001088 else:
1089 OPTIONS.key_map[s] = d
1090
1091
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001092def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001093 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001094 api_level = None
1095 codename = None
1096 for line in data.split("\n"):
1097 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001098 if line and line[0] != '#' and "=" in line:
1099 key, value = line.split("=", 1)
1100 key = key.strip()
1101 if key == "ro.build.version.sdk":
1102 api_level = int(value.strip())
1103 elif key == "ro.build.version.codename":
1104 codename = value.strip()
1105
1106 if api_level is None:
1107 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1108 if codename is None:
1109 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1110
1111 return (api_level, codename)
1112
1113
1114def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001115 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001116 api_level = None
1117 codenames = None
1118 for line in data.split("\n"):
1119 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001120 if line and line[0] != '#' and "=" in line:
1121 key, value = line.split("=", 1)
1122 key = key.strip()
1123 if key == "ro.build.version.sdk":
1124 api_level = int(value.strip())
1125 elif key == "ro.build.version.all_codenames":
1126 codenames = value.strip().split(",")
1127
1128 if api_level is None:
1129 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1130 if codenames is None:
1131 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1132
Tao Baoa3705452019-06-24 15:33:41 -07001133 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001134 for codename in codenames:
1135 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001136 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001137 result[codename] = api_level
1138 return result
1139
1140
Tao Baoaa7e9932019-03-15 09:37:01 -07001141def ReadApexKeysInfo(tf_zip):
1142 """Parses the APEX keys info from a given target-files zip.
1143
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001144 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1145 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1146 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001147
1148 Args:
1149 tf_zip: The input target_files ZipFile (already open).
1150
1151 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001152 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001153 - payload_key contains the path to the payload signing key
1154 - container_key contains the path to the container signing key
1155 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001156 """
1157 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001158 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001159 line = line.strip()
1160 if not line:
1161 continue
1162 matches = re.match(
1163 r'^name="(?P<NAME>.*)"\s+'
1164 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1165 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1166 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001167 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001168 r'(\s+partition="(?P<PARTITION>.*?)")?'
1169 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001170 line)
1171 if not matches:
1172 continue
1173
1174 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001175 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1176
1177 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1178 pubkey_suffix_len = len(pubkey_suffix)
1179 privkey_suffix_len = len(privkey_suffix)
1180 return (pubkey.endswith(pubkey_suffix) and
1181 privkey.endswith(privkey_suffix) and
1182 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1183
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001184 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001185 # extensions. This doesn't apply to payload keys though, which we will use
1186 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001187 container_cert = matches.group("CONTAINER_CERT")
1188 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001189 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1190 container_key = 'PRESIGNED'
1191 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001192 container_cert, OPTIONS.public_key_suffix,
1193 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001194 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1195 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001196 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001197
Jooyung Han8caba5e2021-10-27 03:58:09 +09001198 sign_tool = matches.group("SIGN_TOOL")
1199 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001200
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001201 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001202
1203
Daniel Norman78554ea2021-09-14 10:29:38 -07001204def BuildVendorPartitions(output_zip_path):
1205 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1206 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1207 logger.warning("Allowed --vendor_partitions: %s",
1208 ",".join(ALLOWED_VENDOR_PARTITIONS))
1209 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1210 OPTIONS.vendor_partitions)
1211
1212 logger.info("Building vendor partitions using vendor otatools.")
1213 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1214 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001215 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001216 "RECOVERY/*",
1217 "BOOT/*",
1218 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001219 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1220
1221 # Disable various partitions that build based on misc_info fields.
1222 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1223 # vendor otatools. These other partitions will be rebuilt using the main
1224 # otatools if necessary.
1225 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1226 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001227 # Ignore if not rebuilding recovery
1228 if not OPTIONS.rebuild_recovery:
1229 vendor_misc_info["no_boot"] = "true" # boot
1230 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1231 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001232 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001233
Daniel Norman78554ea2021-09-14 10:29:38 -07001234 vendor_misc_info["has_dtbo"] = "false" # dtbo
1235 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001236 vendor_misc_info["avb_custom_images_partition_list"] = "" # avb custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001237 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Ray-cy.leee97e0cb2023-06-27 11:44:46 +08001238 vendor_misc_info["custom_images_partition_list"] = "" # custom images
Daniel Norman78554ea2021-09-14 10:29:38 -07001239 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1240 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001241 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001242 with open(vendor_misc_info_path, "w") as output:
1243 for key in sorted(vendor_misc_info):
1244 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1245
Po Hu0663ae42021-09-27 12:59:06 +08001246 # Disable system partition by a placeholder of IMAGES/system.img,
1247 # instead of removing SYSTEM folder.
1248 # Because SYSTEM/build.prop is still needed for:
1249 # add_img_to_target_files.CreateImage ->
1250 # common.BuildInfo ->
1251 # common.BuildInfo.CalculateFingerprint
1252 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1253 if not os.path.exists(vendor_images_path):
1254 os.makedirs(vendor_images_path)
1255 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1256 pass
1257
Daniel Norman78554ea2021-09-14 10:29:38 -07001258 # Disable care_map.pb as not all ab_partitions are available when
1259 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001260 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1261 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1262 # Disable RADIO images
1263 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1264 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001265
1266 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001267 # Accept either a zip file or extracted directory.
1268 if os.path.isfile(OPTIONS.vendor_otatools):
1269 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1270 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1271 else:
1272 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001273 cmd = [
1274 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1275 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001276 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001277 "--verbose",
1278 vendor_tempdir,
1279 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001280 if OPTIONS.rebuild_recovery:
1281 cmd.insert(4, "--rebuild_recovery")
1282
Daniel Norman78554ea2021-09-14 10:29:38 -07001283 common.RunAndCheckOutput(cmd, verbose=True)
1284
1285 logger.info("Writing vendor partitions to output archive.")
1286 with zipfile.ZipFile(
1287 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1288 allowZip64=True) as output_zip:
1289 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001290 img_file_path = "IMAGES/{}.img".format(p)
1291 map_file_path = "IMAGES/{}.map".format(p)
1292 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001293 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1294 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001295 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001296 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001297 recovery_img = "IMAGES/recovery.img"
1298 boot_img = "IMAGES/boot.img"
1299 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1300 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001301 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1302 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1303 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1304 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001305
1306
Doug Zongkereef39442009-04-02 12:14:19 -07001307def main(argv):
1308
Doug Zongker831840e2011-09-22 10:28:04 -07001309 key_mapping_options = []
1310
Doug Zongkereef39442009-04-02 12:14:19 -07001311 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001312 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001313 names, key = a.split("=")
1314 names = names.split(",")
1315 for n in names:
1316 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001317 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001318 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001319 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001320 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001321 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001322 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001323 prefix = a.split('/')[0]
1324 if not prefix or prefix != prefix.upper():
1325 raise ValueError("Invalid path prefix '%s'" % (a,))
1326 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001327 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001328 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001329 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001330 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001331 elif o in ("-o", "--replace_ota_keys"):
1332 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001333 elif o in ("-t", "--tag_changes"):
1334 new = []
1335 for i in a.split(","):
1336 i = i.strip()
1337 if not i or i[0] not in "-+":
1338 raise ValueError("Bad tag change '%s'" % (i,))
1339 new.append(i[0] + i[1:].strip())
1340 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001341 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001342 raise ValueError("--replace_verity_public_key is no longer supported,"
1343 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001344 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001345 raise ValueError("--replace_verity_private_key is no longer supported,"
1346 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001347 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001348 raise ValueError("--replace_verity_keyid is no longer supported, please"
1349 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001350 elif o == "--remove_avb_public_keys":
1351 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001352 elif o == "--avb_vbmeta_key":
1353 OPTIONS.avb_keys['vbmeta'] = a
1354 elif o == "--avb_vbmeta_algorithm":
1355 OPTIONS.avb_algorithms['vbmeta'] = a
1356 elif o == "--avb_vbmeta_extra_args":
1357 OPTIONS.avb_extra_args['vbmeta'] = a
1358 elif o == "--avb_boot_key":
1359 OPTIONS.avb_keys['boot'] = a
1360 elif o == "--avb_boot_algorithm":
1361 OPTIONS.avb_algorithms['boot'] = a
1362 elif o == "--avb_boot_extra_args":
1363 OPTIONS.avb_extra_args['boot'] = a
1364 elif o == "--avb_dtbo_key":
1365 OPTIONS.avb_keys['dtbo'] = a
1366 elif o == "--avb_dtbo_algorithm":
1367 OPTIONS.avb_algorithms['dtbo'] = a
1368 elif o == "--avb_dtbo_extra_args":
1369 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001370 elif o == "--avb_init_boot_key":
1371 OPTIONS.avb_keys['init_boot'] = a
1372 elif o == "--avb_init_boot_algorithm":
1373 OPTIONS.avb_algorithms['init_boot'] = a
1374 elif o == "--avb_init_boot_extra_args":
1375 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001376 elif o == "--avb_recovery_key":
1377 OPTIONS.avb_keys['recovery'] = a
1378 elif o == "--avb_recovery_algorithm":
1379 OPTIONS.avb_algorithms['recovery'] = a
1380 elif o == "--avb_recovery_extra_args":
1381 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001382 elif o == "--avb_system_key":
1383 OPTIONS.avb_keys['system'] = a
1384 elif o == "--avb_system_algorithm":
1385 OPTIONS.avb_algorithms['system'] = a
1386 elif o == "--avb_system_extra_args":
1387 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001388 elif o == "--avb_system_other_key":
1389 OPTIONS.avb_keys['system_other'] = a
1390 elif o == "--avb_system_other_algorithm":
1391 OPTIONS.avb_algorithms['system_other'] = a
1392 elif o == "--avb_system_other_extra_args":
1393 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001394 elif o == "--avb_vendor_key":
1395 OPTIONS.avb_keys['vendor'] = a
1396 elif o == "--avb_vendor_algorithm":
1397 OPTIONS.avb_algorithms['vendor'] = a
1398 elif o == "--avb_vendor_extra_args":
1399 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001400 elif o == "--avb_vbmeta_system_key":
1401 OPTIONS.avb_keys['vbmeta_system'] = a
1402 elif o == "--avb_vbmeta_system_algorithm":
1403 OPTIONS.avb_algorithms['vbmeta_system'] = a
1404 elif o == "--avb_vbmeta_system_extra_args":
1405 OPTIONS.avb_extra_args['vbmeta_system'] = a
1406 elif o == "--avb_vbmeta_vendor_key":
1407 OPTIONS.avb_keys['vbmeta_vendor'] = a
1408 elif o == "--avb_vbmeta_vendor_algorithm":
1409 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1410 elif o == "--avb_vbmeta_vendor_extra_args":
1411 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001412 elif o == "--avb_apex_extra_args":
1413 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001414 elif o == "--avb_extra_custom_image_key":
1415 partition, key = a.split("=")
1416 OPTIONS.avb_keys[partition] = key
1417 elif o == "--avb_extra_custom_image_algorithm":
1418 partition, algorithm = a.split("=")
1419 OPTIONS.avb_algorithms[partition] = algorithm
1420 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001421 # Setting the maxsplit parameter to one, which will return a list with
1422 # two elements. e.g., the second '=' should not be splitted for
1423 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1424 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001425 OPTIONS.avb_extra_args[partition] = extra_args
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001426 elif o == "--gki_signing_key":
1427 OPTIONS.gki_signing_key = a
1428 elif o == "--gki_signing_algorithm":
1429 OPTIONS.gki_signing_algorithm = a
1430 elif o == "--gki_signing_extra_args":
1431 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001432 elif o == "--vendor_otatools":
1433 OPTIONS.vendor_otatools = a
1434 elif o == "--vendor_partitions":
1435 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001436 elif o == "--allow_gsi_debug_sepolicy":
1437 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001438 elif o == "--override_apk_keys":
1439 OPTIONS.override_apk_keys = a
1440 elif o == "--override_apex_keys":
1441 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001442 else:
1443 return False
1444 return True
1445
Tao Bao639118f2017-06-19 15:48:02 -07001446 args = common.ParseOptions(
1447 argv, __doc__,
1448 extra_opts="e:d:k:ot:",
1449 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001450 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001451 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001452 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001453 "default_key_mappings=",
1454 "key_mapping=",
1455 "replace_ota_keys",
1456 "tag_changes=",
1457 "replace_verity_public_key=",
1458 "replace_verity_private_key=",
1459 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001460 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001461 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001462 "avb_vbmeta_algorithm=",
1463 "avb_vbmeta_key=",
1464 "avb_vbmeta_extra_args=",
1465 "avb_boot_algorithm=",
1466 "avb_boot_key=",
1467 "avb_boot_extra_args=",
1468 "avb_dtbo_algorithm=",
1469 "avb_dtbo_key=",
1470 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001471 "avb_init_boot_algorithm=",
1472 "avb_init_boot_key=",
1473 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001474 "avb_recovery_algorithm=",
1475 "avb_recovery_key=",
1476 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001477 "avb_system_algorithm=",
1478 "avb_system_key=",
1479 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001480 "avb_system_other_algorithm=",
1481 "avb_system_other_key=",
1482 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001483 "avb_vendor_algorithm=",
1484 "avb_vendor_key=",
1485 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001486 "avb_vbmeta_system_algorithm=",
1487 "avb_vbmeta_system_key=",
1488 "avb_vbmeta_system_extra_args=",
1489 "avb_vbmeta_vendor_algorithm=",
1490 "avb_vbmeta_vendor_key=",
1491 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001492 "avb_extra_custom_image_key=",
1493 "avb_extra_custom_image_algorithm=",
1494 "avb_extra_custom_image_extra_args=",
Yi-Yo Chiang92a517d2023-12-01 07:02:17 +00001495 "gki_signing_key=",
1496 "gki_signing_algorithm=",
1497 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001498 "vendor_partitions=",
1499 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001500 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001501 "override_apk_keys=",
1502 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001503 ],
1504 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001505
1506 if len(args) != 2:
1507 common.Usage(__doc__)
1508 sys.exit(1)
1509
Tao Baobadceb22019-03-15 09:33:43 -07001510 common.InitLogging()
1511
Kelvin Zhang928c2342020-09-22 16:15:57 -04001512 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001513 output_zip = zipfile.ZipFile(args[1], "w",
1514 compression=zipfile.ZIP_DEFLATED,
1515 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001516
Doug Zongker831840e2011-09-22 10:28:04 -07001517 misc_info = common.LoadInfoDict(input_zip)
1518
1519 BuildKeyMap(misc_info, key_mapping_options)
1520
Tao Baoaa7e9932019-03-15 09:37:01 -07001521 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1522 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001523
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001524 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001525 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1526
Tianjie Xu88a759d2020-01-23 10:47:54 -08001527 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1528 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001529 CheckApkAndApexKeysAvailable(
1530 input_zip,
1531 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001532 compressed_extension,
1533 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001534
1535 key_passwords = common.GetKeyPasswords(
1536 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001537 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001538 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001539
Doug Zongker412c02f2014-02-13 10:58:24 -08001540 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001541 apk_keys, apex_keys, key_passwords,
1542 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001543 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001544
Kelvin Zhangf92f7f02023-04-14 21:32:54 +00001545 common.ZipClose(input_zip)
1546 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001547
Daniel Norman78554ea2021-09-14 10:29:38 -07001548 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1549 BuildVendorPartitions(args[1])
1550
Tianjie Xub48589a2016-08-03 19:21:52 -07001551 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001552 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001553 # add_img_to_target_files builds the system image from scratch, so the
1554 # recovery patch is guaranteed to be regenerated there.
1555 if OPTIONS.rebuild_recovery:
1556 new_args.append("--rebuild_recovery")
1557 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001558 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001559
Tao Bao0c28d2d2017-12-24 10:37:38 -08001560 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001561
1562
1563if __name__ == '__main__':
1564 try:
1565 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001566 finally:
1567 common.Cleanup()