blob: 4a12e748da7dfa6c902f05fabf7994054207bc4a [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
86 key file replaces the one at BOOT/RAMDISK/verity_key (or ROOT/verity_key
87 for devices using system_root_image). It expects the key filename WITH
88 the extension (e.g. verity_key.pub).
89
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -070090 --replace_verity_keyid <path_to_X509_PEM_cert_file>
91 Replace the veritykeyid in BOOT/cmdline of input_target_file_zip
Tao Bao8adcfd12016-06-17 17:01:22 -070092 with keyid of the cert pointed by <path_to_X509_PEM_cert_file>.
Tao Bao639118f2017-06-19 15:48:02 -070093
Bowgo Tsai2fe786a2020-02-21 17:48:18 +080094 --remove_avb_public_keys <key1>,<key2>,...
95 Remove AVB public keys from the first-stage ramdisk. The key file to
96 remove is located at either of the following dirs:
97 - BOOT/RAMDISK/avb/ or
98 - BOOT/RAMDISK/first_stage_ramdisk/avb/
99 The second dir will be used for lookup if BOARD_USES_RECOVERY_AS_BOOT is
100 set to true.
101
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800102 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
103 vbmeta_system,vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,init_boot,recovery,system,system_other,vendor,dtbo,vbmeta,
105 vbmeta_system,vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -0700106 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
107 the specified image. Otherwise it uses the existing values in info dict.
108
Hongguang Chen0d6b7272022-11-07 13:36:38 -0800109 --avb_{apex,init_boot,boot,recovery,system,system_other,vendor,dtbo,vbmeta,
Ben Fennema6082d0a2021-12-11 14:03:10 -0800110 vbmeta_system,vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700111 Specify any additional args that are needed to AVB-sign the image
112 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
113 the existing ones in info dict.
Tianjie Xu88a759d2020-01-23 10:47:54 -0800114
Hongguang Chenf23364d2020-04-27 18:36:36 -0700115 --avb_extra_custom_image_key <partition=key>
116 --avb_extra_custom_image_algorithm <partition=algorithm>
117 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
118 the specified custom images mounted on the partition. Otherwise it uses
119 the existing values in info dict.
120
121 --avb_extra_custom_image_extra_args <partition=extra_args>
122 Specify any additional args that are needed to AVB-sign the custom images
123 mounted on the partition (e.g. "--signing_helper /path/to/helper"). The
124 args will be appended to the existing ones in info dict.
125
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800126 --gki_signing_algorithm <algorithm>
127 --gki_signing_key <key>
128 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to generate
129 'boot signature' in a v4 boot.img. Otherwise it uses the existing values
130 in info dict.
131
132 --gki_signing_extra_args <args>
133 Specify any additional args that are needed to generate 'boot signature'
134 (e.g. --prop foo:bar). The args will be appended to the existing ones
135 in info dict.
136
Tianjie Xu88a759d2020-01-23 10:47:54 -0800137 --android_jar_path <path>
138 Path to the android.jar to repack the apex file.
Bowgo Tsai2a781692021-10-13 17:39:33 +0800139
140 --allow_gsi_debug_sepolicy
141 Allow the existence of the file 'userdebug_plat_sepolicy.cil' under
142 (/system/system_ext|/system_ext)/etc/selinux.
143 If not set, error out when the file exists.
Kelvin Zhange50bb512022-08-01 15:58:51 -0700144
145 --override_apk_keys <path>
146 Replace all APK keys with this private key
147
148 --override_apex_keys <path>
149 Replace all APEX keys with this private key
Doug Zongkereef39442009-04-02 12:14:19 -0700150"""
151
Tao Bao0c28d2d2017-12-24 10:37:38 -0800152from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700153
Robert Craig817c5742013-04-19 10:59:22 -0400154import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700155import copy
Robert Craig817c5742013-04-19 10:59:22 -0400156import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100157import gzip
Tao Baobb733882019-07-24 23:31:19 -0700158import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700159import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700160import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700161import os
162import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100163import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700164import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700165import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800166import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700167import tempfile
168import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800169from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700170
Doug Zongker3c84f562014-07-31 11:06:30 -0700171import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700172import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700173import common
174
Tao Bao0c28d2d2017-12-24 10:37:38 -0800175
176if sys.hexversion < 0x02070000:
177 print("Python 2.7 or newer is required.", file=sys.stderr)
178 sys.exit(1)
179
180
Tao Baobadceb22019-03-15 09:33:43 -0700181logger = logging.getLogger(__name__)
182
Doug Zongkereef39442009-04-02 12:14:19 -0700183OPTIONS = common.OPTIONS
184
185OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700186OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700187OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700188OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700189OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700190OPTIONS.replace_ota_keys = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800191OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700192OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700193OPTIONS.avb_keys = {}
194OPTIONS.avb_algorithms = {}
195OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800196OPTIONS.gki_signing_key = None
197OPTIONS.gki_signing_algorithm = None
198OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800199OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700200OPTIONS.vendor_partitions = set()
201OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800202OPTIONS.allow_gsi_debug_sepolicy = False
Kelvin Zhange50bb512022-08-01 15:58:51 -0700203OPTIONS.override_apk_keys = None
204OPTIONS.override_apex_keys = None
Doug Zongkereef39442009-04-02 12:14:19 -0700205
Tao Bao0c28d2d2017-12-24 10:37:38 -0800206
Tao Bao19b02fe2019-10-09 00:04:28 -0700207AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800208 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000209 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800210 'dtbo': 'avb_dtbo_add_hash_footer_args',
211 'product': 'avb_product_add_hashtree_footer_args',
212 'recovery': 'avb_recovery_add_hash_footer_args',
213 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000214 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800215 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
216 'system_other': 'avb_system_other_add_hashtree_footer_args',
217 'odm': 'avb_odm_add_hashtree_footer_args',
218 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
219 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
220 'vendor': 'avb_vendor_add_hashtree_footer_args',
221 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
Lucas Wei03230252022-04-18 16:00:40 +0800222 'vendor_kernel_boot': 'avb_vendor_kernel_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800223 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
224 'vbmeta': 'avb_vbmeta_args',
225 'vbmeta_system': 'avb_vbmeta_system_args',
226 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700227}
228
229
Tianjiebf0b8a82021-03-03 17:31:04 -0800230# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
231for partition in common.AVB_PARTITIONS:
232 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
233 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
234
Daniel Norman78554ea2021-09-14 10:29:38 -0700235# Partitions that can be regenerated after signing using a separate
236# vendor otatools package.
237ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
238
Tianjiebf0b8a82021-03-03 17:31:04 -0800239
Tianjie4d48d502021-06-11 17:03:43 -0700240def IsApexFile(filename):
241 return filename.endswith(".apex") or filename.endswith(".capex")
242
243
244def GetApexFilename(filename):
245 name = os.path.basename(filename)
246 # Replace the suffix for compressed apex
247 if name.endswith(".capex"):
248 return name.replace(".capex", ".apex")
249 return name
250
251
Narayan Kamatha07bf042017-08-14 14:49:21 +0100252def GetApkCerts(certmap):
Kelvin Zhange50bb512022-08-01 15:58:51 -0700253 if OPTIONS.override_apk_keys is not None:
254 for apk in certmap.keys():
255 certmap[apk] = OPTIONS.override_apk_keys
256
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800257 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700258 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800259 certmap[apk] = OPTIONS.key_map.get(cert, cert)
260
261 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700262 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800263 if not cert:
264 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700265 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800266
Doug Zongkereef39442009-04-02 12:14:19 -0700267 return certmap
268
269
Tao Baoaa7e9932019-03-15 09:37:01 -0700270def GetApexKeys(keys_info, key_map):
271 """Gets APEX payload and container signing keys by applying the mapping rules.
272
Tao Baoe1343992019-03-19 12:24:03 -0700273 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700274
275 Args:
276 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900277 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700278 key_map: A dict that overrides the keys, specified via command-line input.
279
280 Returns:
281 A dict that contains the updated APEX key mapping, which should be used for
282 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700283
284 Raises:
285 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700286 """
Kelvin Zhange50bb512022-08-01 15:58:51 -0700287 if OPTIONS.override_apex_keys is not None:
288 for apex in keys_info.keys():
289 keys_info[apex] = (OPTIONS.override_apex_keys, keys_info[apex][1], keys_info[apex][2])
290
291 if OPTIONS.override_apk_keys is not None:
292 key = key_map.get(OPTIONS.override_apk_keys, OPTIONS.override_apk_keys)
293 for apex in keys_info.keys():
294 keys_info[apex] = (keys_info[apex][0], key, keys_info[apex][2])
295
Tao Baoaa7e9932019-03-15 09:37:01 -0700296 # Apply all the --extra_apex_payload_key options to override the payload
297 # signing keys in the given keys_info.
298 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700299 if not key:
300 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700301 if apex not in keys_info:
302 logger.warning('Failed to find %s in target_files; Ignored', apex)
303 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900304 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700305
306 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900307 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
308 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700309
310 # Apply all the --extra_apks options to override the container keys.
311 for apex, key in OPTIONS.extra_apks.items():
312 # Skip non-APEX containers.
313 if apex not in keys_info:
314 continue
Tao Baoe1343992019-03-19 12:24:03 -0700315 if not key:
316 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900317 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700318
Tao Baof98fa102019-04-24 14:51:25 -0700319 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
320 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
321 # (overridden via commandline) indicates a config error, which should not be
322 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900323 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700324 if container_key != 'PRESIGNED':
325 continue
326 if apex in OPTIONS.extra_apex_payload_keys:
327 payload_override = OPTIONS.extra_apex_payload_keys[apex]
328 assert payload_override == '', \
329 ("Invalid APEX key overrides: {} has PRESIGNED container but "
330 "non-PRESIGNED payload key {}").format(apex, payload_override)
331 if payload_key != 'PRESIGNED':
332 print(
333 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
334 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900335 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700336
Tao Baoaa7e9932019-03-15 09:37:01 -0700337 return keys_info
338
339
Tao Bao93c2a012018-06-19 12:19:35 -0700340def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700341 """Returns the APK info based on the given filename.
342
343 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700344 compressed extension into consideration. If it appears to be an APK file,
345 further checks if the APK file should be skipped when signing, based on the
346 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700347
348 Args:
349 filename: Path to the file.
350 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
351 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700352 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700353
354 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700355 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
356 given filename is an APK file. is_compressed indicates whether the APK file
357 is compressed (only meaningful when is_apk is True). should_be_skipped
358 indicates whether the filename matches any of the given prefixes to be
359 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700360
361 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700362 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700363 """
364 assert compressed_extension is None or compressed_extension.startswith('.'), \
365 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
366
Tao Bao93c2a012018-06-19 12:19:35 -0700367 # skipped_prefixes should be one of set/list/tuple types. Other types such as
368 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700369 assert isinstance(skipped_prefixes, (set, list, tuple)), \
370 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700371
Tao Bao11f955c2018-06-19 12:19:35 -0700372 compressed_apk_extension = (
373 ".apk" + compressed_extension if compressed_extension else None)
374 is_apk = (filename.endswith(".apk") or
375 (compressed_apk_extension and
376 filename.endswith(compressed_apk_extension)))
377 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700378 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700379
380 is_compressed = (compressed_apk_extension and
381 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700382 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
383 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700384
385
Tao Baoaa7e9932019-03-15 09:37:01 -0700386def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700387 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700388 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700389
390 Args:
391 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700392 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700393 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700394 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700395 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900396 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700397
398 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700399 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700400 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700401 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700402 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800403 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700404 if IsApexFile(info.filename):
405 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700406 if name not in known_keys:
407 unknown_files.append(name)
408 continue
409
410 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700411 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
412 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
413 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700414 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700415
Tao Bao11f955c2018-06-19 12:19:35 -0700416 name = os.path.basename(info.filename)
417 if is_compressed:
418 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700419 if name not in known_keys:
420 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700421
Tao Baoaa7e9932019-03-15 09:37:01 -0700422 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700423 ("No key specified for:\n {}\n"
424 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700425 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700426
Tao Baoe1343992019-03-19 12:24:03 -0700427 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700428 # one of the payload / container keys set. Note that non-PRESIGNED container
429 # with PRESIGNED payload could be allowed but currently unsupported. It would
430 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700431 if not apex_keys:
432 return
433
434 invalid_apexes = []
435 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700436 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700437 continue
438
Tianjie4d48d502021-06-11 17:03:43 -0700439 name = GetApexFilename(info.filename)
440
Jooyung Han8caba5e2021-10-27 03:58:09 +0900441 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700442 if ((payload_key in common.SPECIAL_CERT_STRINGS and
443 container_key not in common.SPECIAL_CERT_STRINGS) or
444 (payload_key not in common.SPECIAL_CERT_STRINGS and
445 container_key in common.SPECIAL_CERT_STRINGS)):
446 invalid_apexes.append(
447 "{}: payload_key {}, container_key {}".format(
448 name, payload_key, container_key))
449
450 assert not invalid_apexes, \
451 "Invalid APEX keys specified:\n {}\n".format(
452 "\n ".join(invalid_apexes))
453
Doug Zongkereb338ef2009-05-20 16:50:49 -0700454
Narayan Kamatha07bf042017-08-14 14:49:21 +0100455def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700456 is_compressed, apk_name):
457 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700458 unsigned.write(data)
459 unsigned.flush()
460
Narayan Kamatha07bf042017-08-14 14:49:21 +0100461 if is_compressed:
462 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800463 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400464 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100465 shutil.copyfileobj(in_file, out_file)
466
467 # Finally, close the "unsigned" file (which is gzip compressed), and then
468 # replace it with the uncompressed version.
469 #
470 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
471 # we could just gzip / gunzip in-memory buffers instead.
472 unsigned.close()
473 unsigned = uncompressed
474
Oleg Aravin8046cb02020-06-02 16:02:38 -0700475 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700476
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800477 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
478 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
479 # didn't change, we don't want its signature to change due to the switch
480 # from SHA-1 to SHA-256.
481 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
482 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
483 # that the APK's minSdkVersion is 1.
484 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
485 # determine whether to use SHA-256.
486 min_api_level = None
487 if platform_api_level > 23:
488 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
489 # minSdkVersion attribute
490 min_api_level = None
491 else:
492 # Force APK signer to use SHA-1
493 min_api_level = 1
494
495 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800496 min_api_level=min_api_level,
497 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700498
Tao Bao0c28d2d2017-12-24 10:37:38 -0800499 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100500 if is_compressed:
501 # Recompress the file after it has been signed.
502 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800503 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400504 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100505 shutil.copyfileobj(in_file, out_file)
506
507 data = compressed.read()
508 compressed.close()
509 else:
510 data = signed.read()
511
Doug Zongkereef39442009-04-02 12:14:19 -0700512 unsigned.close()
513 signed.close()
514
515 return data
516
Tianjie5bd03952021-02-18 23:02:36 -0800517
Kelvin Zhang119f2792021-02-10 12:45:24 -0500518def IsBuildPropFile(filename):
519 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400520 "SYSTEM/etc/prop.default",
521 "BOOT/RAMDISK/prop.default",
522 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500523
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400524 "VENDOR_BOOT/RAMDISK/default.prop",
525 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500526
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400527 # ROOT/default.prop is a legacy path, but may still exist for upgrading
528 # devices that don't support `property_overrides_split_enabled`.
529 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500530
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400531 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
532 # as a symlink in the current code. So it's a no-op here. Keeping the
533 # path here for clarity.
Kelvin Zhang30669e62023-01-10 21:02:02 -0800534 # Some build props might be stored under path
Hongguang Chen1a732332023-01-29 10:51:19 -0800535 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop, and
536 # default.prop can be a symbolic link to prop.default, so overwrite all
537 # files that ends with build.prop, default.prop or prop.default
Kelvin Zhang30669e62023-01-10 21:02:02 -0800538 "RECOVERY/RAMDISK/default.prop") or \
539 filename.endswith("build.prop") or \
Hongguang Chen1a732332023-01-29 10:51:19 -0800540 filename.endswith("/default.prop") or \
541 filename.endswith("/prop.default")
Doug Zongkereef39442009-04-02 12:14:19 -0700542
Tianjie5bd03952021-02-18 23:02:36 -0800543
Doug Zongker412c02f2014-02-13 10:58:24 -0800544def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700545 apk_keys, apex_keys, key_passwords,
546 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000547 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700548 # maxsize measures the maximum filename length, including the ones to be
549 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800550 try:
551 maxsize = max(
552 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
553 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
554 except ValueError:
555 # Sets this to zero for targets without APK files, e.g., gki_arm64.
556 maxsize = 0
557
Tao Baoa80ed222016-06-16 14:41:24 -0700558 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800559
Doug Zongkereef39442009-04-02 12:14:19 -0700560 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700561 filename = info.filename
562 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700563 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700564
Tao Bao04808502019-07-25 23:11:41 -0700565 # Skip OTA-specific images (e.g. split super images), which will be
566 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800567 if filename.startswith("OTA/") and filename.endswith(".img"):
568 continue
569
Tao Bao11f955c2018-06-19 12:19:35 -0700570 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700571 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700572 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
573 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
574
575 if is_apk and should_be_skipped:
576 # Copy skipped APKs verbatim.
577 print(
578 "NOT signing: %s\n"
579 " (skipped due to matching prefix)" % (filename,))
580 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800581
Tao Baof2cffbd2015-07-22 12:33:18 -0700582 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700583 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700584 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100585 if is_compressed:
586 name = name[:-len(compressed_extension)]
587
Tao Baoaa7e9932019-03-15 09:37:01 -0700588 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800589 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800590 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800591 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700592 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700593 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700594 else:
595 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700596 print(
597 "NOT signing: %s\n"
598 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700599 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700600
Tianjie5bd03952021-02-18 23:02:36 -0800601 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700602 elif IsApexFile(filename):
603 name = GetApexFilename(filename)
604
Jooyung Han8caba5e2021-10-27 03:58:09 +0900605 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700606
Tao Baoe1343992019-03-19 12:24:03 -0700607 # We've asserted not having a case with only one of them PRESIGNED.
608 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400609 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700610 print(" signing: %-*s container (%s)" % (
611 maxsize, name, container_key))
612 print(" : %-*s payload (%s)" % (
613 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700614
Tao Baoe7354ba2019-05-09 16:54:15 -0700615 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700616 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700617 data,
618 payload_key,
619 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300620 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800621 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700622 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400623 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900624 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000625 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700626 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700627
Tao Baoe1343992019-03-19 12:24:03 -0700628 else:
629 print(
630 "NOT signing: %s\n"
631 " (skipped due to special cert string)" % (name,))
632 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700633
Tao Baoa80ed222016-06-16 14:41:24 -0700634 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500635 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700636 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800637 if stat.S_ISLNK(info.external_attr >> 16):
638 new_data = data
639 else:
Tao Baoa3705452019-06-24 15:33:41 -0700640 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700641 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700642
Tao Bao66472632017-12-04 17:16:36 -0800643 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900644 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700645 elif filename.endswith("mac_permissions.xml"):
646 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700647 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700648 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700649
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700650 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700651 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100652 "VENDOR/recovery-from-boot.p",
653
Tao Bao11f955c2018-06-19 12:19:35 -0700654 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100655 "VENDOR/etc/recovery.img",
656
657 "SYSTEM/bin/install-recovery.sh",
658 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700659 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700660
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700661 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700662 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500663 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800664 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700665
Tao Bao46a59992017-06-05 11:55:16 -0700666 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700667 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700668 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700669
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800670 elif (OPTIONS.remove_avb_public_keys and
671 (filename.startswith("BOOT/RAMDISK/avb/") or
672 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400673 matched_removal = False
674 for key_to_remove in OPTIONS.remove_avb_public_keys:
675 if filename.endswith(key_to_remove):
676 matched_removal = True
677 print("Removing AVB public key from ramdisk: %s" % filename)
678 break
679 if not matched_removal:
680 # Copy it verbatim if we don't want to remove it.
681 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700682
Tianjiebbde59f2021-05-03 21:18:56 -0700683 # Skip the vbmeta digest as we will recalculate it.
684 elif filename == "META/vbmeta_digest.txt":
685 pass
686
Tianjie Xu4f099002016-08-11 18:04:27 -0700687 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400688 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700689 pass
690
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500691 # Skip apex_info.pb because we sign/modify apexes
692 elif filename == "META/apex_info.pb":
693 pass
694
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800695 # Updates system_other.avbpubkey in /product/etc/.
696 elif filename in (
697 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800698 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800699 # Only update system_other's public key, if the corresponding signing
700 # key is specified via --avb_system_other_key.
701 signing_key = OPTIONS.avb_keys.get("system_other")
702 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700703 public_key = common.ExtractAvbPublicKey(
704 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800705 print(" Rewriting AVB public key of system_other in /product")
706 common.ZipWrite(output_tf_zip, public_key, filename)
707
Andrew Scullbbc930b2022-02-17 22:34:27 +0000708 # Updates pvmfw embedded public key with the virt APEX payload key.
709 elif filename == "PREBUILT_IMAGES/pvmfw.img":
710 # Find the name of the virt APEX in the target files.
711 namelist = input_tf_zip.namelist()
712 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
713 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
714 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
715 if not virt_apex:
716 print("Removing %s from ramdisk: virt APEX not found" % filename)
717 else:
718 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
719 # Get the current and new embedded keys.
720 payload_key, container_key, sign_tool = apex_keys[virt_apex]
721 new_pubkey_path = common.ExtractAvbPublicKey(
722 misc_info['avb_avbtool'], payload_key)
723 with open(new_pubkey_path, 'rb') as f:
724 new_pubkey = f.read()
725 pubkey_info = copy.copy(
726 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
727 old_pubkey = input_tf_zip.read(pubkey_info.filename)
728 # Validate the keys and image.
729 if len(old_pubkey) != len(new_pubkey):
730 raise common.ExternalError("pvmfw embedded public key size mismatch")
731 pos = data.find(old_pubkey)
732 if pos == -1:
733 raise common.ExternalError("pvmfw embedded public key not found")
734 # Replace the key and copy new files.
735 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
736 common.ZipWriteStr(output_tf_zip, out_info, new_data)
737 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
738 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
739 pass
740
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800741 # Should NOT sign boot-debug.img.
742 elif filename in (
743 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800744 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800745 raise common.ExternalError("debuggable boot.img cannot be signed")
746
Bowgo Tsai2a781692021-10-13 17:39:33 +0800747 # Should NOT sign userdebug sepolicy file.
748 elif filename in (
749 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
750 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
751 if not OPTIONS.allow_gsi_debug_sepolicy:
752 raise common.ExternalError("debug sepolicy shouldn't be included")
753 else:
754 # Copy it verbatim if we allow the file to exist.
755 common.ZipWriteStr(output_tf_zip, out_info, data)
756
Tao Baoa80ed222016-06-16 14:41:24 -0700757 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700758 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700759 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700760
Doug Zongker412c02f2014-02-13 10:58:24 -0800761 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700762 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800763
Tao Bao639118f2017-06-19 15:48:02 -0700764 # Replace the AVB signing keys, if any.
765 ReplaceAvbSigningKeys(misc_info)
766
Tao Bao19b02fe2019-10-09 00:04:28 -0700767 # Rewrite the props in AVB signing args.
768 if misc_info.get('avb_enable') == 'true':
769 RewriteAvbProps(misc_info)
770
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800771 # Replace the GKI signing key for boot.img, if any.
772 ReplaceGkiSigningKey(misc_info)
773
Tao Bao46a59992017-06-05 11:55:16 -0700774 # Write back misc_info with the latest values.
775 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
776
Doug Zongker8e931bf2009-04-06 15:21:45 -0700777
Robert Craig817c5742013-04-19 10:59:22 -0400778def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800779 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400780
Tao Bao66472632017-12-04 17:16:36 -0800781 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
782 be skipped. After the replacement, it additionally checks for duplicate
783 entries, which would otherwise fail the policy loading code in
784 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
785
786 Args:
787 data: Input string that contains a set of X.509 certs.
788
789 Returns:
790 A string after the replacement.
791
792 Raises:
793 AssertionError: On finding duplicate entries.
794 """
Tao Baoa3705452019-06-24 15:33:41 -0700795 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800796 if OPTIONS.verbose:
797 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
798
799 try:
800 with open(old + ".x509.pem") as old_fp:
801 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700802 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800803 with open(new + ".x509.pem") as new_fp:
804 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700805 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800806 except IOError as e:
807 if OPTIONS.verbose or e.errno != errno.ENOENT:
808 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
809 "%s.x509.pem." % (e.filename, e.strerror, old, new))
810 continue
811
812 # Only match entire certs.
813 pattern = "\\b" + old_cert16 + "\\b"
814 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
815
816 if OPTIONS.verbose:
817 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
818 num, old, new))
819
820 # Verify that there're no duplicate entries after the replacement. Note that
821 # it's only checking entries with global seinfo at the moment (i.e. ignoring
822 # the ones with inner packages). (Bug: 69479366)
823 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400824 signatures = [signer.attrib['signature']
825 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800826 assert len(signatures) == len(set(signatures)), \
827 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400828
829 return data
830
831
Doug Zongkerc09abc82010-01-11 13:09:15 -0800832def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800833 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
834
835 Args:
836 tags: The input string that contains comma-separated tags.
837
838 Returns:
839 The updated tags (comma-separated and sorted).
840 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800841 tags = set(tags.split(","))
842 for ch in OPTIONS.tag_changes:
843 if ch[0] == "-":
844 tags.discard(ch[1:])
845 elif ch[0] == "+":
846 tags.add(ch[1:])
847 return ",".join(sorted(tags))
848
849
Tao Baoa7054ee2017-12-08 14:42:16 -0800850def RewriteProps(data):
851 """Rewrites the system properties in the given string.
852
853 Each property is expected in 'key=value' format. The properties that contain
854 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
855 EditTags().
856
857 Args:
858 data: Input string, separated by newlines.
859
860 Returns:
861 The string with modified properties.
862 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700863 output = []
864 for line in data.split("\n"):
865 line = line.strip()
866 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700867 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700868 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200869 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400870 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800871 pieces = value.split("/")
872 pieces[-1] = EditTags(pieces[-1])
873 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700874 elif key == "ro.bootimage.build.fingerprint":
875 pieces = value.split("/")
876 pieces[-1] = EditTags(pieces[-1])
877 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700878 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800879 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500880 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800881 pieces[-1] = EditTags(pieces[-1])
882 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200883 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800884 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700885 elif key == "ro.build.display.id":
886 # change, eg, "JWR66N dev-keys" to "JWR66N"
887 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700888 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800889 value.pop()
890 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800891 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700892 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800893 print(" replace: ", original_line)
894 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700895 output.append(line)
896 return "\n".join(output) + "\n"
897
898
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700899def WriteOtacerts(output_zip, filename, keys):
900 """Constructs a zipfile from given keys; and writes it to output_zip.
901
902 Args:
903 output_zip: The output target_files zip.
904 filename: The archive name in the output zip.
905 keys: A list of public keys to use during OTA package verification.
906 """
Tao Baobb733882019-07-24 23:31:19 -0700907 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400908 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700909 for k in keys:
910 common.ZipWrite(certs_zip, k)
Kelvin Zhang37a42902022-10-26 12:49:03 -0700911 certs_zip.close()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700912 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
913
914
Doug Zongker831840e2011-09-22 10:28:04 -0700915def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700916 try:
917 keylist = input_tf_zip.read("META/otakeys.txt").split()
918 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700919 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700920
Jacky Liubeb0b692021-12-29 16:29:05 +0800921 extra_ota_keys_info = misc_info.get("extra_ota_keys")
922 if extra_ota_keys_info:
923 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
924 for k in extra_ota_keys_info.split()]
925 print("extra ota key(s): " + ", ".join(extra_ota_keys))
926 else:
927 extra_ota_keys = []
928 for k in extra_ota_keys:
929 if not os.path.isfile(k):
930 raise common.ExternalError(k + " does not exist or is not a file")
931
932 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
933 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800934 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800935 for k in extra_recovery_keys_info.split()]
936 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800937 else:
938 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800939 for k in extra_recovery_keys:
940 if not os.path.isfile(k):
941 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800942
Doug Zongker8e931bf2009-04-06 15:21:45 -0700943 mapped_keys = []
944 for k in keylist:
945 m = re.match(r"^(.*)\.x509\.pem$", k)
946 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800947 raise common.ExternalError(
948 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700949 k = m.group(1)
950 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
951
Doug Zongkere05628c2009-08-20 17:38:42 -0700952 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800953 print("using:\n ", "\n ".join(mapped_keys))
954 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700955 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700956 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700957 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800958 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
959 if mapped_devkey != devkey:
960 misc_info["default_system_dev_certificate"] = mapped_devkey
961 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700962 print("META/otakeys.txt has no keys; using %s for OTA package"
963 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800964 for k in mapped_keys:
965 if not os.path.isfile(k):
966 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700967
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500968 otacerts = [info
969 for info in input_tf_zip.infolist()
970 if info.filename.endswith("/otacerts.zip")]
971 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800972 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
973 extra_keys = extra_recovery_keys
974 else:
975 extra_keys = extra_ota_keys
976 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
977 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700978
Tao Baoa80ed222016-06-16 14:41:24 -0700979
Tao Bao46a59992017-06-05 11:55:16 -0700980def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
981 """Replaces META/misc_info.txt.
982
983 Only writes back the ones in the original META/misc_info.txt. Because the
984 current in-memory dict contains additional items computed at runtime.
985 """
986 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700987 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700988 items = []
989 for key in sorted(misc_info):
990 if key in misc_info_old:
991 items.append('%s=%s' % (key, misc_info[key]))
992 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700993
Tao Bao8adcfd12016-06-17 17:01:22 -0700994
Tao Bao639118f2017-06-19 15:48:02 -0700995def ReplaceAvbSigningKeys(misc_info):
996 """Replaces the AVB signing keys."""
997
Tao Bao639118f2017-06-19 15:48:02 -0700998 def ReplaceAvbPartitionSigningKey(partition):
999 key = OPTIONS.avb_keys.get(partition)
1000 if not key:
1001 return
1002
1003 algorithm = OPTIONS.avb_algorithms.get(partition)
1004 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1005
Tao Bao0c28d2d2017-12-24 10:37:38 -08001006 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1007 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001008 misc_info['avb_' + partition + '_algorithm'] = algorithm
1009 misc_info['avb_' + partition + '_key_path'] = key
1010
1011 extra_args = OPTIONS.avb_extra_args.get(partition)
1012 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001013 print('Setting extra AVB signing args for %s to "%s"' % (
1014 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001015 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1016 partition,
1017 # custom partition
1018 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001019 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1020
1021 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1022 ReplaceAvbPartitionSigningKey(partition)
1023
Hongguang Chenf23364d2020-04-27 18:36:36 -07001024 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001025 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001026 ReplaceAvbPartitionSigningKey(custom_partition)
1027
Tao Bao639118f2017-06-19 15:48:02 -07001028
Tao Bao19b02fe2019-10-09 00:04:28 -07001029def RewriteAvbProps(misc_info):
1030 """Rewrites the props in AVB signing args."""
1031 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1032 args = misc_info.get(args_key)
1033 if not args:
1034 continue
1035
1036 tokens = []
1037 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001038 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001039 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1040 if not token.startswith(fingerprint_key):
1041 tokens.append(token)
1042 continue
1043 prefix, tag = token.rsplit('/', 1)
1044 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1045 changed = True
1046
1047 if changed:
1048 result = ' '.join(tokens)
1049 print('Rewriting AVB prop for {}:\n'.format(partition))
1050 print(' replace: {}'.format(args))
1051 print(' with: {}'.format(result))
1052 misc_info[args_key] = result
1053
1054
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001055def ReplaceGkiSigningKey(misc_info):
1056 """Replaces the GKI signing key."""
1057
1058 key = OPTIONS.gki_signing_key
1059 if not key:
1060 return
1061
1062 algorithm = OPTIONS.gki_signing_algorithm
1063 if not algorithm:
1064 raise ValueError("Missing --gki_signing_algorithm")
1065
1066 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1067 misc_info["gki_signing_algorithm"] = algorithm
1068 misc_info["gki_signing_key_path"] = key
1069
1070 extra_args = OPTIONS.gki_signing_extra_args
1071 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001072 print('Setting GKI signing args: "%s"' % (extra_args))
1073 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001074
1075
Doug Zongker831840e2011-09-22 10:28:04 -07001076def BuildKeyMap(misc_info, key_mapping_options):
1077 for s, d in key_mapping_options:
1078 if s is None: # -d option
1079 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001080 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001081 devkeydir = os.path.dirname(devkey)
1082
1083 OPTIONS.key_map.update({
1084 devkeydir + "/testkey": d + "/releasekey",
1085 devkeydir + "/devkey": d + "/releasekey",
1086 devkeydir + "/media": d + "/media",
1087 devkeydir + "/shared": d + "/shared",
1088 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001089 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001090 })
Doug Zongker831840e2011-09-22 10:28:04 -07001091 else:
1092 OPTIONS.key_map[s] = d
1093
1094
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001095def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001096 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001097 api_level = None
1098 codename = None
1099 for line in data.split("\n"):
1100 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001101 if line and line[0] != '#' and "=" in line:
1102 key, value = line.split("=", 1)
1103 key = key.strip()
1104 if key == "ro.build.version.sdk":
1105 api_level = int(value.strip())
1106 elif key == "ro.build.version.codename":
1107 codename = value.strip()
1108
1109 if api_level is None:
1110 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1111 if codename is None:
1112 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1113
1114 return (api_level, codename)
1115
1116
1117def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001118 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001119 api_level = None
1120 codenames = None
1121 for line in data.split("\n"):
1122 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001123 if line and line[0] != '#' and "=" in line:
1124 key, value = line.split("=", 1)
1125 key = key.strip()
1126 if key == "ro.build.version.sdk":
1127 api_level = int(value.strip())
1128 elif key == "ro.build.version.all_codenames":
1129 codenames = value.strip().split(",")
1130
1131 if api_level is None:
1132 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1133 if codenames is None:
1134 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1135
Tao Baoa3705452019-06-24 15:33:41 -07001136 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001137 for codename in codenames:
1138 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001139 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001140 result[codename] = api_level
1141 return result
1142
1143
Tao Baoaa7e9932019-03-15 09:37:01 -07001144def ReadApexKeysInfo(tf_zip):
1145 """Parses the APEX keys info from a given target-files zip.
1146
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001147 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1148 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1149 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001150
1151 Args:
1152 tf_zip: The input target_files ZipFile (already open).
1153
1154 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001155 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001156 - payload_key contains the path to the payload signing key
1157 - container_key contains the path to the container signing key
1158 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001159 """
1160 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001161 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001162 line = line.strip()
1163 if not line:
1164 continue
1165 matches = re.match(
1166 r'^name="(?P<NAME>.*)"\s+'
1167 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1168 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1169 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001170 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001171 r'(\s+partition="(?P<PARTITION>.*?)")?'
1172 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001173 line)
1174 if not matches:
1175 continue
1176
1177 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001178 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1179
1180 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1181 pubkey_suffix_len = len(pubkey_suffix)
1182 privkey_suffix_len = len(privkey_suffix)
1183 return (pubkey.endswith(pubkey_suffix) and
1184 privkey.endswith(privkey_suffix) and
1185 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1186
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001187 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001188 # extensions. This doesn't apply to payload keys though, which we will use
1189 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001190 container_cert = matches.group("CONTAINER_CERT")
1191 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001192 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1193 container_key = 'PRESIGNED'
1194 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001195 container_cert, OPTIONS.public_key_suffix,
1196 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001197 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1198 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001199 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001200
Jooyung Han8caba5e2021-10-27 03:58:09 +09001201 sign_tool = matches.group("SIGN_TOOL")
1202 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001203
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001204 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001205
1206
Daniel Norman78554ea2021-09-14 10:29:38 -07001207def BuildVendorPartitions(output_zip_path):
1208 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1209 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1210 logger.warning("Allowed --vendor_partitions: %s",
1211 ",".join(ALLOWED_VENDOR_PARTITIONS))
1212 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1213 OPTIONS.vendor_partitions)
1214
1215 logger.info("Building vendor partitions using vendor otatools.")
1216 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1217 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001218 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001219 "RECOVERY/*",
1220 "BOOT/*",
1221 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001222 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1223
1224 # Disable various partitions that build based on misc_info fields.
1225 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1226 # vendor otatools. These other partitions will be rebuilt using the main
1227 # otatools if necessary.
1228 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1229 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001230 # Ignore if not rebuilding recovery
1231 if not OPTIONS.rebuild_recovery:
1232 vendor_misc_info["no_boot"] = "true" # boot
1233 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1234 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001235 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001236
Daniel Norman78554ea2021-09-14 10:29:38 -07001237 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1238 vendor_misc_info["has_dtbo"] = "false" # dtbo
1239 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1240 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001241 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001242 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1243 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001244 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001245 with open(vendor_misc_info_path, "w") as output:
1246 for key in sorted(vendor_misc_info):
1247 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1248
Po Hu0663ae42021-09-27 12:59:06 +08001249 # Disable system partition by a placeholder of IMAGES/system.img,
1250 # instead of removing SYSTEM folder.
1251 # Because SYSTEM/build.prop is still needed for:
1252 # add_img_to_target_files.CreateImage ->
1253 # common.BuildInfo ->
1254 # common.BuildInfo.CalculateFingerprint
1255 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1256 if not os.path.exists(vendor_images_path):
1257 os.makedirs(vendor_images_path)
1258 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1259 pass
1260
Daniel Norman78554ea2021-09-14 10:29:38 -07001261 # Disable care_map.pb as not all ab_partitions are available when
1262 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001263 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1264 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1265 # Disable RADIO images
1266 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1267 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001268
1269 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001270 # Accept either a zip file or extracted directory.
1271 if os.path.isfile(OPTIONS.vendor_otatools):
1272 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1273 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1274 else:
1275 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001276 cmd = [
1277 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1278 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001279 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001280 "--verbose",
1281 vendor_tempdir,
1282 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001283 if OPTIONS.rebuild_recovery:
1284 cmd.insert(4, "--rebuild_recovery")
1285
Daniel Norman78554ea2021-09-14 10:29:38 -07001286 common.RunAndCheckOutput(cmd, verbose=True)
1287
1288 logger.info("Writing vendor partitions to output archive.")
1289 with zipfile.ZipFile(
1290 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1291 allowZip64=True) as output_zip:
1292 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001293 img_file_path = "IMAGES/{}.img".format(p)
1294 map_file_path = "IMAGES/{}.map".format(p)
1295 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001296 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1297 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001298 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001299 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001300 recovery_img = "IMAGES/recovery.img"
1301 boot_img = "IMAGES/boot.img"
1302 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1303 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001304 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1305 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1306 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1307 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001308
1309
Doug Zongkereef39442009-04-02 12:14:19 -07001310def main(argv):
1311
Doug Zongker831840e2011-09-22 10:28:04 -07001312 key_mapping_options = []
1313
Doug Zongkereef39442009-04-02 12:14:19 -07001314 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001315 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001316 names, key = a.split("=")
1317 names = names.split(",")
1318 for n in names:
1319 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001320 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001321 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001322 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001323 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001324 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001325 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001326 prefix = a.split('/')[0]
1327 if not prefix or prefix != prefix.upper():
1328 raise ValueError("Invalid path prefix '%s'" % (a,))
1329 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001330 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001331 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001332 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001333 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001334 elif o in ("-o", "--replace_ota_keys"):
1335 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001336 elif o in ("-t", "--tag_changes"):
1337 new = []
1338 for i in a.split(","):
1339 i = i.strip()
1340 if not i or i[0] not in "-+":
1341 raise ValueError("Bad tag change '%s'" % (i,))
1342 new.append(i[0] + i[1:].strip())
1343 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001344 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001345 raise ValueError("--replace_verity_public_key is no longer supported,"
1346 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001347 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001348 raise ValueError("--replace_verity_private_key is no longer supported,"
1349 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001350 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001351 raise ValueError("--replace_verity_keyid is no longer supported, please"
1352 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001353 elif o == "--remove_avb_public_keys":
1354 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001355 elif o == "--avb_vbmeta_key":
1356 OPTIONS.avb_keys['vbmeta'] = a
1357 elif o == "--avb_vbmeta_algorithm":
1358 OPTIONS.avb_algorithms['vbmeta'] = a
1359 elif o == "--avb_vbmeta_extra_args":
1360 OPTIONS.avb_extra_args['vbmeta'] = a
1361 elif o == "--avb_boot_key":
1362 OPTIONS.avb_keys['boot'] = a
1363 elif o == "--avb_boot_algorithm":
1364 OPTIONS.avb_algorithms['boot'] = a
1365 elif o == "--avb_boot_extra_args":
1366 OPTIONS.avb_extra_args['boot'] = a
1367 elif o == "--avb_dtbo_key":
1368 OPTIONS.avb_keys['dtbo'] = a
1369 elif o == "--avb_dtbo_algorithm":
1370 OPTIONS.avb_algorithms['dtbo'] = a
1371 elif o == "--avb_dtbo_extra_args":
1372 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001373 elif o == "--avb_init_boot_key":
1374 OPTIONS.avb_keys['init_boot'] = a
1375 elif o == "--avb_init_boot_algorithm":
1376 OPTIONS.avb_algorithms['init_boot'] = a
1377 elif o == "--avb_init_boot_extra_args":
1378 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001379 elif o == "--avb_recovery_key":
1380 OPTIONS.avb_keys['recovery'] = a
1381 elif o == "--avb_recovery_algorithm":
1382 OPTIONS.avb_algorithms['recovery'] = a
1383 elif o == "--avb_recovery_extra_args":
1384 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001385 elif o == "--avb_system_key":
1386 OPTIONS.avb_keys['system'] = a
1387 elif o == "--avb_system_algorithm":
1388 OPTIONS.avb_algorithms['system'] = a
1389 elif o == "--avb_system_extra_args":
1390 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001391 elif o == "--avb_system_other_key":
1392 OPTIONS.avb_keys['system_other'] = a
1393 elif o == "--avb_system_other_algorithm":
1394 OPTIONS.avb_algorithms['system_other'] = a
1395 elif o == "--avb_system_other_extra_args":
1396 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001397 elif o == "--avb_vendor_key":
1398 OPTIONS.avb_keys['vendor'] = a
1399 elif o == "--avb_vendor_algorithm":
1400 OPTIONS.avb_algorithms['vendor'] = a
1401 elif o == "--avb_vendor_extra_args":
1402 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001403 elif o == "--avb_vbmeta_system_key":
1404 OPTIONS.avb_keys['vbmeta_system'] = a
1405 elif o == "--avb_vbmeta_system_algorithm":
1406 OPTIONS.avb_algorithms['vbmeta_system'] = a
1407 elif o == "--avb_vbmeta_system_extra_args":
1408 OPTIONS.avb_extra_args['vbmeta_system'] = a
1409 elif o == "--avb_vbmeta_vendor_key":
1410 OPTIONS.avb_keys['vbmeta_vendor'] = a
1411 elif o == "--avb_vbmeta_vendor_algorithm":
1412 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1413 elif o == "--avb_vbmeta_vendor_extra_args":
1414 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001415 elif o == "--avb_apex_extra_args":
1416 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001417 elif o == "--avb_extra_custom_image_key":
1418 partition, key = a.split("=")
1419 OPTIONS.avb_keys[partition] = key
1420 elif o == "--avb_extra_custom_image_algorithm":
1421 partition, algorithm = a.split("=")
1422 OPTIONS.avb_algorithms[partition] = algorithm
1423 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001424 # Setting the maxsplit parameter to one, which will return a list with
1425 # two elements. e.g., the second '=' should not be splitted for
1426 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1427 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001428 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001429 elif o == "--gki_signing_key":
1430 OPTIONS.gki_signing_key = a
1431 elif o == "--gki_signing_algorithm":
1432 OPTIONS.gki_signing_algorithm = a
1433 elif o == "--gki_signing_extra_args":
1434 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001435 elif o == "--vendor_otatools":
1436 OPTIONS.vendor_otatools = a
1437 elif o == "--vendor_partitions":
1438 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001439 elif o == "--allow_gsi_debug_sepolicy":
1440 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001441 elif o == "--override_apk_keys":
1442 OPTIONS.override_apk_keys = a
1443 elif o == "--override_apex_keys":
1444 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001445 else:
1446 return False
1447 return True
1448
Tao Bao639118f2017-06-19 15:48:02 -07001449 args = common.ParseOptions(
1450 argv, __doc__,
1451 extra_opts="e:d:k:ot:",
1452 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001453 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001454 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001455 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001456 "default_key_mappings=",
1457 "key_mapping=",
1458 "replace_ota_keys",
1459 "tag_changes=",
1460 "replace_verity_public_key=",
1461 "replace_verity_private_key=",
1462 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001463 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001464 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001465 "avb_vbmeta_algorithm=",
1466 "avb_vbmeta_key=",
1467 "avb_vbmeta_extra_args=",
1468 "avb_boot_algorithm=",
1469 "avb_boot_key=",
1470 "avb_boot_extra_args=",
1471 "avb_dtbo_algorithm=",
1472 "avb_dtbo_key=",
1473 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001474 "avb_init_boot_algorithm=",
1475 "avb_init_boot_key=",
1476 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001477 "avb_recovery_algorithm=",
1478 "avb_recovery_key=",
1479 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001480 "avb_system_algorithm=",
1481 "avb_system_key=",
1482 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001483 "avb_system_other_algorithm=",
1484 "avb_system_other_key=",
1485 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001486 "avb_vendor_algorithm=",
1487 "avb_vendor_key=",
1488 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001489 "avb_vbmeta_system_algorithm=",
1490 "avb_vbmeta_system_key=",
1491 "avb_vbmeta_system_extra_args=",
1492 "avb_vbmeta_vendor_algorithm=",
1493 "avb_vbmeta_vendor_key=",
1494 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001495 "avb_extra_custom_image_key=",
1496 "avb_extra_custom_image_algorithm=",
1497 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001498 "gki_signing_key=",
1499 "gki_signing_algorithm=",
1500 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001501 "vendor_partitions=",
1502 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001503 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001504 "override_apk_keys=",
1505 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001506 ],
1507 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001508
1509 if len(args) != 2:
1510 common.Usage(__doc__)
1511 sys.exit(1)
1512
Tao Baobadceb22019-03-15 09:33:43 -07001513 common.InitLogging()
1514
Kelvin Zhang928c2342020-09-22 16:15:57 -04001515 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001516 output_zip = zipfile.ZipFile(args[1], "w",
1517 compression=zipfile.ZIP_DEFLATED,
1518 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001519
Doug Zongker831840e2011-09-22 10:28:04 -07001520 misc_info = common.LoadInfoDict(input_zip)
1521
1522 BuildKeyMap(misc_info, key_mapping_options)
1523
Tao Baoaa7e9932019-03-15 09:37:01 -07001524 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1525 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001526
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001527 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001528 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1529
Tianjie Xu88a759d2020-01-23 10:47:54 -08001530 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1531 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001532 CheckApkAndApexKeysAvailable(
1533 input_zip,
1534 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001535 compressed_extension,
1536 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001537
1538 key_passwords = common.GetKeyPasswords(
1539 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001540 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001541 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001542
Doug Zongker412c02f2014-02-13 10:58:24 -08001543 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001544 apk_keys, apex_keys, key_passwords,
1545 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001546 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001547
Kelvin Zhang37a42902022-10-26 12:49:03 -07001548 input_zip.close()
1549 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001550
Daniel Norman78554ea2021-09-14 10:29:38 -07001551 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1552 BuildVendorPartitions(args[1])
1553
Tianjie Xub48589a2016-08-03 19:21:52 -07001554 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001555 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001556 # add_img_to_target_files builds the system image from scratch, so the
1557 # recovery patch is guaranteed to be regenerated there.
1558 if OPTIONS.rebuild_recovery:
1559 new_args.append("--rebuild_recovery")
1560 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001561 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001562
Tao Bao0c28d2d2017-12-24 10:37:38 -08001563 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001564
1565
1566if __name__ == '__main__':
1567 try:
1568 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001569 finally:
1570 common.Cleanup()