blob: 0dd0790df078b9d7d298b699fa9065cfb9460433 [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
535 # VENDOR_BOOT/RAMDISK_FRAGMENTS/recovery/RAMDISK/default.prop
536 # so overwrite all files that ends with build.prop or default.prop
537 "RECOVERY/RAMDISK/default.prop") or \
538 filename.endswith("build.prop") or \
539 filename.endswith("/default.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700540
Tianjie5bd03952021-02-18 23:02:36 -0800541
Doug Zongker412c02f2014-02-13 10:58:24 -0800542def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700543 apk_keys, apex_keys, key_passwords,
544 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000545 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700546 # maxsize measures the maximum filename length, including the ones to be
547 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800548 try:
549 maxsize = max(
550 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
551 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
552 except ValueError:
553 # Sets this to zero for targets without APK files, e.g., gki_arm64.
554 maxsize = 0
555
Tao Baoa80ed222016-06-16 14:41:24 -0700556 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800557
Doug Zongkereef39442009-04-02 12:14:19 -0700558 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700559 filename = info.filename
560 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700561 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700562
Tao Bao04808502019-07-25 23:11:41 -0700563 # Skip OTA-specific images (e.g. split super images), which will be
564 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800565 if filename.startswith("OTA/") and filename.endswith(".img"):
566 continue
567
Tao Bao11f955c2018-06-19 12:19:35 -0700568 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700569 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700570 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
571 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
572
573 if is_apk and should_be_skipped:
574 # Copy skipped APKs verbatim.
575 print(
576 "NOT signing: %s\n"
577 " (skipped due to matching prefix)" % (filename,))
578 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800579
Tao Baof2cffbd2015-07-22 12:33:18 -0700580 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700581 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700582 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100583 if is_compressed:
584 name = name[:-len(compressed_extension)]
585
Tao Baoaa7e9932019-03-15 09:37:01 -0700586 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800587 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800588 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800589 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700590 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700591 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700592 else:
593 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700594 print(
595 "NOT signing: %s\n"
596 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700597 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700598
Tianjie5bd03952021-02-18 23:02:36 -0800599 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700600 elif IsApexFile(filename):
601 name = GetApexFilename(filename)
602
Jooyung Han8caba5e2021-10-27 03:58:09 +0900603 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700604
Tao Baoe1343992019-03-19 12:24:03 -0700605 # We've asserted not having a case with only one of them PRESIGNED.
606 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400607 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700608 print(" signing: %-*s container (%s)" % (
609 maxsize, name, container_key))
610 print(" : %-*s payload (%s)" % (
611 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700612
Tao Baoe7354ba2019-05-09 16:54:15 -0700613 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700614 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700615 data,
616 payload_key,
617 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300618 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800619 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700620 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400621 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900622 signing_args=OPTIONS.avb_extra_args.get('apex'),
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +0000623 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700624 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700625
Tao Baoe1343992019-03-19 12:24:03 -0700626 else:
627 print(
628 "NOT signing: %s\n"
629 " (skipped due to special cert string)" % (name,))
630 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700631
Tao Baoa80ed222016-06-16 14:41:24 -0700632 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500633 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700634 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800635 if stat.S_ISLNK(info.external_attr >> 16):
636 new_data = data
637 else:
Tao Baoa3705452019-06-24 15:33:41 -0700638 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700639 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700640
Tao Bao66472632017-12-04 17:16:36 -0800641 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900642 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700643 elif filename.endswith("mac_permissions.xml"):
644 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700645 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700646 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700647
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700648 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700649 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100650 "VENDOR/recovery-from-boot.p",
651
Tao Bao11f955c2018-06-19 12:19:35 -0700652 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100653 "VENDOR/etc/recovery.img",
654
655 "SYSTEM/bin/install-recovery.sh",
656 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700657 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700658
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700659 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700660 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500661 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800662 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700663
Tao Bao46a59992017-06-05 11:55:16 -0700664 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700665 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700666 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700667
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800668 elif (OPTIONS.remove_avb_public_keys and
669 (filename.startswith("BOOT/RAMDISK/avb/") or
670 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400671 matched_removal = False
672 for key_to_remove in OPTIONS.remove_avb_public_keys:
673 if filename.endswith(key_to_remove):
674 matched_removal = True
675 print("Removing AVB public key from ramdisk: %s" % filename)
676 break
677 if not matched_removal:
678 # Copy it verbatim if we don't want to remove it.
679 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700680
Tianjiebbde59f2021-05-03 21:18:56 -0700681 # Skip the vbmeta digest as we will recalculate it.
682 elif filename == "META/vbmeta_digest.txt":
683 pass
684
Tianjie Xu4f099002016-08-11 18:04:27 -0700685 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400686 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700687 pass
688
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500689 # Skip apex_info.pb because we sign/modify apexes
690 elif filename == "META/apex_info.pb":
691 pass
692
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800693 # Updates system_other.avbpubkey in /product/etc/.
694 elif filename in (
695 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800696 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800697 # Only update system_other's public key, if the corresponding signing
698 # key is specified via --avb_system_other_key.
699 signing_key = OPTIONS.avb_keys.get("system_other")
700 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700701 public_key = common.ExtractAvbPublicKey(
702 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800703 print(" Rewriting AVB public key of system_other in /product")
704 common.ZipWrite(output_tf_zip, public_key, filename)
705
Andrew Scullbbc930b2022-02-17 22:34:27 +0000706 # Updates pvmfw embedded public key with the virt APEX payload key.
707 elif filename == "PREBUILT_IMAGES/pvmfw.img":
708 # Find the name of the virt APEX in the target files.
709 namelist = input_tf_zip.namelist()
710 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
711 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
712 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
713 if not virt_apex:
714 print("Removing %s from ramdisk: virt APEX not found" % filename)
715 else:
716 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
717 # Get the current and new embedded keys.
718 payload_key, container_key, sign_tool = apex_keys[virt_apex]
719 new_pubkey_path = common.ExtractAvbPublicKey(
720 misc_info['avb_avbtool'], payload_key)
721 with open(new_pubkey_path, 'rb') as f:
722 new_pubkey = f.read()
723 pubkey_info = copy.copy(
724 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
725 old_pubkey = input_tf_zip.read(pubkey_info.filename)
726 # Validate the keys and image.
727 if len(old_pubkey) != len(new_pubkey):
728 raise common.ExternalError("pvmfw embedded public key size mismatch")
729 pos = data.find(old_pubkey)
730 if pos == -1:
731 raise common.ExternalError("pvmfw embedded public key not found")
732 # Replace the key and copy new files.
733 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
734 common.ZipWriteStr(output_tf_zip, out_info, new_data)
735 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
736 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
737 pass
738
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800739 # Should NOT sign boot-debug.img.
740 elif filename in (
741 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800742 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800743 raise common.ExternalError("debuggable boot.img cannot be signed")
744
Bowgo Tsai2a781692021-10-13 17:39:33 +0800745 # Should NOT sign userdebug sepolicy file.
746 elif filename in (
747 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
748 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
749 if not OPTIONS.allow_gsi_debug_sepolicy:
750 raise common.ExternalError("debug sepolicy shouldn't be included")
751 else:
752 # Copy it verbatim if we allow the file to exist.
753 common.ZipWriteStr(output_tf_zip, out_info, data)
754
Tao Baoa80ed222016-06-16 14:41:24 -0700755 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700756 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700757 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700758
Doug Zongker412c02f2014-02-13 10:58:24 -0800759 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700760 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800761
Tao Bao639118f2017-06-19 15:48:02 -0700762 # Replace the AVB signing keys, if any.
763 ReplaceAvbSigningKeys(misc_info)
764
Tao Bao19b02fe2019-10-09 00:04:28 -0700765 # Rewrite the props in AVB signing args.
766 if misc_info.get('avb_enable') == 'true':
767 RewriteAvbProps(misc_info)
768
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800769 # Replace the GKI signing key for boot.img, if any.
770 ReplaceGkiSigningKey(misc_info)
771
Tao Bao46a59992017-06-05 11:55:16 -0700772 # Write back misc_info with the latest values.
773 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
774
Doug Zongker8e931bf2009-04-06 15:21:45 -0700775
Robert Craig817c5742013-04-19 10:59:22 -0400776def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800777 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400778
Tao Bao66472632017-12-04 17:16:36 -0800779 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
780 be skipped. After the replacement, it additionally checks for duplicate
781 entries, which would otherwise fail the policy loading code in
782 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
783
784 Args:
785 data: Input string that contains a set of X.509 certs.
786
787 Returns:
788 A string after the replacement.
789
790 Raises:
791 AssertionError: On finding duplicate entries.
792 """
Tao Baoa3705452019-06-24 15:33:41 -0700793 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800794 if OPTIONS.verbose:
795 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
796
797 try:
798 with open(old + ".x509.pem") as old_fp:
799 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700800 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800801 with open(new + ".x509.pem") as new_fp:
802 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700803 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800804 except IOError as e:
805 if OPTIONS.verbose or e.errno != errno.ENOENT:
806 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
807 "%s.x509.pem." % (e.filename, e.strerror, old, new))
808 continue
809
810 # Only match entire certs.
811 pattern = "\\b" + old_cert16 + "\\b"
812 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
813
814 if OPTIONS.verbose:
815 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
816 num, old, new))
817
818 # Verify that there're no duplicate entries after the replacement. Note that
819 # it's only checking entries with global seinfo at the moment (i.e. ignoring
820 # the ones with inner packages). (Bug: 69479366)
821 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400822 signatures = [signer.attrib['signature']
823 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800824 assert len(signatures) == len(set(signatures)), \
825 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400826
827 return data
828
829
Doug Zongkerc09abc82010-01-11 13:09:15 -0800830def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800831 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
832
833 Args:
834 tags: The input string that contains comma-separated tags.
835
836 Returns:
837 The updated tags (comma-separated and sorted).
838 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800839 tags = set(tags.split(","))
840 for ch in OPTIONS.tag_changes:
841 if ch[0] == "-":
842 tags.discard(ch[1:])
843 elif ch[0] == "+":
844 tags.add(ch[1:])
845 return ",".join(sorted(tags))
846
847
Tao Baoa7054ee2017-12-08 14:42:16 -0800848def RewriteProps(data):
849 """Rewrites the system properties in the given string.
850
851 Each property is expected in 'key=value' format. The properties that contain
852 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
853 EditTags().
854
855 Args:
856 data: Input string, separated by newlines.
857
858 Returns:
859 The string with modified properties.
860 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700861 output = []
862 for line in data.split("\n"):
863 line = line.strip()
864 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700865 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700866 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200867 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400868 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800869 pieces = value.split("/")
870 pieces[-1] = EditTags(pieces[-1])
871 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700872 elif key == "ro.bootimage.build.fingerprint":
873 pieces = value.split("/")
874 pieces[-1] = EditTags(pieces[-1])
875 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700876 elif key == "ro.build.description":
jiajia tange5ddfcd2022-06-21 10:36:12 +0800877 pieces = value.split()
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500878 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800879 pieces[-1] = EditTags(pieces[-1])
880 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200881 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800882 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700883 elif key == "ro.build.display.id":
884 # change, eg, "JWR66N dev-keys" to "JWR66N"
885 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700886 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800887 value.pop()
888 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800889 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700890 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800891 print(" replace: ", original_line)
892 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700893 output.append(line)
894 return "\n".join(output) + "\n"
895
896
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700897def WriteOtacerts(output_zip, filename, keys):
898 """Constructs a zipfile from given keys; and writes it to output_zip.
899
900 Args:
901 output_zip: The output target_files zip.
902 filename: The archive name in the output zip.
903 keys: A list of public keys to use during OTA package verification.
904 """
Tao Baobb733882019-07-24 23:31:19 -0700905 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400906 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700907 for k in keys:
908 common.ZipWrite(certs_zip, k)
Kelvin Zhang37a42902022-10-26 12:49:03 -0700909 certs_zip.close()
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700910 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
911
912
Doug Zongker831840e2011-09-22 10:28:04 -0700913def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700914 try:
915 keylist = input_tf_zip.read("META/otakeys.txt").split()
916 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700917 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700918
Jacky Liubeb0b692021-12-29 16:29:05 +0800919 extra_ota_keys_info = misc_info.get("extra_ota_keys")
920 if extra_ota_keys_info:
921 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
922 for k in extra_ota_keys_info.split()]
923 print("extra ota key(s): " + ", ".join(extra_ota_keys))
924 else:
925 extra_ota_keys = []
926 for k in extra_ota_keys:
927 if not os.path.isfile(k):
928 raise common.ExternalError(k + " does not exist or is not a file")
929
930 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
931 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800932 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800933 for k in extra_recovery_keys_info.split()]
934 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800935 else:
936 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800937 for k in extra_recovery_keys:
938 if not os.path.isfile(k):
939 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800940
Doug Zongker8e931bf2009-04-06 15:21:45 -0700941 mapped_keys = []
942 for k in keylist:
943 m = re.match(r"^(.*)\.x509\.pem$", k)
944 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800945 raise common.ExternalError(
946 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700947 k = m.group(1)
948 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
949
Doug Zongkere05628c2009-08-20 17:38:42 -0700950 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800951 print("using:\n ", "\n ".join(mapped_keys))
952 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700953 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700954 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700955 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800956 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
957 if mapped_devkey != devkey:
958 misc_info["default_system_dev_certificate"] = mapped_devkey
959 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700960 print("META/otakeys.txt has no keys; using %s for OTA package"
961 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800962 for k in mapped_keys:
963 if not os.path.isfile(k):
964 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700965
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500966 otacerts = [info
967 for info in input_tf_zip.infolist()
968 if info.filename.endswith("/otacerts.zip")]
969 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800970 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
971 extra_keys = extra_recovery_keys
972 else:
973 extra_keys = extra_ota_keys
974 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
975 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700976
Tao Baoa80ed222016-06-16 14:41:24 -0700977
Tao Bao46a59992017-06-05 11:55:16 -0700978def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
979 """Replaces META/misc_info.txt.
980
981 Only writes back the ones in the original META/misc_info.txt. Because the
982 current in-memory dict contains additional items computed at runtime.
983 """
984 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -0700985 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -0700986 items = []
987 for key in sorted(misc_info):
988 if key in misc_info_old:
989 items.append('%s=%s' % (key, misc_info[key]))
990 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700991
Tao Bao8adcfd12016-06-17 17:01:22 -0700992
Tao Bao639118f2017-06-19 15:48:02 -0700993def ReplaceAvbSigningKeys(misc_info):
994 """Replaces the AVB signing keys."""
995
Tao Bao639118f2017-06-19 15:48:02 -0700996 def ReplaceAvbPartitionSigningKey(partition):
997 key = OPTIONS.avb_keys.get(partition)
998 if not key:
999 return
1000
1001 algorithm = OPTIONS.avb_algorithms.get(partition)
1002 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1003
Tao Bao0c28d2d2017-12-24 10:37:38 -08001004 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1005 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001006 misc_info['avb_' + partition + '_algorithm'] = algorithm
1007 misc_info['avb_' + partition + '_key_path'] = key
1008
1009 extra_args = OPTIONS.avb_extra_args.get(partition)
1010 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001011 print('Setting extra AVB signing args for %s to "%s"' % (
1012 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001013 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1014 partition,
1015 # custom partition
1016 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001017 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1018
1019 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1020 ReplaceAvbPartitionSigningKey(partition)
1021
Hongguang Chenf23364d2020-04-27 18:36:36 -07001022 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001023 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001024 ReplaceAvbPartitionSigningKey(custom_partition)
1025
Tao Bao639118f2017-06-19 15:48:02 -07001026
Tao Bao19b02fe2019-10-09 00:04:28 -07001027def RewriteAvbProps(misc_info):
1028 """Rewrites the props in AVB signing args."""
1029 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1030 args = misc_info.get(args_key)
1031 if not args:
1032 continue
1033
1034 tokens = []
1035 changed = False
jiajia tange5ddfcd2022-06-21 10:36:12 +08001036 for token in args.split():
Tao Bao19b02fe2019-10-09 00:04:28 -07001037 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1038 if not token.startswith(fingerprint_key):
1039 tokens.append(token)
1040 continue
1041 prefix, tag = token.rsplit('/', 1)
1042 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1043 changed = True
1044
1045 if changed:
1046 result = ' '.join(tokens)
1047 print('Rewriting AVB prop for {}:\n'.format(partition))
1048 print(' replace: {}'.format(args))
1049 print(' with: {}'.format(result))
1050 misc_info[args_key] = result
1051
1052
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001053def ReplaceGkiSigningKey(misc_info):
1054 """Replaces the GKI signing key."""
1055
1056 key = OPTIONS.gki_signing_key
1057 if not key:
1058 return
1059
1060 algorithm = OPTIONS.gki_signing_algorithm
1061 if not algorithm:
1062 raise ValueError("Missing --gki_signing_algorithm")
1063
1064 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1065 misc_info["gki_signing_algorithm"] = algorithm
1066 misc_info["gki_signing_key_path"] = key
1067
1068 extra_args = OPTIONS.gki_signing_extra_args
1069 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001070 print('Setting GKI signing args: "%s"' % (extra_args))
1071 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001072
1073
Doug Zongker831840e2011-09-22 10:28:04 -07001074def BuildKeyMap(misc_info, key_mapping_options):
1075 for s, d in key_mapping_options:
1076 if s is None: # -d option
1077 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001078 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001079 devkeydir = os.path.dirname(devkey)
1080
1081 OPTIONS.key_map.update({
1082 devkeydir + "/testkey": d + "/releasekey",
1083 devkeydir + "/devkey": d + "/releasekey",
1084 devkeydir + "/media": d + "/media",
1085 devkeydir + "/shared": d + "/shared",
1086 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001087 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001088 })
Doug Zongker831840e2011-09-22 10:28:04 -07001089 else:
1090 OPTIONS.key_map[s] = d
1091
1092
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001093def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001094 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001095 api_level = None
1096 codename = None
1097 for line in data.split("\n"):
1098 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001099 if line and line[0] != '#' and "=" in line:
1100 key, value = line.split("=", 1)
1101 key = key.strip()
1102 if key == "ro.build.version.sdk":
1103 api_level = int(value.strip())
1104 elif key == "ro.build.version.codename":
1105 codename = value.strip()
1106
1107 if api_level is None:
1108 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1109 if codename is None:
1110 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1111
1112 return (api_level, codename)
1113
1114
1115def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001116 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001117 api_level = None
1118 codenames = None
1119 for line in data.split("\n"):
1120 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001121 if line and line[0] != '#' and "=" in line:
1122 key, value = line.split("=", 1)
1123 key = key.strip()
1124 if key == "ro.build.version.sdk":
1125 api_level = int(value.strip())
1126 elif key == "ro.build.version.all_codenames":
1127 codenames = value.strip().split(",")
1128
1129 if api_level is None:
1130 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1131 if codenames is None:
1132 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1133
Tao Baoa3705452019-06-24 15:33:41 -07001134 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001135 for codename in codenames:
1136 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001137 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001138 result[codename] = api_level
1139 return result
1140
1141
Tao Baoaa7e9932019-03-15 09:37:01 -07001142def ReadApexKeysInfo(tf_zip):
1143 """Parses the APEX keys info from a given target-files zip.
1144
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001145 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1146 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
1147 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001148
1149 Args:
1150 tf_zip: The input target_files ZipFile (already open).
1151
1152 Returns:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001153 (payload_key, container_key, sign_tool):
Jooyung Han8caba5e2021-10-27 03:58:09 +09001154 - payload_key contains the path to the payload signing key
1155 - container_key contains the path to the container signing key
1156 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001157 """
1158 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001159 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001160 line = line.strip()
1161 if not line:
1162 continue
1163 matches = re.match(
1164 r'^name="(?P<NAME>.*)"\s+'
1165 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1166 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1167 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001168 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001169 r'(\s+partition="(?P<PARTITION>.*?)")?'
1170 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001171 line)
1172 if not matches:
1173 continue
1174
1175 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001176 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1177
1178 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1179 pubkey_suffix_len = len(pubkey_suffix)
1180 privkey_suffix_len = len(privkey_suffix)
1181 return (pubkey.endswith(pubkey_suffix) and
1182 privkey.endswith(privkey_suffix) and
1183 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1184
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001185 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001186 # extensions. This doesn't apply to payload keys though, which we will use
1187 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001188 container_cert = matches.group("CONTAINER_CERT")
1189 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001190 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1191 container_key = 'PRESIGNED'
1192 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001193 container_cert, OPTIONS.public_key_suffix,
1194 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001195 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1196 else:
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001197 raise ValueError("Failed to parse container keys: \n{}".format(line))
Tao Baoaa7e9932019-03-15 09:37:01 -07001198
Jooyung Han8caba5e2021-10-27 03:58:09 +09001199 sign_tool = matches.group("SIGN_TOOL")
1200 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001201
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001202 return keys
Tao Baoaa7e9932019-03-15 09:37:01 -07001203
1204
Daniel Norman78554ea2021-09-14 10:29:38 -07001205def BuildVendorPartitions(output_zip_path):
1206 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1207 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1208 logger.warning("Allowed --vendor_partitions: %s",
1209 ",".join(ALLOWED_VENDOR_PARTITIONS))
1210 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1211 OPTIONS.vendor_partitions)
1212
1213 logger.info("Building vendor partitions using vendor otatools.")
1214 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1215 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001216 "SYSTEM/build.prop",
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001217 "RECOVERY/*",
1218 "BOOT/*",
1219 "OTA/",
Daniel Norman78554ea2021-09-14 10:29:38 -07001220 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1221
1222 # Disable various partitions that build based on misc_info fields.
1223 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1224 # vendor otatools. These other partitions will be rebuilt using the main
1225 # otatools if necessary.
1226 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1227 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001228 # Ignore if not rebuilding recovery
1229 if not OPTIONS.rebuild_recovery:
1230 vendor_misc_info["no_boot"] = "true" # boot
1231 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1232 vendor_misc_info["no_recovery"] = "true" # recovery
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001233 vendor_misc_info["avb_enable"] = "false" # vbmeta
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001234
Daniel Norman78554ea2021-09-14 10:29:38 -07001235 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1236 vendor_misc_info["has_dtbo"] = "false" # dtbo
1237 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1238 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001239 vendor_misc_info["avb_building_vbmeta_image"] = "false" # skip building vbmeta
Daniel Norman78554ea2021-09-14 10:29:38 -07001240 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1241 vendor_misc_info["build_super_partition"] = "false" # super split
jiangxu52d8a4cb2022-09-16 14:55:17 +08001242 vendor_misc_info["avb_vbmeta_system"] = "" # skip building vbmeta_system
Daniel Norman78554ea2021-09-14 10:29:38 -07001243 with open(vendor_misc_info_path, "w") as output:
1244 for key in sorted(vendor_misc_info):
1245 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1246
Po Hu0663ae42021-09-27 12:59:06 +08001247 # Disable system partition by a placeholder of IMAGES/system.img,
1248 # instead of removing SYSTEM folder.
1249 # Because SYSTEM/build.prop is still needed for:
1250 # add_img_to_target_files.CreateImage ->
1251 # common.BuildInfo ->
1252 # common.BuildInfo.CalculateFingerprint
1253 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1254 if not os.path.exists(vendor_images_path):
1255 os.makedirs(vendor_images_path)
1256 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1257 pass
1258
Daniel Norman78554ea2021-09-14 10:29:38 -07001259 # Disable care_map.pb as not all ab_partitions are available when
1260 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001261 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1262 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1263 # Disable RADIO images
1264 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1265 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001266
1267 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001268 # Accept either a zip file or extracted directory.
1269 if os.path.isfile(OPTIONS.vendor_otatools):
1270 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1271 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1272 else:
1273 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001274 cmd = [
1275 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1276 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001277 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001278 "--verbose",
1279 vendor_tempdir,
1280 ]
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001281 if OPTIONS.rebuild_recovery:
1282 cmd.insert(4, "--rebuild_recovery")
1283
Daniel Norman78554ea2021-09-14 10:29:38 -07001284 common.RunAndCheckOutput(cmd, verbose=True)
1285
1286 logger.info("Writing vendor partitions to output archive.")
1287 with zipfile.ZipFile(
1288 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1289 allowZip64=True) as output_zip:
1290 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001291 img_file_path = "IMAGES/{}.img".format(p)
1292 map_file_path = "IMAGES/{}.map".format(p)
1293 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
jiangxu5b67b0d52022-06-03 14:46:56 +08001294 if os.path.exists(os.path.join(vendor_tempdir, map_file_path)):
1295 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001296 # copy recovery.img, boot.img, recovery patch & install.sh
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001297 if OPTIONS.rebuild_recovery:
Iavor-Valentin Iftime40adb172022-04-19 18:17:56 +00001298 recovery_img = "IMAGES/recovery.img"
1299 boot_img = "IMAGES/boot.img"
1300 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_img), recovery_img)
1301 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, boot_img), boot_img)
Iavor-Valentin Iftime246a5c02022-03-22 13:51:07 +00001302 recovery_patch_path = "VENDOR/recovery-from-boot.p"
1303 recovery_sh_path = "VENDOR/bin/install-recovery.sh"
1304 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_patch_path), recovery_patch_path)
1305 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, recovery_sh_path), recovery_sh_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001306
1307
Doug Zongkereef39442009-04-02 12:14:19 -07001308def main(argv):
1309
Doug Zongker831840e2011-09-22 10:28:04 -07001310 key_mapping_options = []
1311
Doug Zongkereef39442009-04-02 12:14:19 -07001312 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001313 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001314 names, key = a.split("=")
1315 names = names.split(",")
1316 for n in names:
1317 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001318 elif o == "--extra_apex_payload_key":
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001319 apex_names, key = a.split("=")
Kelvin Zhang87e45272022-07-27 11:14:12 -07001320 for name in apex_names.split(","):
Kelvin Zhang085b6f32022-07-25 16:12:30 -07001321 OPTIONS.extra_apex_payload_keys[name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001322 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001323 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001324 prefix = a.split('/')[0]
1325 if not prefix or prefix != prefix.upper():
1326 raise ValueError("Invalid path prefix '%s'" % (a,))
1327 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001328 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001329 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001330 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001331 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001332 elif o in ("-o", "--replace_ota_keys"):
1333 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001334 elif o in ("-t", "--tag_changes"):
1335 new = []
1336 for i in a.split(","):
1337 i = i.strip()
1338 if not i or i[0] not in "-+":
1339 raise ValueError("Bad tag change '%s'" % (i,))
1340 new.append(i[0] + i[1:].strip())
1341 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001342 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001343 raise ValueError("--replace_verity_public_key is no longer supported,"
1344 " please switch to AVB")
Geremy Condraf19b3652014-07-29 17:54:54 -07001345 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001346 raise ValueError("--replace_verity_private_key is no longer supported,"
1347 " please switch to AVB")
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001348 elif o == "--replace_verity_keyid":
hungweichendd3fca02022-08-19 06:33:25 +00001349 raise ValueError("--replace_verity_keyid is no longer supported, please"
1350 " switch to AVB")
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001351 elif o == "--remove_avb_public_keys":
1352 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001353 elif o == "--avb_vbmeta_key":
1354 OPTIONS.avb_keys['vbmeta'] = a
1355 elif o == "--avb_vbmeta_algorithm":
1356 OPTIONS.avb_algorithms['vbmeta'] = a
1357 elif o == "--avb_vbmeta_extra_args":
1358 OPTIONS.avb_extra_args['vbmeta'] = a
1359 elif o == "--avb_boot_key":
1360 OPTIONS.avb_keys['boot'] = a
1361 elif o == "--avb_boot_algorithm":
1362 OPTIONS.avb_algorithms['boot'] = a
1363 elif o == "--avb_boot_extra_args":
1364 OPTIONS.avb_extra_args['boot'] = a
1365 elif o == "--avb_dtbo_key":
1366 OPTIONS.avb_keys['dtbo'] = a
1367 elif o == "--avb_dtbo_algorithm":
1368 OPTIONS.avb_algorithms['dtbo'] = a
1369 elif o == "--avb_dtbo_extra_args":
1370 OPTIONS.avb_extra_args['dtbo'] = a
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001371 elif o == "--avb_init_boot_key":
1372 OPTIONS.avb_keys['init_boot'] = a
1373 elif o == "--avb_init_boot_algorithm":
1374 OPTIONS.avb_algorithms['init_boot'] = a
1375 elif o == "--avb_init_boot_extra_args":
1376 OPTIONS.avb_extra_args['init_boot'] = a
Ben Fennema6082d0a2021-12-11 14:03:10 -08001377 elif o == "--avb_recovery_key":
1378 OPTIONS.avb_keys['recovery'] = a
1379 elif o == "--avb_recovery_algorithm":
1380 OPTIONS.avb_algorithms['recovery'] = a
1381 elif o == "--avb_recovery_extra_args":
1382 OPTIONS.avb_extra_args['recovery'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001383 elif o == "--avb_system_key":
1384 OPTIONS.avb_keys['system'] = a
1385 elif o == "--avb_system_algorithm":
1386 OPTIONS.avb_algorithms['system'] = a
1387 elif o == "--avb_system_extra_args":
1388 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001389 elif o == "--avb_system_other_key":
1390 OPTIONS.avb_keys['system_other'] = a
1391 elif o == "--avb_system_other_algorithm":
1392 OPTIONS.avb_algorithms['system_other'] = a
1393 elif o == "--avb_system_other_extra_args":
1394 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001395 elif o == "--avb_vendor_key":
1396 OPTIONS.avb_keys['vendor'] = a
1397 elif o == "--avb_vendor_algorithm":
1398 OPTIONS.avb_algorithms['vendor'] = a
1399 elif o == "--avb_vendor_extra_args":
1400 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001401 elif o == "--avb_vbmeta_system_key":
1402 OPTIONS.avb_keys['vbmeta_system'] = a
1403 elif o == "--avb_vbmeta_system_algorithm":
1404 OPTIONS.avb_algorithms['vbmeta_system'] = a
1405 elif o == "--avb_vbmeta_system_extra_args":
1406 OPTIONS.avb_extra_args['vbmeta_system'] = a
1407 elif o == "--avb_vbmeta_vendor_key":
1408 OPTIONS.avb_keys['vbmeta_vendor'] = a
1409 elif o == "--avb_vbmeta_vendor_algorithm":
1410 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1411 elif o == "--avb_vbmeta_vendor_extra_args":
1412 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001413 elif o == "--avb_apex_extra_args":
1414 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001415 elif o == "--avb_extra_custom_image_key":
1416 partition, key = a.split("=")
1417 OPTIONS.avb_keys[partition] = key
1418 elif o == "--avb_extra_custom_image_algorithm":
1419 partition, algorithm = a.split("=")
1420 OPTIONS.avb_algorithms[partition] = algorithm
1421 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001422 # Setting the maxsplit parameter to one, which will return a list with
1423 # two elements. e.g., the second '=' should not be splitted for
1424 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1425 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001426 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001427 elif o == "--gki_signing_key":
1428 OPTIONS.gki_signing_key = a
1429 elif o == "--gki_signing_algorithm":
1430 OPTIONS.gki_signing_algorithm = a
1431 elif o == "--gki_signing_extra_args":
1432 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001433 elif o == "--vendor_otatools":
1434 OPTIONS.vendor_otatools = a
1435 elif o == "--vendor_partitions":
1436 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001437 elif o == "--allow_gsi_debug_sepolicy":
1438 OPTIONS.allow_gsi_debug_sepolicy = True
Kelvin Zhange50bb512022-08-01 15:58:51 -07001439 elif o == "--override_apk_keys":
1440 OPTIONS.override_apk_keys = a
1441 elif o == "--override_apex_keys":
1442 OPTIONS.override_apex_keys = a
Doug Zongkereef39442009-04-02 12:14:19 -07001443 else:
1444 return False
1445 return True
1446
Tao Bao639118f2017-06-19 15:48:02 -07001447 args = common.ParseOptions(
1448 argv, __doc__,
1449 extra_opts="e:d:k:ot:",
1450 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001451 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001452 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001453 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001454 "default_key_mappings=",
1455 "key_mapping=",
1456 "replace_ota_keys",
1457 "tag_changes=",
1458 "replace_verity_public_key=",
1459 "replace_verity_private_key=",
1460 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001461 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001462 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001463 "avb_vbmeta_algorithm=",
1464 "avb_vbmeta_key=",
1465 "avb_vbmeta_extra_args=",
1466 "avb_boot_algorithm=",
1467 "avb_boot_key=",
1468 "avb_boot_extra_args=",
1469 "avb_dtbo_algorithm=",
1470 "avb_dtbo_key=",
1471 "avb_dtbo_extra_args=",
Hongguang Chen0d6b7272022-11-07 13:36:38 -08001472 "avb_init_boot_algorithm=",
1473 "avb_init_boot_key=",
1474 "avb_init_boot_extra_args=",
Ben Fennema6082d0a2021-12-11 14:03:10 -08001475 "avb_recovery_algorithm=",
1476 "avb_recovery_key=",
1477 "avb_recovery_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001478 "avb_system_algorithm=",
1479 "avb_system_key=",
1480 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001481 "avb_system_other_algorithm=",
1482 "avb_system_other_key=",
1483 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001484 "avb_vendor_algorithm=",
1485 "avb_vendor_key=",
1486 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001487 "avb_vbmeta_system_algorithm=",
1488 "avb_vbmeta_system_key=",
1489 "avb_vbmeta_system_extra_args=",
1490 "avb_vbmeta_vendor_algorithm=",
1491 "avb_vbmeta_vendor_key=",
1492 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001493 "avb_extra_custom_image_key=",
1494 "avb_extra_custom_image_algorithm=",
1495 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001496 "gki_signing_key=",
1497 "gki_signing_algorithm=",
1498 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001499 "vendor_partitions=",
1500 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001501 "allow_gsi_debug_sepolicy",
Kelvin Zhange50bb512022-08-01 15:58:51 -07001502 "override_apk_keys=",
1503 "override_apex_keys=",
Tao Bao639118f2017-06-19 15:48:02 -07001504 ],
1505 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001506
1507 if len(args) != 2:
1508 common.Usage(__doc__)
1509 sys.exit(1)
1510
Tao Baobadceb22019-03-15 09:33:43 -07001511 common.InitLogging()
1512
Kelvin Zhang928c2342020-09-22 16:15:57 -04001513 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001514 output_zip = zipfile.ZipFile(args[1], "w",
1515 compression=zipfile.ZIP_DEFLATED,
1516 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001517
Doug Zongker831840e2011-09-22 10:28:04 -07001518 misc_info = common.LoadInfoDict(input_zip)
1519
1520 BuildKeyMap(misc_info, key_mapping_options)
1521
Tao Baoaa7e9932019-03-15 09:37:01 -07001522 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1523 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001524
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001525 apex_keys_info = ReadApexKeysInfo(input_zip)
Tao Baoaa7e9932019-03-15 09:37:01 -07001526 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1527
Tianjie Xu88a759d2020-01-23 10:47:54 -08001528 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1529 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001530 CheckApkAndApexKeysAvailable(
1531 input_zip,
1532 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001533 compressed_extension,
1534 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001535
1536 key_passwords = common.GetKeyPasswords(
1537 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001538 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001539 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001540
Doug Zongker412c02f2014-02-13 10:58:24 -08001541 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001542 apk_keys, apex_keys, key_passwords,
1543 platform_api_level, codename_to_api_level_map,
Melisa Carranza Zúñigada308bf2022-04-12 23:22:11 +00001544 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001545
Kelvin Zhang37a42902022-10-26 12:49:03 -07001546 input_zip.close()
1547 output_zip.close()
Doug Zongkereef39442009-04-02 12:14:19 -07001548
Daniel Norman78554ea2021-09-14 10:29:38 -07001549 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1550 BuildVendorPartitions(args[1])
1551
Tianjie Xub48589a2016-08-03 19:21:52 -07001552 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001553 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001554 # add_img_to_target_files builds the system image from scratch, so the
1555 # recovery patch is guaranteed to be regenerated there.
1556 if OPTIONS.rebuild_recovery:
1557 new_args.append("--rebuild_recovery")
1558 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001559 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001560
Tao Bao0c28d2d2017-12-24 10:37:38 -08001561 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001562
1563
1564if __name__ == '__main__':
1565 try:
1566 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001567 finally:
1568 common.Cleanup()