blob: aaf4a3433761c48318ea7e5d9945d05dab8ba1d8 [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
30 --extra_apex_payload_key <name=key>
31 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
Tao Baod6085d62019-05-06 12:55:42 -0700102 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
103 vbmeta_vendor}_algorithm <algorithm>
104 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
105 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
Tao Baod6085d62019-05-06 12:55:42 -0700109 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
110 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.
Doug Zongkereef39442009-04-02 12:14:19 -0700144"""
145
Tao Bao0c28d2d2017-12-24 10:37:38 -0800146from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700147
Robert Craig817c5742013-04-19 10:59:22 -0400148import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700149import copy
Robert Craig817c5742013-04-19 10:59:22 -0400150import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100151import gzip
Tao Baobb733882019-07-24 23:31:19 -0700152import io
Tao Baoaa7e9932019-03-15 09:37:01 -0700153import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700154import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700155import os
156import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100157import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700158import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700159import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800160import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700161import tempfile
162import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800163from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700164
Doug Zongker3c84f562014-07-31 11:06:30 -0700165import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700166import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700167import common
168
Tao Bao0c28d2d2017-12-24 10:37:38 -0800169
170if sys.hexversion < 0x02070000:
171 print("Python 2.7 or newer is required.", file=sys.stderr)
172 sys.exit(1)
173
174
Tao Baobadceb22019-03-15 09:33:43 -0700175logger = logging.getLogger(__name__)
176
Doug Zongkereef39442009-04-02 12:14:19 -0700177OPTIONS = common.OPTIONS
178
179OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700180OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700181OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700182OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700183OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700184OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700185OPTIONS.replace_verity_public_key = False
186OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700187OPTIONS.replace_verity_keyid = False
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800188OPTIONS.remove_avb_public_keys = None
Doug Zongker831840e2011-09-22 10:28:04 -0700189OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700190OPTIONS.avb_keys = {}
191OPTIONS.avb_algorithms = {}
192OPTIONS.avb_extra_args = {}
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800193OPTIONS.gki_signing_key = None
194OPTIONS.gki_signing_algorithm = None
195OPTIONS.gki_signing_extra_args = None
Tianjie Xu88a759d2020-01-23 10:47:54 -0800196OPTIONS.android_jar_path = None
Daniel Norman78554ea2021-09-14 10:29:38 -0700197OPTIONS.vendor_partitions = set()
198OPTIONS.vendor_otatools = None
Bowgo Tsai2a781692021-10-13 17:39:33 +0800199OPTIONS.allow_gsi_debug_sepolicy = False
Doug Zongkereef39442009-04-02 12:14:19 -0700200
Tao Bao0c28d2d2017-12-24 10:37:38 -0800201
Tao Bao19b02fe2019-10-09 00:04:28 -0700202AVB_FOOTER_ARGS_BY_PARTITION = {
Tianjiebf0b8a82021-03-03 17:31:04 -0800203 'boot': 'avb_boot_add_hash_footer_args',
Devin Mooreafdd7c72021-12-13 22:04:08 +0000204 'init_boot': 'avb_init_boot_add_hash_footer_args',
Tianjiebf0b8a82021-03-03 17:31:04 -0800205 'dtbo': 'avb_dtbo_add_hash_footer_args',
206 'product': 'avb_product_add_hashtree_footer_args',
207 'recovery': 'avb_recovery_add_hash_footer_args',
208 'system': 'avb_system_add_hashtree_footer_args',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000209 'system_dlkm': "avb_system_dlkm_add_hashtree_footer_args",
Tianjiebf0b8a82021-03-03 17:31:04 -0800210 'system_ext': 'avb_system_ext_add_hashtree_footer_args',
211 'system_other': 'avb_system_other_add_hashtree_footer_args',
212 'odm': 'avb_odm_add_hashtree_footer_args',
213 'odm_dlkm': 'avb_odm_dlkm_add_hashtree_footer_args',
214 'pvmfw': 'avb_pvmfw_add_hash_footer_args',
215 'vendor': 'avb_vendor_add_hashtree_footer_args',
216 'vendor_boot': 'avb_vendor_boot_add_hash_footer_args',
217 'vendor_dlkm': "avb_vendor_dlkm_add_hashtree_footer_args",
218 'vbmeta': 'avb_vbmeta_args',
219 'vbmeta_system': 'avb_vbmeta_system_args',
220 'vbmeta_vendor': 'avb_vbmeta_vendor_args',
Tao Bao19b02fe2019-10-09 00:04:28 -0700221}
222
223
Tianjiebf0b8a82021-03-03 17:31:04 -0800224# Check that AVB_FOOTER_ARGS_BY_PARTITION is in sync with AVB_PARTITIONS.
225for partition in common.AVB_PARTITIONS:
226 if partition not in AVB_FOOTER_ARGS_BY_PARTITION:
227 raise RuntimeError("Missing {} in AVB_FOOTER_ARGS".format(partition))
228
Daniel Norman78554ea2021-09-14 10:29:38 -0700229# Partitions that can be regenerated after signing using a separate
230# vendor otatools package.
231ALLOWED_VENDOR_PARTITIONS = set(["vendor", "odm"])
232
Tianjiebf0b8a82021-03-03 17:31:04 -0800233
Tianjie4d48d502021-06-11 17:03:43 -0700234def IsApexFile(filename):
235 return filename.endswith(".apex") or filename.endswith(".capex")
236
237
238def GetApexFilename(filename):
239 name = os.path.basename(filename)
240 # Replace the suffix for compressed apex
241 if name.endswith(".capex"):
242 return name.replace(".capex", ".apex")
243 return name
244
245
Narayan Kamatha07bf042017-08-14 14:49:21 +0100246def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800247 # apply the key remapping to the contents of the file
Tao Baoa3705452019-06-24 15:33:41 -0700248 for apk, cert in certmap.items():
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800249 certmap[apk] = OPTIONS.key_map.get(cert, cert)
250
251 # apply all the -e options, overriding anything in the file
Tao Baoa3705452019-06-24 15:33:41 -0700252 for apk, cert in OPTIONS.extra_apks.items():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800253 if not cert:
254 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700255 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800256
Doug Zongkereef39442009-04-02 12:14:19 -0700257 return certmap
258
259
Tao Baoaa7e9932019-03-15 09:37:01 -0700260def GetApexKeys(keys_info, key_map):
261 """Gets APEX payload and container signing keys by applying the mapping rules.
262
Tao Baoe1343992019-03-19 12:24:03 -0700263 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700264
265 Args:
266 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
Jooyung Han8caba5e2021-10-27 03:58:09 +0900267 container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -0700268 key_map: A dict that overrides the keys, specified via command-line input.
269
270 Returns:
271 A dict that contains the updated APEX key mapping, which should be used for
272 the current signing.
Tao Baof98fa102019-04-24 14:51:25 -0700273
274 Raises:
275 AssertionError: On invalid container / payload key overrides.
Tao Baoaa7e9932019-03-15 09:37:01 -0700276 """
277 # Apply all the --extra_apex_payload_key options to override the payload
278 # signing keys in the given keys_info.
279 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700280 if not key:
281 key = 'PRESIGNED'
Tao Bao34223092019-07-11 11:52:52 -0700282 if apex not in keys_info:
283 logger.warning('Failed to find %s in target_files; Ignored', apex)
284 continue
Jooyung Han8caba5e2021-10-27 03:58:09 +0900285 keys_info[apex] = (key, keys_info[apex][1], keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700286
287 # Apply the key remapping to container keys.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900288 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
289 keys_info[apex] = (payload_key, key_map.get(container_key, container_key), sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -0700290
291 # Apply all the --extra_apks options to override the container keys.
292 for apex, key in OPTIONS.extra_apks.items():
293 # Skip non-APEX containers.
294 if apex not in keys_info:
295 continue
Tao Baoe1343992019-03-19 12:24:03 -0700296 if not key:
297 key = 'PRESIGNED'
Jooyung Han8caba5e2021-10-27 03:58:09 +0900298 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key), keys_info[apex][2])
Tao Baoaa7e9932019-03-15 09:37:01 -0700299
Tao Baof98fa102019-04-24 14:51:25 -0700300 # A PRESIGNED container entails a PRESIGNED payload. Apply this to all the
301 # APEX key pairs. However, a PRESIGNED container with non-PRESIGNED payload
302 # (overridden via commandline) indicates a config error, which should not be
303 # allowed.
Jooyung Han8caba5e2021-10-27 03:58:09 +0900304 for apex, (payload_key, container_key, sign_tool) in keys_info.items():
Tao Baof98fa102019-04-24 14:51:25 -0700305 if container_key != 'PRESIGNED':
306 continue
307 if apex in OPTIONS.extra_apex_payload_keys:
308 payload_override = OPTIONS.extra_apex_payload_keys[apex]
309 assert payload_override == '', \
310 ("Invalid APEX key overrides: {} has PRESIGNED container but "
311 "non-PRESIGNED payload key {}").format(apex, payload_override)
312 if payload_key != 'PRESIGNED':
313 print(
314 "Setting {} payload as PRESIGNED due to PRESIGNED container".format(
315 apex))
Jooyung Han8caba5e2021-10-27 03:58:09 +0900316 keys_info[apex] = ('PRESIGNED', 'PRESIGNED', None)
Tao Baof98fa102019-04-24 14:51:25 -0700317
Tao Baoaa7e9932019-03-15 09:37:01 -0700318 return keys_info
319
320
Tao Bao93c2a012018-06-19 12:19:35 -0700321def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700322 """Returns the APK info based on the given filename.
323
324 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700325 compressed extension into consideration. If it appears to be an APK file,
326 further checks if the APK file should be skipped when signing, based on the
327 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700328
329 Args:
330 filename: Path to the file.
331 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
332 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700333 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700334
335 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700336 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
337 given filename is an APK file. is_compressed indicates whether the APK file
338 is compressed (only meaningful when is_apk is True). should_be_skipped
339 indicates whether the filename matches any of the given prefixes to be
340 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700341
342 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700343 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700344 """
345 assert compressed_extension is None or compressed_extension.startswith('.'), \
346 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
347
Tao Bao93c2a012018-06-19 12:19:35 -0700348 # skipped_prefixes should be one of set/list/tuple types. Other types such as
349 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700350 assert isinstance(skipped_prefixes, (set, list, tuple)), \
351 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700352
Tao Bao11f955c2018-06-19 12:19:35 -0700353 compressed_apk_extension = (
354 ".apk" + compressed_extension if compressed_extension else None)
355 is_apk = (filename.endswith(".apk") or
356 (compressed_apk_extension and
357 filename.endswith(compressed_apk_extension)))
358 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700359 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700360
361 is_compressed = (compressed_apk_extension and
362 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700363 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
364 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700365
366
Tao Baoaa7e9932019-03-15 09:37:01 -0700367def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700368 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700369 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700370
371 Args:
372 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700373 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700374 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700375 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700376 apex_keys: A dict that contains the key mapping from APEX name to
Jooyung Han8caba5e2021-10-27 03:58:09 +0900377 (payload_key, container_key, sign_tool).
Tao Bao11f955c2018-06-19 12:19:35 -0700378
379 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700380 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700381 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700382 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700383 for info in input_tf_zip.infolist():
Tianjie5bd03952021-02-18 23:02:36 -0800384 # Handle APEXes on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700385 if IsApexFile(info.filename):
386 name = GetApexFilename(info.filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700387 if name not in known_keys:
388 unknown_files.append(name)
389 continue
390
391 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700392 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
393 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
394 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700395 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700396
Tao Bao11f955c2018-06-19 12:19:35 -0700397 name = os.path.basename(info.filename)
398 if is_compressed:
399 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700400 if name not in known_keys:
401 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700402
Tao Baoaa7e9932019-03-15 09:37:01 -0700403 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700404 ("No key specified for:\n {}\n"
405 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700406 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700407
Tao Baoe1343992019-03-19 12:24:03 -0700408 # For all the APEXes, double check that we won't have an APEX that has only
Tao Baof98fa102019-04-24 14:51:25 -0700409 # one of the payload / container keys set. Note that non-PRESIGNED container
410 # with PRESIGNED payload could be allowed but currently unsupported. It would
411 # require changing SignApex implementation.
Tao Baoe1343992019-03-19 12:24:03 -0700412 if not apex_keys:
413 return
414
415 invalid_apexes = []
416 for info in input_tf_zip.infolist():
Tianjie4d48d502021-06-11 17:03:43 -0700417 if not IsApexFile(info.filename):
Tao Baoe1343992019-03-19 12:24:03 -0700418 continue
419
Tianjie4d48d502021-06-11 17:03:43 -0700420 name = GetApexFilename(info.filename)
421
Jooyung Han8caba5e2021-10-27 03:58:09 +0900422 (payload_key, container_key, _) = apex_keys[name]
Tao Baoe1343992019-03-19 12:24:03 -0700423 if ((payload_key in common.SPECIAL_CERT_STRINGS and
424 container_key not in common.SPECIAL_CERT_STRINGS) or
425 (payload_key not in common.SPECIAL_CERT_STRINGS and
426 container_key in common.SPECIAL_CERT_STRINGS)):
427 invalid_apexes.append(
428 "{}: payload_key {}, container_key {}".format(
429 name, payload_key, container_key))
430
431 assert not invalid_apexes, \
432 "Invalid APEX keys specified:\n {}\n".format(
433 "\n ".join(invalid_apexes))
434
Doug Zongkereb338ef2009-05-20 16:50:49 -0700435
Narayan Kamatha07bf042017-08-14 14:49:21 +0100436def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700437 is_compressed, apk_name):
438 unsigned = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700439 unsigned.write(data)
440 unsigned.flush()
441
Narayan Kamatha07bf042017-08-14 14:49:21 +0100442 if is_compressed:
443 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800444 with gzip.open(unsigned.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400445 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100446 shutil.copyfileobj(in_file, out_file)
447
448 # Finally, close the "unsigned" file (which is gzip compressed), and then
449 # replace it with the uncompressed version.
450 #
451 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
452 # we could just gzip / gunzip in-memory buffers instead.
453 unsigned.close()
454 unsigned = uncompressed
455
Oleg Aravin8046cb02020-06-02 16:02:38 -0700456 signed = tempfile.NamedTemporaryFile(suffix='_' + apk_name)
Doug Zongkereef39442009-04-02 12:14:19 -0700457
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800458 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
459 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
460 # didn't change, we don't want its signature to change due to the switch
461 # from SHA-1 to SHA-256.
462 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
463 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
464 # that the APK's minSdkVersion is 1.
465 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
466 # determine whether to use SHA-256.
467 min_api_level = None
468 if platform_api_level > 23:
469 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
470 # minSdkVersion attribute
471 min_api_level = None
472 else:
473 # Force APK signer to use SHA-1
474 min_api_level = 1
475
476 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800477 min_api_level=min_api_level,
478 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700479
Tao Bao0c28d2d2017-12-24 10:37:38 -0800480 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100481 if is_compressed:
482 # Recompress the file after it has been signed.
483 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800484 with open(signed.name, "rb") as in_file, \
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400485 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100486 shutil.copyfileobj(in_file, out_file)
487
488 data = compressed.read()
489 compressed.close()
490 else:
491 data = signed.read()
492
Doug Zongkereef39442009-04-02 12:14:19 -0700493 unsigned.close()
494 signed.close()
495
496 return data
497
Tianjie5bd03952021-02-18 23:02:36 -0800498
Kelvin Zhang119f2792021-02-10 12:45:24 -0500499def IsBuildPropFile(filename):
500 return filename in (
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400501 "SYSTEM/etc/prop.default",
502 "BOOT/RAMDISK/prop.default",
503 "RECOVERY/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500504
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400505 "VENDOR_BOOT/RAMDISK/default.prop",
506 "VENDOR_BOOT/RAMDISK/prop.default",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500507
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400508 # ROOT/default.prop is a legacy path, but may still exist for upgrading
509 # devices that don't support `property_overrides_split_enabled`.
510 "ROOT/default.prop",
Kelvin Zhang119f2792021-02-10 12:45:24 -0500511
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400512 # RECOVERY/RAMDISK/default.prop is a legacy path, but will always exist
513 # as a symlink in the current code. So it's a no-op here. Keeping the
514 # path here for clarity.
515 "RECOVERY/RAMDISK/default.prop") or filename.endswith("build.prop")
Doug Zongkereef39442009-04-02 12:14:19 -0700516
Tianjie5bd03952021-02-18 23:02:36 -0800517
Doug Zongker412c02f2014-02-13 10:58:24 -0800518def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700519 apk_keys, apex_keys, key_passwords,
520 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100521 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700522 # maxsize measures the maximum filename length, including the ones to be
523 # skipped.
Bowgo Tsai8d4b7242022-01-04 15:15:35 +0800524 try:
525 maxsize = max(
526 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
527 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
528 except ValueError:
529 # Sets this to zero for targets without APK files, e.g., gki_arm64.
530 maxsize = 0
531
Tao Baoa80ed222016-06-16 14:41:24 -0700532 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800533
Doug Zongkereef39442009-04-02 12:14:19 -0700534 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700535 filename = info.filename
536 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700537 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700538
Tao Bao04808502019-07-25 23:11:41 -0700539 # Skip OTA-specific images (e.g. split super images), which will be
540 # re-generated during signing.
Tao Bao33bf2682019-01-11 12:37:35 -0800541 if filename.startswith("OTA/") and filename.endswith(".img"):
542 continue
543
Tao Bao11f955c2018-06-19 12:19:35 -0700544 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700545 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700546 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
547 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
548
549 if is_apk and should_be_skipped:
550 # Copy skipped APKs verbatim.
551 print(
552 "NOT signing: %s\n"
553 " (skipped due to matching prefix)" % (filename,))
554 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800555
Tao Baof2cffbd2015-07-22 12:33:18 -0700556 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700557 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700558 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100559 if is_compressed:
560 name = name[:-len(compressed_extension)]
561
Tao Baoaa7e9932019-03-15 09:37:01 -0700562 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800563 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800564 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800565 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Oleg Aravin8046cb02020-06-02 16:02:38 -0700566 codename_to_api_level_map, is_compressed, name)
Tao Bao2ed665a2015-04-01 11:21:55 -0700567 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700568 else:
569 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700570 print(
571 "NOT signing: %s\n"
572 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700573 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700574
Tianjie5bd03952021-02-18 23:02:36 -0800575 # Sign bundled APEX files on all partitions
Tianjie4d48d502021-06-11 17:03:43 -0700576 elif IsApexFile(filename):
577 name = GetApexFilename(filename)
578
Jooyung Han8caba5e2021-10-27 03:58:09 +0900579 payload_key, container_key, sign_tool = apex_keys[name]
Tao Baoaa7e9932019-03-15 09:37:01 -0700580
Tao Baoe1343992019-03-19 12:24:03 -0700581 # We've asserted not having a case with only one of them PRESIGNED.
582 if (payload_key not in common.SPECIAL_CERT_STRINGS and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400583 container_key not in common.SPECIAL_CERT_STRINGS):
Tao Baoe1343992019-03-19 12:24:03 -0700584 print(" signing: %-*s container (%s)" % (
585 maxsize, name, container_key))
586 print(" : %-*s payload (%s)" % (
587 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700588
Tao Baoe7354ba2019-05-09 16:54:15 -0700589 signed_apex = apex_utils.SignApex(
Tao Bao1ac886e2019-06-26 11:58:22 -0700590 misc_info['avb_avbtool'],
Tao Baoe1343992019-03-19 12:24:03 -0700591 data,
592 payload_key,
593 container_key,
Oleh Cherpake555ab12020-10-05 17:04:59 +0300594 key_passwords,
Tianjie Xu88a759d2020-01-23 10:47:54 -0800595 apk_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700596 codename_to_api_level_map,
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400597 no_hashtree=None, # Let apex_util determine if hash tree is needed
Jooyung Han8caba5e2021-10-27 03:58:09 +0900598 signing_args=OPTIONS.avb_extra_args.get('apex'),
599 sign_tool=sign_tool)
Tao Baoe1343992019-03-19 12:24:03 -0700600 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700601
Tao Baoe1343992019-03-19 12:24:03 -0700602 else:
603 print(
604 "NOT signing: %s\n"
605 " (skipped due to special cert string)" % (name,))
606 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700607
Tao Baoa80ed222016-06-16 14:41:24 -0700608 # System properties.
Kelvin Zhang119f2792021-02-10 12:45:24 -0500609 elif IsBuildPropFile(filename):
Tao Bao11f955c2018-06-19 12:19:35 -0700610 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800611 if stat.S_ISLNK(info.external_attr >> 16):
612 new_data = data
613 else:
Tao Baoa3705452019-06-24 15:33:41 -0700614 new_data = RewriteProps(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700615 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700616
Tao Bao66472632017-12-04 17:16:36 -0800617 # Replace the certs in *mac_permissions.xml (there could be multiple, such
Inseob Kime7b222a2021-12-21 15:57:03 +0900618 # as {system,vendor}/etc/selinux/{plat,vendor}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700619 elif filename.endswith("mac_permissions.xml"):
620 print("Rewriting %s with new keys." % (filename,))
Tao Baoa3705452019-06-24 15:33:41 -0700621 new_data = ReplaceCerts(data.decode())
Tao Bao2ed665a2015-04-01 11:21:55 -0700622 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700623
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700624 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700625 elif filename in ("SYSTEM/recovery-from-boot.p",
Robin Leeda427de2020-01-03 19:16:32 +0100626 "VENDOR/recovery-from-boot.p",
627
Tao Bao11f955c2018-06-19 12:19:35 -0700628 "SYSTEM/etc/recovery.img",
Robin Leeda427de2020-01-03 19:16:32 +0100629 "VENDOR/etc/recovery.img",
630
631 "SYSTEM/bin/install-recovery.sh",
632 "VENDOR/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700633 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700634
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700635 # Don't copy OTA certs if we're replacing them.
Tianjie Xu2df23d72019-10-15 18:06:25 -0700636 # Replacement of update-payload-key.pub.pem was removed in b/116660991.
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500637 elif OPTIONS.replace_ota_keys and filename.endswith("/otacerts.zip"):
Doug Zongker412c02f2014-02-13 10:58:24 -0800638 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700639
Tao Bao46a59992017-06-05 11:55:16 -0700640 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700641 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700642 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700643
644 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700645 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700646 filename in ("BOOT/RAMDISK/verity_key",
647 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700648 pass
Bowgo Tsai2fe786a2020-02-21 17:48:18 +0800649 elif (OPTIONS.remove_avb_public_keys and
650 (filename.startswith("BOOT/RAMDISK/avb/") or
651 filename.startswith("BOOT/RAMDISK/first_stage_ramdisk/avb/"))):
Kelvin Zhang0876c412020-06-23 15:06:58 -0400652 matched_removal = False
653 for key_to_remove in OPTIONS.remove_avb_public_keys:
654 if filename.endswith(key_to_remove):
655 matched_removal = True
656 print("Removing AVB public key from ramdisk: %s" % filename)
657 break
658 if not matched_removal:
659 # Copy it verbatim if we don't want to remove it.
660 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700661
Tao Bao8adcfd12016-06-17 17:01:22 -0700662 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700663 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700664 pass
665
Tianjiebbde59f2021-05-03 21:18:56 -0700666 # Skip the vbmeta digest as we will recalculate it.
667 elif filename == "META/vbmeta_digest.txt":
668 pass
669
Tianjie Xu4f099002016-08-11 18:04:27 -0700670 # Skip the care_map as we will regenerate the system/vendor images.
Kelvin Zhang0876c412020-06-23 15:06:58 -0400671 elif filename in ["META/care_map.pb", "META/care_map.txt"]:
Tianjie Xu4f099002016-08-11 18:04:27 -0700672 pass
673
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500674 # Skip apex_info.pb because we sign/modify apexes
675 elif filename == "META/apex_info.pb":
676 pass
677
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800678 # Updates system_other.avbpubkey in /product/etc/.
679 elif filename in (
680 "PRODUCT/etc/security/avb/system_other.avbpubkey",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800681 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800682 # Only update system_other's public key, if the corresponding signing
683 # key is specified via --avb_system_other_key.
684 signing_key = OPTIONS.avb_keys.get("system_other")
685 if signing_key:
Tao Bao1ac886e2019-06-26 11:58:22 -0700686 public_key = common.ExtractAvbPublicKey(
687 misc_info['avb_avbtool'], signing_key)
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800688 print(" Rewriting AVB public key of system_other in /product")
689 common.ZipWrite(output_tf_zip, public_key, filename)
690
Andrew Scullbbc930b2022-02-17 22:34:27 +0000691 # Updates pvmfw embedded public key with the virt APEX payload key.
692 elif filename == "PREBUILT_IMAGES/pvmfw.img":
693 # Find the name of the virt APEX in the target files.
694 namelist = input_tf_zip.namelist()
695 apex_gen = (GetApexFilename(f) for f in namelist if IsApexFile(f))
696 virt_apex_re = re.compile("^com\.([^\.]+\.)?android\.virt\.apex$")
697 virt_apex = next((a for a in apex_gen if virt_apex_re.match(a)), None)
698 if not virt_apex:
699 print("Removing %s from ramdisk: virt APEX not found" % filename)
700 else:
701 print("Replacing %s embedded key with %s key" % (filename, virt_apex))
702 # Get the current and new embedded keys.
703 payload_key, container_key, sign_tool = apex_keys[virt_apex]
704 new_pubkey_path = common.ExtractAvbPublicKey(
705 misc_info['avb_avbtool'], payload_key)
706 with open(new_pubkey_path, 'rb') as f:
707 new_pubkey = f.read()
708 pubkey_info = copy.copy(
709 input_tf_zip.getinfo("PREBUILT_IMAGES/pvmfw_embedded.avbpubkey"))
710 old_pubkey = input_tf_zip.read(pubkey_info.filename)
711 # Validate the keys and image.
712 if len(old_pubkey) != len(new_pubkey):
713 raise common.ExternalError("pvmfw embedded public key size mismatch")
714 pos = data.find(old_pubkey)
715 if pos == -1:
716 raise common.ExternalError("pvmfw embedded public key not found")
717 # Replace the key and copy new files.
718 new_data = data[:pos] + new_pubkey + data[pos+len(old_pubkey):]
719 common.ZipWriteStr(output_tf_zip, out_info, new_data)
720 common.ZipWriteStr(output_tf_zip, pubkey_info, new_pubkey)
721 elif filename == "PREBUILT_IMAGES/pvmfw_embedded.avbpubkey":
722 pass
723
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800724 # Should NOT sign boot-debug.img.
725 elif filename in (
726 "BOOT/RAMDISK/force_debuggable",
Bowgo Tsai2a781692021-10-13 17:39:33 +0800727 "BOOT/RAMDISK/first_stage_ramdisk/force_debuggable"):
Bowgo Tsai78369eb2019-04-23 12:28:44 +0800728 raise common.ExternalError("debuggable boot.img cannot be signed")
729
Bowgo Tsai2a781692021-10-13 17:39:33 +0800730 # Should NOT sign userdebug sepolicy file.
731 elif filename in (
732 "SYSTEM_EXT/etc/selinux/userdebug_plat_sepolicy.cil",
733 "SYSTEM/system_ext/etc/selinux/userdebug_plat_sepolicy.cil"):
734 if not OPTIONS.allow_gsi_debug_sepolicy:
735 raise common.ExternalError("debug sepolicy shouldn't be included")
736 else:
737 # Copy it verbatim if we allow the file to exist.
738 common.ZipWriteStr(output_tf_zip, out_info, data)
739
Tao Baoa80ed222016-06-16 14:41:24 -0700740 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700741 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700742 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700743
Doug Zongker412c02f2014-02-13 10:58:24 -0800744 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700745 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800746
Tao Bao46a59992017-06-05 11:55:16 -0700747 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700748 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700749 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700750
751 if OPTIONS.replace_verity_public_key:
Tao Baoc9981932019-09-16 12:10:43 -0700752 # Replace the one in root dir in system.img.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700753 ReplaceVerityPublicKey(
Tao Baoc9981932019-09-16 12:10:43 -0700754 output_tf_zip, 'ROOT/verity_key', OPTIONS.replace_verity_public_key[1])
755
756 if not system_root_image:
757 # Additionally replace the copy in ramdisk if not using system-as-root.
758 ReplaceVerityPublicKey(
759 output_tf_zip,
760 'BOOT/RAMDISK/verity_key',
761 OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700762
763 # Replace the keyid string in BOOT/cmdline.
764 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700765 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
766 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800767
Tao Bao639118f2017-06-19 15:48:02 -0700768 # Replace the AVB signing keys, if any.
769 ReplaceAvbSigningKeys(misc_info)
770
Tao Bao19b02fe2019-10-09 00:04:28 -0700771 # Rewrite the props in AVB signing args.
772 if misc_info.get('avb_enable') == 'true':
773 RewriteAvbProps(misc_info)
774
Bowgo Tsai27c39b02021-03-12 21:40:32 +0800775 # Replace the GKI signing key for boot.img, if any.
776 ReplaceGkiSigningKey(misc_info)
777
Tao Bao46a59992017-06-05 11:55:16 -0700778 # Write back misc_info with the latest values.
779 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
780
Doug Zongker8e931bf2009-04-06 15:21:45 -0700781
Robert Craig817c5742013-04-19 10:59:22 -0400782def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800783 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400784
Tao Bao66472632017-12-04 17:16:36 -0800785 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
786 be skipped. After the replacement, it additionally checks for duplicate
787 entries, which would otherwise fail the policy loading code in
788 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
789
790 Args:
791 data: Input string that contains a set of X.509 certs.
792
793 Returns:
794 A string after the replacement.
795
796 Raises:
797 AssertionError: On finding duplicate entries.
798 """
Tao Baoa3705452019-06-24 15:33:41 -0700799 for old, new in OPTIONS.key_map.items():
Tao Bao66472632017-12-04 17:16:36 -0800800 if OPTIONS.verbose:
801 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
802
803 try:
804 with open(old + ".x509.pem") as old_fp:
805 old_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700806 common.ParseCertificate(old_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800807 with open(new + ".x509.pem") as new_fp:
808 new_cert16 = base64.b16encode(
Tao Baoa3705452019-06-24 15:33:41 -0700809 common.ParseCertificate(new_fp.read())).decode().lower()
Tao Bao66472632017-12-04 17:16:36 -0800810 except IOError as e:
811 if OPTIONS.verbose or e.errno != errno.ENOENT:
812 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
813 "%s.x509.pem." % (e.filename, e.strerror, old, new))
814 continue
815
816 # Only match entire certs.
817 pattern = "\\b" + old_cert16 + "\\b"
818 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
819
820 if OPTIONS.verbose:
821 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
822 num, old, new))
823
824 # Verify that there're no duplicate entries after the replacement. Note that
825 # it's only checking entries with global seinfo at the moment (i.e. ignoring
826 # the ones with inner packages). (Bug: 69479366)
827 root = ElementTree.fromstring(data)
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400828 signatures = [signer.attrib['signature']
829 for signer in root.findall('signer')]
Tao Bao66472632017-12-04 17:16:36 -0800830 assert len(signatures) == len(set(signatures)), \
831 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400832
833 return data
834
835
Doug Zongkerc09abc82010-01-11 13:09:15 -0800836def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800837 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
838
839 Args:
840 tags: The input string that contains comma-separated tags.
841
842 Returns:
843 The updated tags (comma-separated and sorted).
844 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800845 tags = set(tags.split(","))
846 for ch in OPTIONS.tag_changes:
847 if ch[0] == "-":
848 tags.discard(ch[1:])
849 elif ch[0] == "+":
850 tags.add(ch[1:])
851 return ",".join(sorted(tags))
852
853
Tao Baoa7054ee2017-12-08 14:42:16 -0800854def RewriteProps(data):
855 """Rewrites the system properties in the given string.
856
857 Each property is expected in 'key=value' format. The properties that contain
858 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
859 EditTags().
860
861 Args:
862 data: Input string, separated by newlines.
863
864 Returns:
865 The string with modified properties.
866 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700867 output = []
868 for line in data.split("\n"):
869 line = line.strip()
870 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700871 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700872 key, value = line.split("=", 1)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200873 if (key.startswith("ro.") and
Kelvin Zhang7cab7502021-08-02 19:58:14 -0400874 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800875 pieces = value.split("/")
876 pieces[-1] = EditTags(pieces[-1])
877 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700878 elif key == "ro.bootimage.build.fingerprint":
879 pieces = value.split("/")
880 pieces[-1] = EditTags(pieces[-1])
881 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700882 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800883 pieces = value.split(" ")
Stefen Wakefield4260fc12021-03-23 04:58:22 -0500884 assert pieces[-1].endswith("-keys")
Doug Zongkerc09abc82010-01-11 13:09:15 -0800885 pieces[-1] = EditTags(pieces[-1])
886 value = " ".join(pieces)
Magnus Strandh234f4b42019-05-01 23:09:30 +0200887 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800888 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700889 elif key == "ro.build.display.id":
890 # change, eg, "JWR66N dev-keys" to "JWR66N"
891 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700892 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800893 value.pop()
894 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800895 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700896 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800897 print(" replace: ", original_line)
898 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700899 output.append(line)
900 return "\n".join(output) + "\n"
901
902
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700903def WriteOtacerts(output_zip, filename, keys):
904 """Constructs a zipfile from given keys; and writes it to output_zip.
905
906 Args:
907 output_zip: The output target_files zip.
908 filename: The archive name in the output zip.
909 keys: A list of public keys to use during OTA package verification.
910 """
Tao Baobb733882019-07-24 23:31:19 -0700911 temp_file = io.BytesIO()
Kelvin Zhang928c2342020-09-22 16:15:57 -0400912 certs_zip = zipfile.ZipFile(temp_file, "w", allowZip64=True)
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700913 for k in keys:
914 common.ZipWrite(certs_zip, k)
915 common.ZipClose(certs_zip)
916 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
917
918
Doug Zongker831840e2011-09-22 10:28:04 -0700919def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700920 try:
921 keylist = input_tf_zip.read("META/otakeys.txt").split()
922 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700923 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700924
Jacky Liubeb0b692021-12-29 16:29:05 +0800925 extra_ota_keys_info = misc_info.get("extra_ota_keys")
926 if extra_ota_keys_info:
927 extra_ota_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
928 for k in extra_ota_keys_info.split()]
929 print("extra ota key(s): " + ", ".join(extra_ota_keys))
930 else:
931 extra_ota_keys = []
932 for k in extra_ota_keys:
933 if not os.path.isfile(k):
934 raise common.ExternalError(k + " does not exist or is not a file")
935
936 extra_recovery_keys_info = misc_info.get("extra_recovery_keys")
937 if extra_recovery_keys_info:
Doug Zongkere121d6a2011-02-01 14:13:52 -0800938 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
Jacky Liubeb0b692021-12-29 16:29:05 +0800939 for k in extra_recovery_keys_info.split()]
940 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800941 else:
942 extra_recovery_keys = []
Jacky Liubeb0b692021-12-29 16:29:05 +0800943 for k in extra_recovery_keys:
944 if not os.path.isfile(k):
945 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800946
Doug Zongker8e931bf2009-04-06 15:21:45 -0700947 mapped_keys = []
948 for k in keylist:
949 m = re.match(r"^(.*)\.x509\.pem$", k)
950 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800951 raise common.ExternalError(
952 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700953 k = m.group(1)
954 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
955
Doug Zongkere05628c2009-08-20 17:38:42 -0700956 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800957 print("using:\n ", "\n ".join(mapped_keys))
958 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700959 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700960 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -0700961 "build/make/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800962 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
963 if mapped_devkey != devkey:
964 misc_info["default_system_dev_certificate"] = mapped_devkey
965 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700966 print("META/otakeys.txt has no keys; using %s for OTA package"
967 " verification." % (mapped_keys[0],))
Jacky Liubeb0b692021-12-29 16:29:05 +0800968 for k in mapped_keys:
969 if not os.path.isfile(k):
970 raise common.ExternalError(k + " does not exist or is not a file")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700971
Kelvin Zhang9f781ff2021-02-11 19:10:44 -0500972 otacerts = [info
973 for info in input_tf_zip.infolist()
974 if info.filename.endswith("/otacerts.zip")]
975 for info in otacerts:
Jacky Liubeb0b692021-12-29 16:29:05 +0800976 if info.filename.startswith(("BOOT/", "RECOVERY/", "VENDOR_BOOT/")):
977 extra_keys = extra_recovery_keys
978 else:
979 extra_keys = extra_ota_keys
980 print("Rewriting OTA key:", info.filename, mapped_keys + extra_keys)
981 WriteOtacerts(output_tf_zip, info.filename, mapped_keys + extra_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700982
Tao Baoa80ed222016-06-16 14:41:24 -0700983
Tao Bao0c28d2d2017-12-24 10:37:38 -0800984def ReplaceVerityPublicKey(output_zip, filename, key_path):
985 """Replaces the verity public key at the given path in the given zip.
986
987 Args:
988 output_zip: The output target_files zip.
989 filename: The archive name in the output zip.
990 key_path: The path to the public key.
991 """
992 print("Replacing verity public key with %s" % (key_path,))
993 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700994
Tao Bao8adcfd12016-06-17 17:01:22 -0700995
Tao Bao46a59992017-06-05 11:55:16 -0700996def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800997 """Replaces the verity private key in misc_info dict.
998
999 Args:
1000 misc_info: The info dict.
1001 key_path: The path to the private key in PKCS#8 format.
1002 """
1003 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -07001004 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -07001005
Tao Bao8adcfd12016-06-17 17:01:22 -07001006
Tao Baoe838d142017-12-23 23:44:48 -08001007def ReplaceVerityKeyId(input_zip, output_zip, key_path):
1008 """Replaces the veritykeyid parameter in BOOT/cmdline.
1009
1010 Args:
1011 input_zip: The input target_files zip, which should be already open.
1012 output_zip: The output target_files zip, which should be already open and
1013 writable.
1014 key_path: The path to the PEM encoded X.509 certificate.
1015 """
Tao Baoa3705452019-06-24 15:33:41 -07001016 in_cmdline = input_zip.read("BOOT/cmdline").decode()
Tao Baoe838d142017-12-23 23:44:48 -08001017 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001018 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -08001019 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
1020 return
1021
Tao Bao0c28d2d2017-12-24 10:37:38 -08001022 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001023 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -08001024 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001025 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -08001026 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001027
Tao Baoe838d142017-12-23 23:44:48 -08001028 # Extract keyid using openssl command.
1029 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -08001030 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -08001031 keyid, stderr = p.communicate()
1032 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
1033 keyid = re.search(
1034 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
1035 print("Replacing verity keyid with {}".format(keyid))
1036 out_buffer.append("veritykeyid=id:%s" % (keyid,))
1037
1038 out_cmdline = ' '.join(out_buffer).strip() + '\n'
1039 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -07001040
1041
1042def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
1043 """Replaces META/misc_info.txt.
1044
1045 Only writes back the ones in the original META/misc_info.txt. Because the
1046 current in-memory dict contains additional items computed at runtime.
1047 """
1048 misc_info_old = common.LoadDictionaryFromLines(
Tao Baoa3705452019-06-24 15:33:41 -07001049 input_zip.read('META/misc_info.txt').decode().split('\n'))
Tao Bao46a59992017-06-05 11:55:16 -07001050 items = []
1051 for key in sorted(misc_info):
1052 if key in misc_info_old:
1053 items.append('%s=%s' % (key, misc_info[key]))
1054 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001055
Tao Bao8adcfd12016-06-17 17:01:22 -07001056
Tao Bao639118f2017-06-19 15:48:02 -07001057def ReplaceAvbSigningKeys(misc_info):
1058 """Replaces the AVB signing keys."""
1059
Tao Bao639118f2017-06-19 15:48:02 -07001060 def ReplaceAvbPartitionSigningKey(partition):
1061 key = OPTIONS.avb_keys.get(partition)
1062 if not key:
1063 return
1064
1065 algorithm = OPTIONS.avb_algorithms.get(partition)
1066 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
1067
Tao Bao0c28d2d2017-12-24 10:37:38 -08001068 print('Replacing AVB signing key for %s with "%s" (%s)' % (
1069 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -07001070 misc_info['avb_' + partition + '_algorithm'] = algorithm
1071 misc_info['avb_' + partition + '_key_path'] = key
1072
1073 extra_args = OPTIONS.avb_extra_args.get(partition)
1074 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -08001075 print('Setting extra AVB signing args for %s to "%s"' % (
1076 partition, extra_args))
Kelvin Zhang0876c412020-06-23 15:06:58 -04001077 args_key = AVB_FOOTER_ARGS_BY_PARTITION.get(
1078 partition,
1079 # custom partition
1080 "avb_{}_add_hashtree_footer_args".format(partition))
Tao Bao639118f2017-06-19 15:48:02 -07001081 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
1082
1083 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
1084 ReplaceAvbPartitionSigningKey(partition)
1085
Hongguang Chenf23364d2020-04-27 18:36:36 -07001086 for custom_partition in misc_info.get(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001087 "avb_custom_images_partition_list", "").strip().split():
Hongguang Chenf23364d2020-04-27 18:36:36 -07001088 ReplaceAvbPartitionSigningKey(custom_partition)
1089
Tao Bao639118f2017-06-19 15:48:02 -07001090
Tao Bao19b02fe2019-10-09 00:04:28 -07001091def RewriteAvbProps(misc_info):
1092 """Rewrites the props in AVB signing args."""
1093 for partition, args_key in AVB_FOOTER_ARGS_BY_PARTITION.items():
1094 args = misc_info.get(args_key)
1095 if not args:
1096 continue
1097
1098 tokens = []
1099 changed = False
1100 for token in args.split(' '):
1101 fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
1102 if not token.startswith(fingerprint_key):
1103 tokens.append(token)
1104 continue
1105 prefix, tag = token.rsplit('/', 1)
1106 tokens.append('{}/{}'.format(prefix, EditTags(tag)))
1107 changed = True
1108
1109 if changed:
1110 result = ' '.join(tokens)
1111 print('Rewriting AVB prop for {}:\n'.format(partition))
1112 print(' replace: {}'.format(args))
1113 print(' with: {}'.format(result))
1114 misc_info[args_key] = result
1115
1116
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001117def ReplaceGkiSigningKey(misc_info):
1118 """Replaces the GKI signing key."""
1119
1120 key = OPTIONS.gki_signing_key
1121 if not key:
1122 return
1123
1124 algorithm = OPTIONS.gki_signing_algorithm
1125 if not algorithm:
1126 raise ValueError("Missing --gki_signing_algorithm")
1127
1128 print('Replacing GKI signing key with "%s" (%s)' % (key, algorithm))
1129 misc_info["gki_signing_algorithm"] = algorithm
1130 misc_info["gki_signing_key_path"] = key
1131
1132 extra_args = OPTIONS.gki_signing_extra_args
1133 if extra_args:
Bowgo Tsaibcae74d2021-05-10 17:35:37 +08001134 print('Setting GKI signing args: "%s"' % (extra_args))
1135 misc_info["gki_signing_signature_args"] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001136
1137
Doug Zongker831840e2011-09-22 10:28:04 -07001138def BuildKeyMap(misc_info, key_mapping_options):
1139 for s, d in key_mapping_options:
1140 if s is None: # -d option
1141 devkey = misc_info.get("default_system_dev_certificate",
Dan Willemsen0ab1be62019-04-09 21:35:37 -07001142 "build/make/target/product/security/testkey")
Doug Zongker831840e2011-09-22 10:28:04 -07001143 devkeydir = os.path.dirname(devkey)
1144
1145 OPTIONS.key_map.update({
1146 devkeydir + "/testkey": d + "/releasekey",
1147 devkeydir + "/devkey": d + "/releasekey",
1148 devkeydir + "/media": d + "/media",
1149 devkeydir + "/shared": d + "/shared",
1150 devkeydir + "/platform": d + "/platform",
Oleh Cherpak982e6082019-12-10 12:58:54 +02001151 devkeydir + "/networkstack": d + "/networkstack",
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001152 })
Doug Zongker831840e2011-09-22 10:28:04 -07001153 else:
1154 OPTIONS.key_map[s] = d
1155
1156
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001157def GetApiLevelAndCodename(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001158 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001159 api_level = None
1160 codename = None
1161 for line in data.split("\n"):
1162 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001163 if line and line[0] != '#' and "=" in line:
1164 key, value = line.split("=", 1)
1165 key = key.strip()
1166 if key == "ro.build.version.sdk":
1167 api_level = int(value.strip())
1168 elif key == "ro.build.version.codename":
1169 codename = value.strip()
1170
1171 if api_level is None:
1172 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1173 if codename is None:
1174 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
1175
1176 return (api_level, codename)
1177
1178
1179def GetCodenameToApiLevelMap(input_tf_zip):
Tao Baoa3705452019-06-24 15:33:41 -07001180 data = input_tf_zip.read("SYSTEM/build.prop").decode()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001181 api_level = None
1182 codenames = None
1183 for line in data.split("\n"):
1184 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001185 if line and line[0] != '#' and "=" in line:
1186 key, value = line.split("=", 1)
1187 key = key.strip()
1188 if key == "ro.build.version.sdk":
1189 api_level = int(value.strip())
1190 elif key == "ro.build.version.all_codenames":
1191 codenames = value.strip().split(",")
1192
1193 if api_level is None:
1194 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
1195 if codenames is None:
1196 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
1197
Tao Baoa3705452019-06-24 15:33:41 -07001198 result = {}
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001199 for codename in codenames:
1200 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -07001201 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001202 result[codename] = api_level
1203 return result
1204
1205
Tao Baoaa7e9932019-03-15 09:37:01 -07001206def ReadApexKeysInfo(tf_zip):
1207 """Parses the APEX keys info from a given target-files zip.
1208
1209 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
1210 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
Jooyung Han8caba5e2021-10-27 03:58:09 +09001211 tuple of (payload_key, container_key, sign_tool).
Tao Baoaa7e9932019-03-15 09:37:01 -07001212
1213 Args:
1214 tf_zip: The input target_files ZipFile (already open).
1215
1216 Returns:
Jooyung Han8caba5e2021-10-27 03:58:09 +09001217 (payload_key, container_key, sign_tool):
1218 - payload_key contains the path to the payload signing key
1219 - container_key contains the path to the container signing key
1220 - sign_tool is an apex-specific signing tool for its payload contents
Tao Baoaa7e9932019-03-15 09:37:01 -07001221 """
1222 keys = {}
Tao Baoa3705452019-06-24 15:33:41 -07001223 for line in tf_zip.read('META/apexkeys.txt').decode().split('\n'):
Tao Baoaa7e9932019-03-15 09:37:01 -07001224 line = line.strip()
1225 if not line:
1226 continue
1227 matches = re.match(
1228 r'^name="(?P<NAME>.*)"\s+'
1229 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1230 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1231 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
Bill Peckham5c7b0342020-04-03 15:36:23 -07001232 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*?)"'
Jooyung Han8caba5e2021-10-27 03:58:09 +09001233 r'(\s+partition="(?P<PARTITION>.*?)")?'
1234 r'(\s+sign_tool="(?P<SIGN_TOOL>.*?)")?$',
Tao Baoaa7e9932019-03-15 09:37:01 -07001235 line)
1236 if not matches:
1237 continue
1238
1239 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001240 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1241
1242 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1243 pubkey_suffix_len = len(pubkey_suffix)
1244 privkey_suffix_len = len(privkey_suffix)
1245 return (pubkey.endswith(pubkey_suffix) and
1246 privkey.endswith(privkey_suffix) and
1247 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1248
Ivan Lozanob021b2a2020-07-28 09:31:06 -04001249 # Check the container key names, as we'll carry them without the
Tao Bao6d9e3da2019-03-26 12:59:25 -07001250 # extensions. This doesn't apply to payload keys though, which we will use
1251 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001252 container_cert = matches.group("CONTAINER_CERT")
1253 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Baof454c3a2019-04-24 23:53:42 -07001254 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1255 container_key = 'PRESIGNED'
1256 elif CompareKeys(
Kelvin Zhang7cab7502021-08-02 19:58:14 -04001257 container_cert, OPTIONS.public_key_suffix,
1258 container_private_key, OPTIONS.private_key_suffix):
Tao Baof454c3a2019-04-24 23:53:42 -07001259 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1260 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001261 raise ValueError("Failed to parse container keys: \n{}".format(line))
1262
Jooyung Han8caba5e2021-10-27 03:58:09 +09001263 sign_tool = matches.group("SIGN_TOOL")
1264 keys[name] = (payload_private_key, container_key, sign_tool)
Tao Baoaa7e9932019-03-15 09:37:01 -07001265
1266 return keys
1267
1268
Daniel Norman78554ea2021-09-14 10:29:38 -07001269def BuildVendorPartitions(output_zip_path):
1270 """Builds OPTIONS.vendor_partitions using OPTIONS.vendor_otatools."""
1271 if OPTIONS.vendor_partitions.difference(ALLOWED_VENDOR_PARTITIONS):
1272 logger.warning("Allowed --vendor_partitions: %s",
1273 ",".join(ALLOWED_VENDOR_PARTITIONS))
1274 OPTIONS.vendor_partitions = ALLOWED_VENDOR_PARTITIONS.intersection(
1275 OPTIONS.vendor_partitions)
1276
1277 logger.info("Building vendor partitions using vendor otatools.")
1278 vendor_tempdir = common.UnzipTemp(output_zip_path, [
1279 "META/*",
Po Hu0663ae42021-09-27 12:59:06 +08001280 "SYSTEM/build.prop",
Daniel Norman78554ea2021-09-14 10:29:38 -07001281 ] + ["{}/*".format(p.upper()) for p in OPTIONS.vendor_partitions])
1282
1283 # Disable various partitions that build based on misc_info fields.
1284 # Only partitions in ALLOWED_VENDOR_PARTITIONS can be rebuilt using
1285 # vendor otatools. These other partitions will be rebuilt using the main
1286 # otatools if necessary.
1287 vendor_misc_info_path = os.path.join(vendor_tempdir, "META/misc_info.txt")
1288 vendor_misc_info = common.LoadDictionaryFromFile(vendor_misc_info_path)
1289 vendor_misc_info["no_boot"] = "true" # boot
1290 vendor_misc_info["vendor_boot"] = "false" # vendor_boot
1291 vendor_misc_info["no_recovery"] = "true" # recovery
1292 vendor_misc_info["board_bpt_enable"] = "false" # partition-table
1293 vendor_misc_info["has_dtbo"] = "false" # dtbo
1294 vendor_misc_info["has_pvmfw"] = "false" # pvmfw
1295 vendor_misc_info["avb_custom_images_partition_list"] = "" # custom images
1296 vendor_misc_info["avb_enable"] = "false" # vbmeta
1297 vendor_misc_info["use_dynamic_partitions"] = "false" # super_empty
1298 vendor_misc_info["build_super_partition"] = "false" # super split
1299 with open(vendor_misc_info_path, "w") as output:
1300 for key in sorted(vendor_misc_info):
1301 output.write("{}={}\n".format(key, vendor_misc_info[key]))
1302
Po Hu0663ae42021-09-27 12:59:06 +08001303 # Disable system partition by a placeholder of IMAGES/system.img,
1304 # instead of removing SYSTEM folder.
1305 # Because SYSTEM/build.prop is still needed for:
1306 # add_img_to_target_files.CreateImage ->
1307 # common.BuildInfo ->
1308 # common.BuildInfo.CalculateFingerprint
1309 vendor_images_path = os.path.join(vendor_tempdir, "IMAGES")
1310 if not os.path.exists(vendor_images_path):
1311 os.makedirs(vendor_images_path)
1312 with open(os.path.join(vendor_images_path, "system.img"), "w") as output:
1313 pass
1314
Daniel Norman78554ea2021-09-14 10:29:38 -07001315 # Disable care_map.pb as not all ab_partitions are available when
1316 # vendor otatools regenerates vendor images.
Po Hu0663ae42021-09-27 12:59:06 +08001317 if os.path.exists(os.path.join(vendor_tempdir, "META/ab_partitions.txt")):
1318 os.remove(os.path.join(vendor_tempdir, "META/ab_partitions.txt"))
1319 # Disable RADIO images
1320 if os.path.exists(os.path.join(vendor_tempdir, "META/pack_radioimages.txt")):
1321 os.remove(os.path.join(vendor_tempdir, "META/pack_radioimages.txt"))
Daniel Norman78554ea2021-09-14 10:29:38 -07001322
1323 # Build vendor images using vendor otatools.
Iavor-Valentin Iftime63cde0f2022-03-04 16:02:44 +00001324 # Accept either a zip file or extracted directory.
1325 if os.path.isfile(OPTIONS.vendor_otatools):
1326 vendor_otatools_dir = common.MakeTempDir(prefix="vendor_otatools_")
1327 common.UnzipToDir(OPTIONS.vendor_otatools, vendor_otatools_dir)
1328 else:
1329 vendor_otatools_dir = OPTIONS.vendor_otatools
Daniel Norman78554ea2021-09-14 10:29:38 -07001330 cmd = [
1331 os.path.join(vendor_otatools_dir, "bin", "add_img_to_target_files"),
1332 "--is_signing",
Po Hu0663ae42021-09-27 12:59:06 +08001333 "--add_missing",
Daniel Norman78554ea2021-09-14 10:29:38 -07001334 "--verbose",
1335 vendor_tempdir,
1336 ]
1337 common.RunAndCheckOutput(cmd, verbose=True)
1338
1339 logger.info("Writing vendor partitions to output archive.")
1340 with zipfile.ZipFile(
1341 output_zip_path, "a", compression=zipfile.ZIP_DEFLATED,
1342 allowZip64=True) as output_zip:
1343 for p in OPTIONS.vendor_partitions:
Iavor-Valentin Iftime880e4432022-03-17 14:02:27 +00001344 img_file_path = "IMAGES/{}.img".format(p)
1345 map_file_path = "IMAGES/{}.map".format(p)
1346 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, img_file_path), img_file_path)
1347 common.ZipWrite(output_zip, os.path.join(vendor_tempdir, map_file_path), map_file_path)
Daniel Norman78554ea2021-09-14 10:29:38 -07001348
1349
Doug Zongkereef39442009-04-02 12:14:19 -07001350def main(argv):
1351
Doug Zongker831840e2011-09-22 10:28:04 -07001352 key_mapping_options = []
1353
Doug Zongkereef39442009-04-02 12:14:19 -07001354 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001355 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001356 names, key = a.split("=")
1357 names = names.split(",")
1358 for n in names:
1359 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001360 elif o == "--extra_apex_payload_key":
1361 apex_name, key = a.split("=")
1362 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001363 elif o == "--skip_apks_with_path_prefix":
Tianjiea85bdf02020-07-29 11:56:19 -07001364 # Check the prefix, which must be in all upper case.
Tao Bao93c2a012018-06-19 12:19:35 -07001365 prefix = a.split('/')[0]
1366 if not prefix or prefix != prefix.upper():
1367 raise ValueError("Invalid path prefix '%s'" % (a,))
1368 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001369 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001370 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001371 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001372 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001373 elif o in ("-o", "--replace_ota_keys"):
1374 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001375 elif o in ("-t", "--tag_changes"):
1376 new = []
1377 for i in a.split(","):
1378 i = i.strip()
1379 if not i or i[0] not in "-+":
1380 raise ValueError("Bad tag change '%s'" % (i,))
1381 new.append(i[0] + i[1:].strip())
1382 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001383 elif o == "--replace_verity_public_key":
1384 OPTIONS.replace_verity_public_key = (True, a)
1385 elif o == "--replace_verity_private_key":
1386 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001387 elif o == "--replace_verity_keyid":
1388 OPTIONS.replace_verity_keyid = (True, a)
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001389 elif o == "--remove_avb_public_keys":
1390 OPTIONS.remove_avb_public_keys = a.split(",")
Tao Bao639118f2017-06-19 15:48:02 -07001391 elif o == "--avb_vbmeta_key":
1392 OPTIONS.avb_keys['vbmeta'] = a
1393 elif o == "--avb_vbmeta_algorithm":
1394 OPTIONS.avb_algorithms['vbmeta'] = a
1395 elif o == "--avb_vbmeta_extra_args":
1396 OPTIONS.avb_extra_args['vbmeta'] = a
1397 elif o == "--avb_boot_key":
1398 OPTIONS.avb_keys['boot'] = a
1399 elif o == "--avb_boot_algorithm":
1400 OPTIONS.avb_algorithms['boot'] = a
1401 elif o == "--avb_boot_extra_args":
1402 OPTIONS.avb_extra_args['boot'] = a
1403 elif o == "--avb_dtbo_key":
1404 OPTIONS.avb_keys['dtbo'] = a
1405 elif o == "--avb_dtbo_algorithm":
1406 OPTIONS.avb_algorithms['dtbo'] = a
1407 elif o == "--avb_dtbo_extra_args":
1408 OPTIONS.avb_extra_args['dtbo'] = a
1409 elif o == "--avb_system_key":
1410 OPTIONS.avb_keys['system'] = a
1411 elif o == "--avb_system_algorithm":
1412 OPTIONS.avb_algorithms['system'] = a
1413 elif o == "--avb_system_extra_args":
1414 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001415 elif o == "--avb_system_other_key":
1416 OPTIONS.avb_keys['system_other'] = a
1417 elif o == "--avb_system_other_algorithm":
1418 OPTIONS.avb_algorithms['system_other'] = a
1419 elif o == "--avb_system_other_extra_args":
1420 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001421 elif o == "--avb_vendor_key":
1422 OPTIONS.avb_keys['vendor'] = a
1423 elif o == "--avb_vendor_algorithm":
1424 OPTIONS.avb_algorithms['vendor'] = a
1425 elif o == "--avb_vendor_extra_args":
1426 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod6085d62019-05-06 12:55:42 -07001427 elif o == "--avb_vbmeta_system_key":
1428 OPTIONS.avb_keys['vbmeta_system'] = a
1429 elif o == "--avb_vbmeta_system_algorithm":
1430 OPTIONS.avb_algorithms['vbmeta_system'] = a
1431 elif o == "--avb_vbmeta_system_extra_args":
1432 OPTIONS.avb_extra_args['vbmeta_system'] = a
1433 elif o == "--avb_vbmeta_vendor_key":
1434 OPTIONS.avb_keys['vbmeta_vendor'] = a
1435 elif o == "--avb_vbmeta_vendor_algorithm":
1436 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1437 elif o == "--avb_vbmeta_vendor_extra_args":
1438 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001439 elif o == "--avb_apex_extra_args":
1440 OPTIONS.avb_extra_args['apex'] = a
Hongguang Chenf23364d2020-04-27 18:36:36 -07001441 elif o == "--avb_extra_custom_image_key":
1442 partition, key = a.split("=")
1443 OPTIONS.avb_keys[partition] = key
1444 elif o == "--avb_extra_custom_image_algorithm":
1445 partition, algorithm = a.split("=")
1446 OPTIONS.avb_algorithms[partition] = algorithm
1447 elif o == "--avb_extra_custom_image_extra_args":
Hongguang Chen883eecb2020-05-23 22:20:19 -07001448 # Setting the maxsplit parameter to one, which will return a list with
1449 # two elements. e.g., the second '=' should not be splitted for
1450 # 'oem=--signing_helper_with_files=/tmp/avbsigner.sh'.
1451 partition, extra_args = a.split("=", 1)
Hongguang Chenf23364d2020-04-27 18:36:36 -07001452 OPTIONS.avb_extra_args[partition] = extra_args
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001453 elif o == "--gki_signing_key":
1454 OPTIONS.gki_signing_key = a
1455 elif o == "--gki_signing_algorithm":
1456 OPTIONS.gki_signing_algorithm = a
1457 elif o == "--gki_signing_extra_args":
1458 OPTIONS.gki_signing_extra_args = a
Daniel Norman78554ea2021-09-14 10:29:38 -07001459 elif o == "--vendor_otatools":
1460 OPTIONS.vendor_otatools = a
1461 elif o == "--vendor_partitions":
1462 OPTIONS.vendor_partitions = set(a.split(","))
Bowgo Tsai2a781692021-10-13 17:39:33 +08001463 elif o == "--allow_gsi_debug_sepolicy":
1464 OPTIONS.allow_gsi_debug_sepolicy = True
Doug Zongkereef39442009-04-02 12:14:19 -07001465 else:
1466 return False
1467 return True
1468
Tao Bao639118f2017-06-19 15:48:02 -07001469 args = common.ParseOptions(
1470 argv, __doc__,
1471 extra_opts="e:d:k:ot:",
1472 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001473 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001474 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001475 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001476 "default_key_mappings=",
1477 "key_mapping=",
1478 "replace_ota_keys",
1479 "tag_changes=",
1480 "replace_verity_public_key=",
1481 "replace_verity_private_key=",
1482 "replace_verity_keyid=",
Bowgo Tsai2fe786a2020-02-21 17:48:18 +08001483 "remove_avb_public_keys=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001484 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001485 "avb_vbmeta_algorithm=",
1486 "avb_vbmeta_key=",
1487 "avb_vbmeta_extra_args=",
1488 "avb_boot_algorithm=",
1489 "avb_boot_key=",
1490 "avb_boot_extra_args=",
1491 "avb_dtbo_algorithm=",
1492 "avb_dtbo_key=",
1493 "avb_dtbo_extra_args=",
1494 "avb_system_algorithm=",
1495 "avb_system_key=",
1496 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001497 "avb_system_other_algorithm=",
1498 "avb_system_other_key=",
1499 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001500 "avb_vendor_algorithm=",
1501 "avb_vendor_key=",
1502 "avb_vendor_extra_args=",
Tao Baod6085d62019-05-06 12:55:42 -07001503 "avb_vbmeta_system_algorithm=",
1504 "avb_vbmeta_system_key=",
1505 "avb_vbmeta_system_extra_args=",
1506 "avb_vbmeta_vendor_algorithm=",
1507 "avb_vbmeta_vendor_key=",
1508 "avb_vbmeta_vendor_extra_args=",
Hongguang Chenf23364d2020-04-27 18:36:36 -07001509 "avb_extra_custom_image_key=",
1510 "avb_extra_custom_image_algorithm=",
1511 "avb_extra_custom_image_extra_args=",
Bowgo Tsai27c39b02021-03-12 21:40:32 +08001512 "gki_signing_key=",
1513 "gki_signing_algorithm=",
1514 "gki_signing_extra_args=",
Daniel Norman78554ea2021-09-14 10:29:38 -07001515 "vendor_partitions=",
1516 "vendor_otatools=",
Bowgo Tsai2a781692021-10-13 17:39:33 +08001517 "allow_gsi_debug_sepolicy",
Tao Bao639118f2017-06-19 15:48:02 -07001518 ],
1519 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001520
1521 if len(args) != 2:
1522 common.Usage(__doc__)
1523 sys.exit(1)
1524
Tao Baobadceb22019-03-15 09:33:43 -07001525 common.InitLogging()
1526
Kelvin Zhang928c2342020-09-22 16:15:57 -04001527 input_zip = zipfile.ZipFile(args[0], "r", allowZip64=True)
Tao Bao2b8f4892017-06-13 12:54:58 -07001528 output_zip = zipfile.ZipFile(args[1], "w",
1529 compression=zipfile.ZIP_DEFLATED,
1530 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001531
Doug Zongker831840e2011-09-22 10:28:04 -07001532 misc_info = common.LoadInfoDict(input_zip)
1533
1534 BuildKeyMap(misc_info, key_mapping_options)
1535
Tao Baoaa7e9932019-03-15 09:37:01 -07001536 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1537 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001538
Tao Baoaa7e9932019-03-15 09:37:01 -07001539 apex_keys_info = ReadApexKeysInfo(input_zip)
1540 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1541
Tianjie Xu88a759d2020-01-23 10:47:54 -08001542 # TODO(xunchang) check for the apks inside the apex files, and abort early if
1543 # the keys are not available.
Tao Baoaa7e9932019-03-15 09:37:01 -07001544 CheckApkAndApexKeysAvailable(
1545 input_zip,
1546 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001547 compressed_extension,
1548 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001549
1550 key_passwords = common.GetKeyPasswords(
1551 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001552 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001553 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001554
Doug Zongker412c02f2014-02-13 10:58:24 -08001555 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001556 apk_keys, apex_keys, key_passwords,
1557 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001558 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001559
Tao Bao2ed665a2015-04-01 11:21:55 -07001560 common.ZipClose(input_zip)
1561 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001562
Daniel Norman78554ea2021-09-14 10:29:38 -07001563 if OPTIONS.vendor_partitions and OPTIONS.vendor_otatools:
1564 BuildVendorPartitions(args[1])
1565
Tianjie Xub48589a2016-08-03 19:21:52 -07001566 # Skip building userdata.img and cache.img when signing the target files.
Daniel Norman78554ea2021-09-14 10:29:38 -07001567 new_args = ["--is_signing", "--add_missing", "--verbose"]
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001568 # add_img_to_target_files builds the system image from scratch, so the
1569 # recovery patch is guaranteed to be regenerated there.
1570 if OPTIONS.rebuild_recovery:
1571 new_args.append("--rebuild_recovery")
1572 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001573 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001574
Tao Bao0c28d2d2017-12-24 10:37:38 -08001575 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001576
1577
1578if __name__ == '__main__':
1579 try:
1580 main(sys.argv[1:])
Tao Bao639118f2017-06-19 15:48:02 -07001581 finally:
1582 common.Cleanup()