blob: 1b3d6f1096255b44dc7364b6d973fe98d4f21c5c [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
59 META/misc_info.txt. (Defaulting to "build/target/product/security"
60 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
Tao Baod403e7b2019-05-06 12:55:42 -070094 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
95 vbmeta_vendor}_algorithm <algorithm>
96 --avb_{boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
97 vbmeta_vendor}_key <key>
Tao Bao639118f2017-06-19 15:48:02 -070098 Use the specified algorithm (e.g. SHA256_RSA4096) and the key to AVB-sign
99 the specified image. Otherwise it uses the existing values in info dict.
100
Tao Baod403e7b2019-05-06 12:55:42 -0700101 --avb_{apex,boot,system,system_other,vendor,dtbo,vbmeta,vbmeta_system,
102 vbmeta_vendor}_extra_args <args>
Tao Bao639118f2017-06-19 15:48:02 -0700103 Specify any additional args that are needed to AVB-sign the image
104 (e.g. "--signing_helper /path/to/helper"). The args will be appended to
105 the existing ones in info dict.
Doug Zongkereef39442009-04-02 12:14:19 -0700106"""
107
Tao Bao0c28d2d2017-12-24 10:37:38 -0800108from __future__ import print_function
Doug Zongkereef39442009-04-02 12:14:19 -0700109
Robert Craig817c5742013-04-19 10:59:22 -0400110import base64
Doug Zongker8e931bf2009-04-06 15:21:45 -0700111import copy
Robert Craig817c5742013-04-19 10:59:22 -0400112import errno
Narayan Kamatha07bf042017-08-14 14:49:21 +0100113import gzip
Tao Baoaa7e9932019-03-15 09:37:01 -0700114import itertools
Tao Baobadceb22019-03-15 09:33:43 -0700115import logging
Doug Zongkereef39442009-04-02 12:14:19 -0700116import os
117import re
Narayan Kamatha07bf042017-08-14 14:49:21 +0100118import shutil
Tao Bao9fdd00f2017-07-12 11:57:05 -0700119import stat
Doug Zongkereef39442009-04-02 12:14:19 -0700120import subprocess
Tao Bao0c28d2d2017-12-24 10:37:38 -0800121import sys
Doug Zongkereef39442009-04-02 12:14:19 -0700122import tempfile
123import zipfile
Tao Bao66472632017-12-04 17:16:36 -0800124from xml.etree import ElementTree
Doug Zongkereef39442009-04-02 12:14:19 -0700125
Doug Zongker3c84f562014-07-31 11:06:30 -0700126import add_img_to_target_files
Tao Baoaa7e9932019-03-15 09:37:01 -0700127import apex_utils
Doug Zongkereef39442009-04-02 12:14:19 -0700128import common
129
Tao Bao0c28d2d2017-12-24 10:37:38 -0800130
131if sys.hexversion < 0x02070000:
132 print("Python 2.7 or newer is required.", file=sys.stderr)
133 sys.exit(1)
134
135
Tao Baobadceb22019-03-15 09:33:43 -0700136logger = logging.getLogger(__name__)
137
Doug Zongkereef39442009-04-02 12:14:19 -0700138OPTIONS = common.OPTIONS
139
140OPTIONS.extra_apks = {}
Tao Baoaa7e9932019-03-15 09:37:01 -0700141OPTIONS.extra_apex_payload_keys = {}
Tao Bao93c2a012018-06-19 12:19:35 -0700142OPTIONS.skip_apks_with_path_prefix = set()
Doug Zongkereef39442009-04-02 12:14:19 -0700143OPTIONS.key_map = {}
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700144OPTIONS.rebuild_recovery = False
Doug Zongker8e931bf2009-04-06 15:21:45 -0700145OPTIONS.replace_ota_keys = False
Geremy Condraf19b3652014-07-29 17:54:54 -0700146OPTIONS.replace_verity_public_key = False
147OPTIONS.replace_verity_private_key = False
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700148OPTIONS.replace_verity_keyid = False
Doug Zongker831840e2011-09-22 10:28:04 -0700149OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys")
Tao Bao639118f2017-06-19 15:48:02 -0700150OPTIONS.avb_keys = {}
151OPTIONS.avb_algorithms = {}
152OPTIONS.avb_extra_args = {}
Doug Zongkereef39442009-04-02 12:14:19 -0700153
Tao Bao0c28d2d2017-12-24 10:37:38 -0800154
Narayan Kamatha07bf042017-08-14 14:49:21 +0100155def GetApkCerts(certmap):
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800156 # apply the key remapping to the contents of the file
157 for apk, cert in certmap.iteritems():
158 certmap[apk] = OPTIONS.key_map.get(cert, cert)
159
160 # apply all the -e options, overriding anything in the file
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700161 for apk, cert in OPTIONS.extra_apks.iteritems():
Doug Zongkerdecf9952009-12-15 17:27:49 -0800162 if not cert:
163 cert = "PRESIGNED"
Doug Zongkerad88c7c2009-04-14 12:34:27 -0700164 certmap[apk] = OPTIONS.key_map.get(cert, cert)
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800165
Doug Zongkereef39442009-04-02 12:14:19 -0700166 return certmap
167
168
Tao Baoaa7e9932019-03-15 09:37:01 -0700169def GetApexKeys(keys_info, key_map):
170 """Gets APEX payload and container signing keys by applying the mapping rules.
171
Tao Baoe1343992019-03-19 12:24:03 -0700172 Presigned payload / container keys will be set accordingly.
Tao Baoaa7e9932019-03-15 09:37:01 -0700173
174 Args:
175 keys_info: A dict that maps from APEX filenames to a tuple of (payload_key,
176 container_key).
177 key_map: A dict that overrides the keys, specified via command-line input.
178
179 Returns:
180 A dict that contains the updated APEX key mapping, which should be used for
181 the current signing.
182 """
183 # Apply all the --extra_apex_payload_key options to override the payload
184 # signing keys in the given keys_info.
185 for apex, key in OPTIONS.extra_apex_payload_keys.items():
Tao Baoe1343992019-03-19 12:24:03 -0700186 if not key:
187 key = 'PRESIGNED'
Tao Baob369c722019-07-11 11:52:52 -0700188 if apex not in keys_info:
189 logger.warning('Failed to find %s in target_files; Ignored', apex)
190 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700191 keys_info[apex] = (key, keys_info[apex][1])
192
193 # Apply the key remapping to container keys.
194 for apex, (payload_key, container_key) in keys_info.items():
195 keys_info[apex] = (payload_key, key_map.get(container_key, container_key))
196
197 # Apply all the --extra_apks options to override the container keys.
198 for apex, key in OPTIONS.extra_apks.items():
199 # Skip non-APEX containers.
200 if apex not in keys_info:
201 continue
Tao Baoe1343992019-03-19 12:24:03 -0700202 if not key:
203 key = 'PRESIGNED'
Tao Baofa9de0a2019-03-18 10:24:17 -0700204 keys_info[apex] = (keys_info[apex][0], key_map.get(key, key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700205
206 return keys_info
207
208
Tao Bao93c2a012018-06-19 12:19:35 -0700209def GetApkFileInfo(filename, compressed_extension, skipped_prefixes):
Tao Bao11f955c2018-06-19 12:19:35 -0700210 """Returns the APK info based on the given filename.
211
212 Checks if the given filename (with path) looks like an APK file, by taking the
Tao Bao93c2a012018-06-19 12:19:35 -0700213 compressed extension into consideration. If it appears to be an APK file,
214 further checks if the APK file should be skipped when signing, based on the
215 given path prefixes.
Tao Bao11f955c2018-06-19 12:19:35 -0700216
217 Args:
218 filename: Path to the file.
219 compressed_extension: The extension string of compressed APKs (e.g. ".gz"),
220 or None if there's no compressed APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700221 skipped_prefixes: A set/list/tuple of the path prefixes to be skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700222
223 Returns:
Tao Bao93c2a012018-06-19 12:19:35 -0700224 (is_apk, is_compressed, should_be_skipped): is_apk indicates whether the
225 given filename is an APK file. is_compressed indicates whether the APK file
226 is compressed (only meaningful when is_apk is True). should_be_skipped
227 indicates whether the filename matches any of the given prefixes to be
228 skipped.
Tao Bao11f955c2018-06-19 12:19:35 -0700229
230 Raises:
Tao Bao93c2a012018-06-19 12:19:35 -0700231 AssertionError: On invalid compressed_extension or skipped_prefixes inputs.
Tao Bao11f955c2018-06-19 12:19:35 -0700232 """
233 assert compressed_extension is None or compressed_extension.startswith('.'), \
234 "Invalid compressed_extension arg: '{}'".format(compressed_extension)
235
Tao Bao93c2a012018-06-19 12:19:35 -0700236 # skipped_prefixes should be one of set/list/tuple types. Other types such as
237 # str shouldn't be accepted.
Tao Baobadceb22019-03-15 09:33:43 -0700238 assert isinstance(skipped_prefixes, (set, list, tuple)), \
239 "Invalid skipped_prefixes input type: {}".format(type(skipped_prefixes))
Tao Bao93c2a012018-06-19 12:19:35 -0700240
Tao Bao11f955c2018-06-19 12:19:35 -0700241 compressed_apk_extension = (
242 ".apk" + compressed_extension if compressed_extension else None)
243 is_apk = (filename.endswith(".apk") or
244 (compressed_apk_extension and
245 filename.endswith(compressed_apk_extension)))
246 if not is_apk:
Tao Bao93c2a012018-06-19 12:19:35 -0700247 return (False, False, False)
Tao Bao11f955c2018-06-19 12:19:35 -0700248
249 is_compressed = (compressed_apk_extension and
250 filename.endswith(compressed_apk_extension))
Tao Bao93c2a012018-06-19 12:19:35 -0700251 should_be_skipped = filename.startswith(tuple(skipped_prefixes))
252 return (True, is_compressed, should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700253
254
Tao Baoaa7e9932019-03-15 09:37:01 -0700255def CheckApkAndApexKeysAvailable(input_tf_zip, known_keys,
Tao Baoe1343992019-03-19 12:24:03 -0700256 compressed_extension, apex_keys):
Tao Baoaa7e9932019-03-15 09:37:01 -0700257 """Checks that all the APKs and APEXes have keys specified.
Tao Bao11f955c2018-06-19 12:19:35 -0700258
259 Args:
260 input_tf_zip: An open target_files zip file.
Tao Baoaa7e9932019-03-15 09:37:01 -0700261 known_keys: A set of APKs and APEXes that have known signing keys.
Tao Bao11f955c2018-06-19 12:19:35 -0700262 compressed_extension: The extension string of compressed APKs, such as
Tao Baoaa7e9932019-03-15 09:37:01 -0700263 '.gz', or None if there's no compressed APKs.
Tao Baoe1343992019-03-19 12:24:03 -0700264 apex_keys: A dict that contains the key mapping from APEX name to
265 (payload_key, container_key).
Tao Bao11f955c2018-06-19 12:19:35 -0700266
267 Raises:
Tao Baoaa7e9932019-03-15 09:37:01 -0700268 AssertionError: On finding unknown APKs and APEXes.
Tao Bao11f955c2018-06-19 12:19:35 -0700269 """
Tao Baoaa7e9932019-03-15 09:37:01 -0700270 unknown_files = []
Doug Zongkereb338ef2009-05-20 16:50:49 -0700271 for info in input_tf_zip.infolist():
Tao Baoaa7e9932019-03-15 09:37:01 -0700272 # Handle APEXes first, e.g. SYSTEM/apex/com.android.tzdata.apex.
273 if (info.filename.startswith('SYSTEM/apex') and
274 info.filename.endswith('.apex')):
275 name = os.path.basename(info.filename)
276 if name not in known_keys:
277 unknown_files.append(name)
278 continue
279
280 # And APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700281 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
282 info.filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
283 if not is_apk or should_be_skipped:
Tao Bao11f955c2018-06-19 12:19:35 -0700284 continue
Tao Baoaa7e9932019-03-15 09:37:01 -0700285
Tao Bao11f955c2018-06-19 12:19:35 -0700286 name = os.path.basename(info.filename)
287 if is_compressed:
288 name = name[:-len(compressed_extension)]
Tao Baoaa7e9932019-03-15 09:37:01 -0700289 if name not in known_keys:
290 unknown_files.append(name)
Tao Bao11f955c2018-06-19 12:19:35 -0700291
Tao Baoaa7e9932019-03-15 09:37:01 -0700292 assert not unknown_files, \
Tao Bao11f955c2018-06-19 12:19:35 -0700293 ("No key specified for:\n {}\n"
294 "Use '-e <apkname>=' to specify a key (which may be an empty string to "
Tao Baoaa7e9932019-03-15 09:37:01 -0700295 "not sign this apk).".format("\n ".join(unknown_files)))
Doug Zongkereb338ef2009-05-20 16:50:49 -0700296
Tao Baoe1343992019-03-19 12:24:03 -0700297 # For all the APEXes, double check that we won't have an APEX that has only
298 # one of the payload / container keys set.
299 if not apex_keys:
300 return
301
302 invalid_apexes = []
303 for info in input_tf_zip.infolist():
304 if (not info.filename.startswith('SYSTEM/apex') or
305 not info.filename.endswith('.apex')):
306 continue
307
308 name = os.path.basename(info.filename)
309 (payload_key, container_key) = apex_keys[name]
310 if ((payload_key in common.SPECIAL_CERT_STRINGS and
311 container_key not in common.SPECIAL_CERT_STRINGS) or
312 (payload_key not in common.SPECIAL_CERT_STRINGS and
313 container_key in common.SPECIAL_CERT_STRINGS)):
314 invalid_apexes.append(
315 "{}: payload_key {}, container_key {}".format(
316 name, payload_key, container_key))
317
318 assert not invalid_apexes, \
319 "Invalid APEX keys specified:\n {}\n".format(
320 "\n ".join(invalid_apexes))
321
Doug Zongkereb338ef2009-05-20 16:50:49 -0700322
Narayan Kamatha07bf042017-08-14 14:49:21 +0100323def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map,
324 is_compressed):
Doug Zongkereef39442009-04-02 12:14:19 -0700325 unsigned = tempfile.NamedTemporaryFile()
326 unsigned.write(data)
327 unsigned.flush()
328
Narayan Kamatha07bf042017-08-14 14:49:21 +0100329 if is_compressed:
330 uncompressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800331 with gzip.open(unsigned.name, "rb") as in_file, \
332 open(uncompressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100333 shutil.copyfileobj(in_file, out_file)
334
335 # Finally, close the "unsigned" file (which is gzip compressed), and then
336 # replace it with the uncompressed version.
337 #
338 # TODO(narayan): All this nastiness can be avoided if python 3.2 is in use,
339 # we could just gzip / gunzip in-memory buffers instead.
340 unsigned.close()
341 unsigned = uncompressed
342
Doug Zongkereef39442009-04-02 12:14:19 -0700343 signed = tempfile.NamedTemporaryFile()
344
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800345 # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's
346 # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK
347 # didn't change, we don't want its signature to change due to the switch
348 # from SHA-1 to SHA-256.
349 # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion
350 # is 18 or higher. For pre-N builds we disable this mechanism by pretending
351 # that the APK's minSdkVersion is 1.
352 # For N+ builds, we let APK signer rely on the APK's minSdkVersion to
353 # determine whether to use SHA-256.
354 min_api_level = None
355 if platform_api_level > 23:
356 # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's
357 # minSdkVersion attribute
358 min_api_level = None
359 else:
360 # Force APK signer to use SHA-1
361 min_api_level = 1
362
363 common.SignFile(unsigned.name, signed.name, keyname, pw,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800364 min_api_level=min_api_level,
365 codename_to_api_level_map=codename_to_api_level_map)
Doug Zongkereef39442009-04-02 12:14:19 -0700366
Tao Bao0c28d2d2017-12-24 10:37:38 -0800367 data = None
Narayan Kamatha07bf042017-08-14 14:49:21 +0100368 if is_compressed:
369 # Recompress the file after it has been signed.
370 compressed = tempfile.NamedTemporaryFile()
Tao Bao0c28d2d2017-12-24 10:37:38 -0800371 with open(signed.name, "rb") as in_file, \
372 gzip.open(compressed.name, "wb") as out_file:
Narayan Kamatha07bf042017-08-14 14:49:21 +0100373 shutil.copyfileobj(in_file, out_file)
374
375 data = compressed.read()
376 compressed.close()
377 else:
378 data = signed.read()
379
Doug Zongkereef39442009-04-02 12:14:19 -0700380 unsigned.close()
381 signed.close()
382
383 return data
384
385
Doug Zongker412c02f2014-02-13 10:58:24 -0800386def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -0700387 apk_keys, apex_keys, key_passwords,
388 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +0100389 compressed_extension):
Tao Bao93c2a012018-06-19 12:19:35 -0700390 # maxsize measures the maximum filename length, including the ones to be
391 # skipped.
Tao Bao0c28d2d2017-12-24 10:37:38 -0800392 maxsize = max(
393 [len(os.path.basename(i.filename)) for i in input_tf_zip.infolist()
Tao Bao93c2a012018-06-19 12:19:35 -0700394 if GetApkFileInfo(i.filename, compressed_extension, [])[0]])
Tao Baoa80ed222016-06-16 14:41:24 -0700395 system_root_image = misc_info.get("system_root_image") == "true"
Doug Zongker412c02f2014-02-13 10:58:24 -0800396
Doug Zongkereef39442009-04-02 12:14:19 -0700397 for info in input_tf_zip.infolist():
Tao Bao11f955c2018-06-19 12:19:35 -0700398 filename = info.filename
399 if filename.startswith("IMAGES/"):
Dan Albert8b72aef2015-03-23 19:13:21 -0700400 continue
Doug Zongker3c84f562014-07-31 11:06:30 -0700401
Tao Bao33bf2682019-01-11 12:37:35 -0800402 # Skip split super images, which will be re-generated during signing.
403 if filename.startswith("OTA/") and filename.endswith(".img"):
404 continue
405
Tao Bao11f955c2018-06-19 12:19:35 -0700406 data = input_tf_zip.read(filename)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700407 out_info = copy.copy(info)
Tao Bao93c2a012018-06-19 12:19:35 -0700408 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
409 filename, compressed_extension, OPTIONS.skip_apks_with_path_prefix)
410
411 if is_apk and should_be_skipped:
412 # Copy skipped APKs verbatim.
413 print(
414 "NOT signing: %s\n"
415 " (skipped due to matching prefix)" % (filename,))
416 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker412c02f2014-02-13 10:58:24 -0800417
Tao Baof2cffbd2015-07-22 12:33:18 -0700418 # Sign APKs.
Tao Bao93c2a012018-06-19 12:19:35 -0700419 elif is_apk:
Tao Bao11f955c2018-06-19 12:19:35 -0700420 name = os.path.basename(filename)
Narayan Kamatha07bf042017-08-14 14:49:21 +0100421 if is_compressed:
422 name = name[:-len(compressed_extension)]
423
Tao Baoaa7e9932019-03-15 09:37:01 -0700424 key = apk_keys[name]
Doug Zongkerf6a53aa2009-12-15 15:06:55 -0800425 if key not in common.SPECIAL_CERT_STRINGS:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800426 print(" signing: %-*s (%s)" % (maxsize, name, key))
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800427 signed_data = SignApk(data, key, key_passwords[key], platform_api_level,
Tao Bao0c28d2d2017-12-24 10:37:38 -0800428 codename_to_api_level_map, is_compressed)
Tao Bao2ed665a2015-04-01 11:21:55 -0700429 common.ZipWriteStr(output_tf_zip, out_info, signed_data)
Doug Zongkereef39442009-04-02 12:14:19 -0700430 else:
431 # an APK we're not supposed to sign.
Tao Bao93c2a012018-06-19 12:19:35 -0700432 print(
433 "NOT signing: %s\n"
434 " (skipped due to special cert string)" % (name,))
Tao Bao2ed665a2015-04-01 11:21:55 -0700435 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoa80ed222016-06-16 14:41:24 -0700436
Tao Baoaa7e9932019-03-15 09:37:01 -0700437 # Sign bundled APEX files.
438 elif filename.startswith("SYSTEM/apex") and filename.endswith(".apex"):
439 name = os.path.basename(filename)
440 payload_key, container_key = apex_keys[name]
441
Tao Baoe1343992019-03-19 12:24:03 -0700442 # We've asserted not having a case with only one of them PRESIGNED.
443 if (payload_key not in common.SPECIAL_CERT_STRINGS and
444 container_key not in common.SPECIAL_CERT_STRINGS):
445 print(" signing: %-*s container (%s)" % (
446 maxsize, name, container_key))
447 print(" : %-*s payload (%s)" % (
448 maxsize, name, payload_key))
Tao Baoaa7e9932019-03-15 09:37:01 -0700449
Tao Baof52dbb82019-05-09 16:54:15 -0700450 signed_apex = apex_utils.SignApex(
Tao Baoe1343992019-03-19 12:24:03 -0700451 data,
452 payload_key,
453 container_key,
454 key_passwords[container_key],
455 codename_to_api_level_map,
456 OPTIONS.avb_extra_args.get('apex'))
457 common.ZipWrite(output_tf_zip, signed_apex, filename)
Tao Baoaa7e9932019-03-15 09:37:01 -0700458
Tao Baoe1343992019-03-19 12:24:03 -0700459 else:
460 print(
461 "NOT signing: %s\n"
462 " (skipped due to special cert string)" % (name,))
463 common.ZipWriteStr(output_tf_zip, out_info, data)
Tao Baoaa7e9932019-03-15 09:37:01 -0700464
465 # AVB public keys for the installed APEXes, which will be updated later.
466 elif (os.path.dirname(filename) == 'SYSTEM/etc/security/apex' and
467 filename != 'SYSTEM/etc/security/apex/'):
468 continue
469
Tao Baoa80ed222016-06-16 14:41:24 -0700470 # System properties.
Tao Bao11f955c2018-06-19 12:19:35 -0700471 elif filename in ("SYSTEM/build.prop",
472 "VENDOR/build.prop",
Magnus Strandh63967972019-05-01 23:09:30 +0200473 "SYSTEM/vendor/build.prop",
Bowgo Tsai33ff6022019-05-17 23:21:48 +0800474 "ODM/build.prop", # legacy
475 "ODM/etc/build.prop",
476 "VENDOR/odm/build.prop", # legacy
477 "VENDOR/odm/etc/build.prop",
Magnus Strandh63967972019-05-01 23:09:30 +0200478 "PRODUCT/build.prop",
479 "SYSTEM/product/build.prop",
480 "PRODUCT_SERVICES/build.prop",
481 "SYSTEM/product_services/build.prop",
Tao Bao11f955c2018-06-19 12:19:35 -0700482 "SYSTEM/etc/prop.default",
483 "BOOT/RAMDISK/prop.default",
484 "BOOT/RAMDISK/default.prop", # legacy
485 "ROOT/default.prop", # legacy
486 "RECOVERY/RAMDISK/prop.default",
487 "RECOVERY/RAMDISK/default.prop"): # legacy
488 print("Rewriting %s:" % (filename,))
Hung-ying Tyan7eb6a922017-05-01 21:56:26 +0800489 if stat.S_ISLNK(info.external_attr >> 16):
490 new_data = data
491 else:
Tao Baoa7054ee2017-12-08 14:42:16 -0800492 new_data = RewriteProps(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700493 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700494
Tao Bao66472632017-12-04 17:16:36 -0800495 # Replace the certs in *mac_permissions.xml (there could be multiple, such
496 # as {system,vendor}/etc/selinux/{plat,nonplat}_mac_permissions.xml).
Tao Bao11f955c2018-06-19 12:19:35 -0700497 elif filename.endswith("mac_permissions.xml"):
498 print("Rewriting %s with new keys." % (filename,))
Robert Craig817c5742013-04-19 10:59:22 -0400499 new_data = ReplaceCerts(data)
Tao Bao2ed665a2015-04-01 11:21:55 -0700500 common.ZipWriteStr(output_tf_zip, out_info, new_data)
Tao Baoa80ed222016-06-16 14:41:24 -0700501
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700502 # Ask add_img_to_target_files to rebuild the recovery patch if needed.
Tao Bao11f955c2018-06-19 12:19:35 -0700503 elif filename in ("SYSTEM/recovery-from-boot.p",
504 "SYSTEM/etc/recovery.img",
505 "SYSTEM/bin/install-recovery.sh"):
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700506 OPTIONS.rebuild_recovery = True
Tao Baoa80ed222016-06-16 14:41:24 -0700507
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700508 # Don't copy OTA certs if we're replacing them.
Tao Bao696bb332018-08-17 16:27:01 -0700509 elif (
510 OPTIONS.replace_ota_keys and
511 filename in (
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700512 "BOOT/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700513 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700514 "RECOVERY/RAMDISK/system/etc/security/otacerts.zip",
Tao Bao696bb332018-08-17 16:27:01 -0700515 "SYSTEM/etc/security/otacerts.zip",
516 "SYSTEM/etc/update_engine/update-payload-key.pub.pem")):
Doug Zongker412c02f2014-02-13 10:58:24 -0800517 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700518
Tao Bao46a59992017-06-05 11:55:16 -0700519 # Skip META/misc_info.txt since we will write back the new values later.
Tao Bao11f955c2018-06-19 12:19:35 -0700520 elif filename == "META/misc_info.txt":
Geremy Condraf19b3652014-07-29 17:54:54 -0700521 pass
Tao Bao8adcfd12016-06-17 17:01:22 -0700522
523 # Skip verity public key if we will replace it.
Michael Runge947894f2014-10-14 20:58:38 -0700524 elif (OPTIONS.replace_verity_public_key and
Tao Bao11f955c2018-06-19 12:19:35 -0700525 filename in ("BOOT/RAMDISK/verity_key",
526 "ROOT/verity_key")):
Geremy Condraf19b3652014-07-29 17:54:54 -0700527 pass
Tao Baoa80ed222016-06-16 14:41:24 -0700528
Tao Bao8adcfd12016-06-17 17:01:22 -0700529 # Skip verity keyid (for system_root_image use) if we will replace it.
Tao Bao11f955c2018-06-19 12:19:35 -0700530 elif OPTIONS.replace_verity_keyid and filename == "BOOT/cmdline":
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700531 pass
532
Tianjie Xu4f099002016-08-11 18:04:27 -0700533 # Skip the care_map as we will regenerate the system/vendor images.
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700534 elif filename == "META/care_map.pb" or filename == "META/care_map.txt":
Tianjie Xu4f099002016-08-11 18:04:27 -0700535 pass
536
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800537 # Updates system_other.avbpubkey in /product/etc/.
538 elif filename in (
539 "PRODUCT/etc/security/avb/system_other.avbpubkey",
540 "SYSTEM/product/etc/security/avb/system_other.avbpubkey"):
541 # Only update system_other's public key, if the corresponding signing
542 # key is specified via --avb_system_other_key.
543 signing_key = OPTIONS.avb_keys.get("system_other")
544 if signing_key:
545 public_key = common.ExtractAvbPublicKey(signing_key)
546 print(" Rewriting AVB public key of system_other in /product")
547 common.ZipWrite(output_tf_zip, public_key, filename)
548
Bowgo Tsai08aca592019-04-23 12:28:44 +0800549 # Should NOT sign boot-debug.img.
550 elif filename in (
551 "BOOT/RAMDISK/force_debuggable",
552 "RECOVERY/RAMDISK/force_debuggable"
553 "RECOVERY/RAMDISK/first_stage_ramdisk/force_debuggable"):
554 raise common.ExternalError("debuggable boot.img cannot be signed")
555
Tao Baoa80ed222016-06-16 14:41:24 -0700556 # A non-APK file; copy it verbatim.
Doug Zongkereef39442009-04-02 12:14:19 -0700557 else:
Tao Bao2ed665a2015-04-01 11:21:55 -0700558 common.ZipWriteStr(output_tf_zip, out_info, data)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700559
Doug Zongker412c02f2014-02-13 10:58:24 -0800560 if OPTIONS.replace_ota_keys:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700561 ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info)
Doug Zongker412c02f2014-02-13 10:58:24 -0800562
Tao Bao46a59992017-06-05 11:55:16 -0700563 # Replace the keyid string in misc_info dict.
Tao Bao8adcfd12016-06-17 17:01:22 -0700564 if OPTIONS.replace_verity_private_key:
Tao Bao46a59992017-06-05 11:55:16 -0700565 ReplaceVerityPrivateKey(misc_info, OPTIONS.replace_verity_private_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700566
567 if OPTIONS.replace_verity_public_key:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800568 dest = "ROOT/verity_key" if system_root_image else "BOOT/RAMDISK/verity_key"
Tao Bao8adcfd12016-06-17 17:01:22 -0700569 # We are replacing the one in boot image only, since the one under
570 # recovery won't ever be needed.
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700571 ReplaceVerityPublicKey(
Tao Bao8adcfd12016-06-17 17:01:22 -0700572 output_tf_zip, dest, OPTIONS.replace_verity_public_key[1])
Tao Bao8adcfd12016-06-17 17:01:22 -0700573
574 # Replace the keyid string in BOOT/cmdline.
575 if OPTIONS.replace_verity_keyid:
Tianjie Xu616fbeb2017-05-23 14:51:02 -0700576 ReplaceVerityKeyId(input_tf_zip, output_tf_zip,
577 OPTIONS.replace_verity_keyid[1])
Doug Zongker412c02f2014-02-13 10:58:24 -0800578
Tao Bao639118f2017-06-19 15:48:02 -0700579 # Replace the AVB signing keys, if any.
580 ReplaceAvbSigningKeys(misc_info)
581
Tao Bao46a59992017-06-05 11:55:16 -0700582 # Write back misc_info with the latest values.
583 ReplaceMiscInfoTxt(input_tf_zip, output_tf_zip, misc_info)
584
Doug Zongker8e931bf2009-04-06 15:21:45 -0700585
Robert Craig817c5742013-04-19 10:59:22 -0400586def ReplaceCerts(data):
Tao Bao66472632017-12-04 17:16:36 -0800587 """Replaces all the occurences of X.509 certs with the new ones.
Robert Craig817c5742013-04-19 10:59:22 -0400588
Tao Bao66472632017-12-04 17:16:36 -0800589 The mapping info is read from OPTIONS.key_map. Non-existent certificate will
590 be skipped. After the replacement, it additionally checks for duplicate
591 entries, which would otherwise fail the policy loading code in
592 frameworks/base/services/core/java/com/android/server/pm/SELinuxMMAC.java.
593
594 Args:
595 data: Input string that contains a set of X.509 certs.
596
597 Returns:
598 A string after the replacement.
599
600 Raises:
601 AssertionError: On finding duplicate entries.
602 """
603 for old, new in OPTIONS.key_map.iteritems():
604 if OPTIONS.verbose:
605 print(" Replacing %s.x509.pem with %s.x509.pem" % (old, new))
606
607 try:
608 with open(old + ".x509.pem") as old_fp:
609 old_cert16 = base64.b16encode(
610 common.ParseCertificate(old_fp.read())).lower()
611 with open(new + ".x509.pem") as new_fp:
612 new_cert16 = base64.b16encode(
613 common.ParseCertificate(new_fp.read())).lower()
614 except IOError as e:
615 if OPTIONS.verbose or e.errno != errno.ENOENT:
616 print(" Error accessing %s: %s.\nSkip replacing %s.x509.pem with "
617 "%s.x509.pem." % (e.filename, e.strerror, old, new))
618 continue
619
620 # Only match entire certs.
621 pattern = "\\b" + old_cert16 + "\\b"
622 (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE)
623
624 if OPTIONS.verbose:
625 print(" Replaced %d occurence(s) of %s.x509.pem with %s.x509.pem" % (
626 num, old, new))
627
628 # Verify that there're no duplicate entries after the replacement. Note that
629 # it's only checking entries with global seinfo at the moment (i.e. ignoring
630 # the ones with inner packages). (Bug: 69479366)
631 root = ElementTree.fromstring(data)
632 signatures = [signer.attrib['signature'] for signer in root.findall('signer')]
633 assert len(signatures) == len(set(signatures)), \
634 "Found duplicate entries after cert replacement: {}".format(data)
Robert Craig817c5742013-04-19 10:59:22 -0400635
636 return data
637
638
Doug Zongkerc09abc82010-01-11 13:09:15 -0800639def EditTags(tags):
Tao Baoa7054ee2017-12-08 14:42:16 -0800640 """Applies the edits to the tag string as specified in OPTIONS.tag_changes.
641
642 Args:
643 tags: The input string that contains comma-separated tags.
644
645 Returns:
646 The updated tags (comma-separated and sorted).
647 """
Doug Zongkerc09abc82010-01-11 13:09:15 -0800648 tags = set(tags.split(","))
649 for ch in OPTIONS.tag_changes:
650 if ch[0] == "-":
651 tags.discard(ch[1:])
652 elif ch[0] == "+":
653 tags.add(ch[1:])
654 return ",".join(sorted(tags))
655
656
Tao Baoa7054ee2017-12-08 14:42:16 -0800657def RewriteProps(data):
658 """Rewrites the system properties in the given string.
659
660 Each property is expected in 'key=value' format. The properties that contain
661 build tags (i.e. test-keys, dev-keys) will be updated accordingly by calling
662 EditTags().
663
664 Args:
665 data: Input string, separated by newlines.
666
667 Returns:
668 The string with modified properties.
669 """
Doug Zongker17aa9442009-04-17 10:15:58 -0700670 output = []
671 for line in data.split("\n"):
672 line = line.strip()
673 original_line = line
Michael Rungedc2661a2014-06-03 14:43:11 -0700674 if line and line[0] != '#' and "=" in line:
Doug Zongker17aa9442009-04-17 10:15:58 -0700675 key, value = line.split("=", 1)
Magnus Strandh63967972019-05-01 23:09:30 +0200676 if (key.startswith("ro.") and
677 key.endswith((".build.fingerprint", ".build.thumbprint"))):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800678 pieces = value.split("/")
679 pieces[-1] = EditTags(pieces[-1])
680 value = "/".join(pieces)
Tao Baocb7ff772015-09-11 15:27:56 -0700681 elif key == "ro.bootimage.build.fingerprint":
682 pieces = value.split("/")
683 pieces[-1] = EditTags(pieces[-1])
684 value = "/".join(pieces)
Doug Zongker17aa9442009-04-17 10:15:58 -0700685 elif key == "ro.build.description":
Doug Zongkerc09abc82010-01-11 13:09:15 -0800686 pieces = value.split(" ")
Doug Zongker17aa9442009-04-17 10:15:58 -0700687 assert len(pieces) == 5
Doug Zongkerc09abc82010-01-11 13:09:15 -0800688 pieces[-1] = EditTags(pieces[-1])
689 value = " ".join(pieces)
Magnus Strandh63967972019-05-01 23:09:30 +0200690 elif key.startswith("ro.") and key.endswith(".build.tags"):
Doug Zongkerc09abc82010-01-11 13:09:15 -0800691 value = EditTags(value)
Doug Zongkera8608a72013-07-23 11:51:04 -0700692 elif key == "ro.build.display.id":
693 # change, eg, "JWR66N dev-keys" to "JWR66N"
694 value = value.split()
Michael Rungedc2661a2014-06-03 14:43:11 -0700695 if len(value) > 1 and value[-1].endswith("-keys"):
Andrew Boie73d5abb2013-12-11 12:42:03 -0800696 value.pop()
697 value = " ".join(value)
Doug Zongkerc09abc82010-01-11 13:09:15 -0800698 line = key + "=" + value
Doug Zongker17aa9442009-04-17 10:15:58 -0700699 if line != original_line:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800700 print(" replace: ", original_line)
701 print(" with: ", line)
Doug Zongker17aa9442009-04-17 10:15:58 -0700702 output.append(line)
703 return "\n".join(output) + "\n"
704
705
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700706def WriteOtacerts(output_zip, filename, keys):
707 """Constructs a zipfile from given keys; and writes it to output_zip.
708
709 Args:
710 output_zip: The output target_files zip.
711 filename: The archive name in the output zip.
712 keys: A list of public keys to use during OTA package verification.
713 """
714
715 try:
716 from StringIO import StringIO
717 except ImportError:
718 from io import StringIO
719 temp_file = StringIO()
720 certs_zip = zipfile.ZipFile(temp_file, "w")
721 for k in keys:
722 common.ZipWrite(certs_zip, k)
723 common.ZipClose(certs_zip)
724 common.ZipWriteStr(output_zip, filename, temp_file.getvalue())
725
726
Doug Zongker831840e2011-09-22 10:28:04 -0700727def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info):
Doug Zongker8e931bf2009-04-06 15:21:45 -0700728 try:
729 keylist = input_tf_zip.read("META/otakeys.txt").split()
730 except KeyError:
T.R. Fullharta28acc62013-03-18 10:31:26 -0700731 raise common.ExternalError("can't read META/otakeys.txt from input")
Doug Zongker8e931bf2009-04-06 15:21:45 -0700732
Tao Baof718f902017-11-09 10:10:10 -0800733 extra_recovery_keys = misc_info.get("extra_recovery_keys")
Doug Zongkere121d6a2011-02-01 14:13:52 -0800734 if extra_recovery_keys:
735 extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem"
736 for k in extra_recovery_keys.split()]
737 if extra_recovery_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800738 print("extra recovery-only key(s): " + ", ".join(extra_recovery_keys))
Doug Zongkere121d6a2011-02-01 14:13:52 -0800739 else:
740 extra_recovery_keys = []
741
Doug Zongker8e931bf2009-04-06 15:21:45 -0700742 mapped_keys = []
743 for k in keylist:
744 m = re.match(r"^(.*)\.x509\.pem$", k)
745 if not m:
Doug Zongker412c02f2014-02-13 10:58:24 -0800746 raise common.ExternalError(
747 "can't parse \"%s\" from META/otakeys.txt" % (k,))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700748 k = m.group(1)
749 mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem")
750
Doug Zongkere05628c2009-08-20 17:38:42 -0700751 if mapped_keys:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800752 print("using:\n ", "\n ".join(mapped_keys))
753 print("for OTA package verification")
Doug Zongkere05628c2009-08-20 17:38:42 -0700754 else:
Doug Zongker831840e2011-09-22 10:28:04 -0700755 devkey = misc_info.get("default_system_dev_certificate",
756 "build/target/product/security/testkey")
Tao Baof718f902017-11-09 10:10:10 -0800757 mapped_devkey = OPTIONS.key_map.get(devkey, devkey)
758 if mapped_devkey != devkey:
759 misc_info["default_system_dev_certificate"] = mapped_devkey
760 mapped_keys.append(mapped_devkey + ".x509.pem")
Tao Baoa80ed222016-06-16 14:41:24 -0700761 print("META/otakeys.txt has no keys; using %s for OTA package"
762 " verification." % (mapped_keys[0],))
Doug Zongker8e931bf2009-04-06 15:21:45 -0700763
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700764 # recovery now uses the same x509.pem version of the keys.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800765 # extra_recovery_keys are used only in recovery.
Tom Cherry2929cad2018-09-20 11:04:37 -0700766 if misc_info.get("recovery_as_boot") == "true":
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700767 recovery_keys_location = "BOOT/RAMDISK/system/etc/security/otacerts.zip"
Tao Baoa80ed222016-06-16 14:41:24 -0700768 else:
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700769 recovery_keys_location = "RECOVERY/RAMDISK/system/etc/security/otacerts.zip"
770
771 WriteOtacerts(output_tf_zip, recovery_keys_location,
772 mapped_keys + extra_recovery_keys)
Doug Zongker8e931bf2009-04-06 15:21:45 -0700773
774 # SystemUpdateActivity uses the x509.pem version of the keys, but
775 # put into a zipfile system/etc/security/otacerts.zip.
Doug Zongkere121d6a2011-02-01 14:13:52 -0800776 # We DO NOT include the extra_recovery_keys (if any) here.
Tianjie Xuffbe6b92018-10-19 14:34:15 -0700777 WriteOtacerts(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", mapped_keys)
Doug Zongkereef39442009-04-02 12:14:19 -0700778
Tao Baoa80ed222016-06-16 14:41:24 -0700779 # For A/B devices, update the payload verification key.
780 if misc_info.get("ab_update") == "true":
781 # Unlike otacerts.zip that may contain multiple keys, we can only specify
782 # ONE payload verification key.
783 if len(mapped_keys) > 1:
784 print("\n WARNING: Found more than one OTA keys; Using the first one"
785 " as payload verification key.\n\n")
786
Tao Bao0c28d2d2017-12-24 10:37:38 -0800787 print("Using %s for payload verification." % (mapped_keys[0],))
Tao Bao04e1f012018-02-04 12:13:35 -0800788 pubkey = common.ExtractPublicKey(mapped_keys[0])
Tao Bao13b69622016-07-06 15:28:59 -0700789 common.ZipWriteStr(
Tao Baoa80ed222016-06-16 14:41:24 -0700790 output_tf_zip,
Tao Bao13b69622016-07-06 15:28:59 -0700791 "SYSTEM/etc/update_engine/update-payload-key.pub.pem",
792 pubkey)
Alex Deymob3e8ce62016-08-04 16:06:12 -0700793 common.ZipWriteStr(
794 output_tf_zip,
Tao Bao696bb332018-08-17 16:27:01 -0700795 "BOOT/RAMDISK/system/etc/update_engine/update-payload-key.pub.pem",
Alex Deymob3e8ce62016-08-04 16:06:12 -0700796 pubkey)
Tao Baoa80ed222016-06-16 14:41:24 -0700797
Tao Bao8adcfd12016-06-17 17:01:22 -0700798
Tao Bao0c28d2d2017-12-24 10:37:38 -0800799def ReplaceVerityPublicKey(output_zip, filename, key_path):
800 """Replaces the verity public key at the given path in the given zip.
801
802 Args:
803 output_zip: The output target_files zip.
804 filename: The archive name in the output zip.
805 key_path: The path to the public key.
806 """
807 print("Replacing verity public key with %s" % (key_path,))
808 common.ZipWrite(output_zip, key_path, arcname=filename)
Geremy Condraf19b3652014-07-29 17:54:54 -0700809
Tao Bao8adcfd12016-06-17 17:01:22 -0700810
Tao Bao46a59992017-06-05 11:55:16 -0700811def ReplaceVerityPrivateKey(misc_info, key_path):
Tao Bao0c28d2d2017-12-24 10:37:38 -0800812 """Replaces the verity private key in misc_info dict.
813
814 Args:
815 misc_info: The info dict.
816 key_path: The path to the private key in PKCS#8 format.
817 """
818 print("Replacing verity private key with %s" % (key_path,))
Andrew Boied083f0b2014-09-15 16:01:07 -0700819 misc_info["verity_key"] = key_path
Doug Zongkereef39442009-04-02 12:14:19 -0700820
Tao Bao8adcfd12016-06-17 17:01:22 -0700821
Tao Baoe838d142017-12-23 23:44:48 -0800822def ReplaceVerityKeyId(input_zip, output_zip, key_path):
823 """Replaces the veritykeyid parameter in BOOT/cmdline.
824
825 Args:
826 input_zip: The input target_files zip, which should be already open.
827 output_zip: The output target_files zip, which should be already open and
828 writable.
829 key_path: The path to the PEM encoded X.509 certificate.
830 """
831 in_cmdline = input_zip.read("BOOT/cmdline")
832 # Copy in_cmdline to output_zip if veritykeyid is not present.
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700833 if "veritykeyid" not in in_cmdline:
Tao Baoe838d142017-12-23 23:44:48 -0800834 common.ZipWriteStr(output_zip, "BOOT/cmdline", in_cmdline)
835 return
836
Tao Bao0c28d2d2017-12-24 10:37:38 -0800837 out_buffer = []
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700838 for param in in_cmdline.split():
Tao Baoe838d142017-12-23 23:44:48 -0800839 if "veritykeyid" not in param:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800840 out_buffer.append(param)
Tao Baoe838d142017-12-23 23:44:48 -0800841 continue
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700842
Tao Baoe838d142017-12-23 23:44:48 -0800843 # Extract keyid using openssl command.
844 p = common.Run(["openssl", "x509", "-in", key_path, "-text"],
Tao Baode1d4792018-02-20 10:05:46 -0800845 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Tao Baoe838d142017-12-23 23:44:48 -0800846 keyid, stderr = p.communicate()
847 assert p.returncode == 0, "Failed to dump certificate: {}".format(stderr)
848 keyid = re.search(
849 r'keyid:([0-9a-fA-F:]*)', keyid).group(1).replace(':', '').lower()
850 print("Replacing verity keyid with {}".format(keyid))
851 out_buffer.append("veritykeyid=id:%s" % (keyid,))
852
853 out_cmdline = ' '.join(out_buffer).strip() + '\n'
854 common.ZipWriteStr(output_zip, "BOOT/cmdline", out_cmdline)
Tao Bao46a59992017-06-05 11:55:16 -0700855
856
857def ReplaceMiscInfoTxt(input_zip, output_zip, misc_info):
858 """Replaces META/misc_info.txt.
859
860 Only writes back the ones in the original META/misc_info.txt. Because the
861 current in-memory dict contains additional items computed at runtime.
862 """
863 misc_info_old = common.LoadDictionaryFromLines(
864 input_zip.read('META/misc_info.txt').split('\n'))
865 items = []
866 for key in sorted(misc_info):
867 if key in misc_info_old:
868 items.append('%s=%s' % (key, misc_info[key]))
869 common.ZipWriteStr(output_zip, "META/misc_info.txt", '\n'.join(items))
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -0700870
Tao Bao8adcfd12016-06-17 17:01:22 -0700871
Tao Bao639118f2017-06-19 15:48:02 -0700872def ReplaceAvbSigningKeys(misc_info):
873 """Replaces the AVB signing keys."""
874
875 AVB_FOOTER_ARGS_BY_PARTITION = {
Tao Bao0c28d2d2017-12-24 10:37:38 -0800876 'boot' : 'avb_boot_add_hash_footer_args',
877 'dtbo' : 'avb_dtbo_add_hash_footer_args',
878 'recovery' : 'avb_recovery_add_hash_footer_args',
879 'system' : 'avb_system_add_hashtree_footer_args',
Bowgo Tsaie4544b12019-02-27 10:15:51 +0800880 'system_other' : 'avb_system_other_add_hashtree_footer_args',
Tao Bao0c28d2d2017-12-24 10:37:38 -0800881 'vendor' : 'avb_vendor_add_hashtree_footer_args',
882 'vbmeta' : 'avb_vbmeta_args',
Tao Baod403e7b2019-05-06 12:55:42 -0700883 'vbmeta_system' : 'avb_vbmeta_system_args',
884 'vbmeta_vendor' : 'avb_vbmeta_vendor_args',
Tao Bao639118f2017-06-19 15:48:02 -0700885 }
886
887 def ReplaceAvbPartitionSigningKey(partition):
888 key = OPTIONS.avb_keys.get(partition)
889 if not key:
890 return
891
892 algorithm = OPTIONS.avb_algorithms.get(partition)
893 assert algorithm, 'Missing AVB signing algorithm for %s' % (partition,)
894
Tao Bao0c28d2d2017-12-24 10:37:38 -0800895 print('Replacing AVB signing key for %s with "%s" (%s)' % (
896 partition, key, algorithm))
Tao Bao639118f2017-06-19 15:48:02 -0700897 misc_info['avb_' + partition + '_algorithm'] = algorithm
898 misc_info['avb_' + partition + '_key_path'] = key
899
900 extra_args = OPTIONS.avb_extra_args.get(partition)
901 if extra_args:
Tao Bao0c28d2d2017-12-24 10:37:38 -0800902 print('Setting extra AVB signing args for %s to "%s"' % (
903 partition, extra_args))
Tao Bao639118f2017-06-19 15:48:02 -0700904 args_key = AVB_FOOTER_ARGS_BY_PARTITION[partition]
905 misc_info[args_key] = (misc_info.get(args_key, '') + ' ' + extra_args)
906
907 for partition in AVB_FOOTER_ARGS_BY_PARTITION:
908 ReplaceAvbPartitionSigningKey(partition)
909
910
Doug Zongker831840e2011-09-22 10:28:04 -0700911def BuildKeyMap(misc_info, key_mapping_options):
912 for s, d in key_mapping_options:
913 if s is None: # -d option
914 devkey = misc_info.get("default_system_dev_certificate",
915 "build/target/product/security/testkey")
916 devkeydir = os.path.dirname(devkey)
917
918 OPTIONS.key_map.update({
919 devkeydir + "/testkey": d + "/releasekey",
920 devkeydir + "/devkey": d + "/releasekey",
921 devkeydir + "/media": d + "/media",
922 devkeydir + "/shared": d + "/shared",
923 devkeydir + "/platform": d + "/platform",
924 })
925 else:
926 OPTIONS.key_map[s] = d
927
928
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800929def GetApiLevelAndCodename(input_tf_zip):
930 data = input_tf_zip.read("SYSTEM/build.prop")
931 api_level = None
932 codename = None
933 for line in data.split("\n"):
934 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800935 if line and line[0] != '#' and "=" in line:
936 key, value = line.split("=", 1)
937 key = key.strip()
938 if key == "ro.build.version.sdk":
939 api_level = int(value.strip())
940 elif key == "ro.build.version.codename":
941 codename = value.strip()
942
943 if api_level is None:
944 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
945 if codename is None:
946 raise ValueError("No ro.build.version.codename in SYSTEM/build.prop")
947
948 return (api_level, codename)
949
950
951def GetCodenameToApiLevelMap(input_tf_zip):
952 data = input_tf_zip.read("SYSTEM/build.prop")
953 api_level = None
954 codenames = None
955 for line in data.split("\n"):
956 line = line.strip()
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800957 if line and line[0] != '#' and "=" in line:
958 key, value = line.split("=", 1)
959 key = key.strip()
960 if key == "ro.build.version.sdk":
961 api_level = int(value.strip())
962 elif key == "ro.build.version.all_codenames":
963 codenames = value.strip().split(",")
964
965 if api_level is None:
966 raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop")
967 if codenames is None:
968 raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop")
969
970 result = dict()
971 for codename in codenames:
972 codename = codename.strip()
Tao Baobadceb22019-03-15 09:33:43 -0700973 if codename:
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800974 result[codename] = api_level
Tao Bao9e401df2019-06-03 13:57:09 -0700975
976 # Work around APKs that still target 'Q' instead of API 29 (b/132882632).
977 result['Q'] = 29
978
Alex Klyubin2cfd1d12016-01-13 10:32:47 -0800979 return result
980
981
Tao Baoaa7e9932019-03-15 09:37:01 -0700982def ReadApexKeysInfo(tf_zip):
983 """Parses the APEX keys info from a given target-files zip.
984
985 Given a target-files ZipFile, parses the META/apexkeys.txt entry and returns a
986 dict that contains the mapping from APEX names (e.g. com.android.tzdata) to a
987 tuple of (payload_key, container_key).
988
989 Args:
990 tf_zip: The input target_files ZipFile (already open).
991
992 Returns:
993 (payload_key, container_key): payload_key contains the path to the payload
994 signing key; container_key contains the path to the container signing
995 key.
996 """
997 keys = {}
998 for line in tf_zip.read("META/apexkeys.txt").split("\n"):
999 line = line.strip()
1000 if not line:
1001 continue
1002 matches = re.match(
1003 r'^name="(?P<NAME>.*)"\s+'
1004 r'public_key="(?P<PAYLOAD_PUBLIC_KEY>.*)"\s+'
1005 r'private_key="(?P<PAYLOAD_PRIVATE_KEY>.*)"\s+'
1006 r'container_certificate="(?P<CONTAINER_CERT>.*)"\s+'
1007 r'container_private_key="(?P<CONTAINER_PRIVATE_KEY>.*)"$',
1008 line)
1009 if not matches:
1010 continue
1011
1012 name = matches.group('NAME')
Tao Baoaa7e9932019-03-15 09:37:01 -07001013 payload_private_key = matches.group("PAYLOAD_PRIVATE_KEY")
1014
1015 def CompareKeys(pubkey, pubkey_suffix, privkey, privkey_suffix):
1016 pubkey_suffix_len = len(pubkey_suffix)
1017 privkey_suffix_len = len(privkey_suffix)
1018 return (pubkey.endswith(pubkey_suffix) and
1019 privkey.endswith(privkey_suffix) and
1020 pubkey[:-pubkey_suffix_len] == privkey[:-privkey_suffix_len])
1021
Tao Bao6d9e3da2019-03-26 12:59:25 -07001022 # Sanity check on the container key names, as we'll carry them without the
1023 # extensions. This doesn't apply to payload keys though, which we will use
1024 # full names only.
Tao Baoaa7e9932019-03-15 09:37:01 -07001025 container_cert = matches.group("CONTAINER_CERT")
1026 container_private_key = matches.group("CONTAINER_PRIVATE_KEY")
Tao Bao548db7d2019-04-24 23:53:42 -07001027 if container_cert == 'PRESIGNED' and container_private_key == 'PRESIGNED':
1028 container_key = 'PRESIGNED'
1029 elif CompareKeys(
Tao Baoaa7e9932019-03-15 09:37:01 -07001030 container_cert, OPTIONS.public_key_suffix,
1031 container_private_key, OPTIONS.private_key_suffix):
Tao Bao548db7d2019-04-24 23:53:42 -07001032 container_key = container_cert[:-len(OPTIONS.public_key_suffix)]
1033 else:
Tao Baoaa7e9932019-03-15 09:37:01 -07001034 raise ValueError("Failed to parse container keys: \n{}".format(line))
1035
Tao Bao548db7d2019-04-24 23:53:42 -07001036 keys[name] = (payload_private_key, container_key)
Tao Baoaa7e9932019-03-15 09:37:01 -07001037
1038 return keys
1039
1040
Doug Zongkereef39442009-04-02 12:14:19 -07001041def main(argv):
1042
Doug Zongker831840e2011-09-22 10:28:04 -07001043 key_mapping_options = []
1044
Doug Zongkereef39442009-04-02 12:14:19 -07001045 def option_handler(o, a):
Doug Zongker05d3dea2009-06-22 11:32:31 -07001046 if o in ("-e", "--extra_apks"):
Doug Zongkereef39442009-04-02 12:14:19 -07001047 names, key = a.split("=")
1048 names = names.split(",")
1049 for n in names:
1050 OPTIONS.extra_apks[n] = key
Tao Baoaa7e9932019-03-15 09:37:01 -07001051 elif o == "--extra_apex_payload_key":
1052 apex_name, key = a.split("=")
1053 OPTIONS.extra_apex_payload_keys[apex_name] = key
Tao Bao93c2a012018-06-19 12:19:35 -07001054 elif o == "--skip_apks_with_path_prefix":
1055 # Sanity check the prefix, which must be in all upper case.
1056 prefix = a.split('/')[0]
1057 if not prefix or prefix != prefix.upper():
1058 raise ValueError("Invalid path prefix '%s'" % (a,))
1059 OPTIONS.skip_apks_with_path_prefix.add(a)
Doug Zongkereef39442009-04-02 12:14:19 -07001060 elif o in ("-d", "--default_key_mappings"):
Doug Zongker831840e2011-09-22 10:28:04 -07001061 key_mapping_options.append((None, a))
Doug Zongkereef39442009-04-02 12:14:19 -07001062 elif o in ("-k", "--key_mapping"):
Doug Zongker831840e2011-09-22 10:28:04 -07001063 key_mapping_options.append(a.split("=", 1))
Doug Zongker8e931bf2009-04-06 15:21:45 -07001064 elif o in ("-o", "--replace_ota_keys"):
1065 OPTIONS.replace_ota_keys = True
Doug Zongkerae877012009-04-21 10:04:51 -07001066 elif o in ("-t", "--tag_changes"):
1067 new = []
1068 for i in a.split(","):
1069 i = i.strip()
1070 if not i or i[0] not in "-+":
1071 raise ValueError("Bad tag change '%s'" % (i,))
1072 new.append(i[0] + i[1:].strip())
1073 OPTIONS.tag_changes = tuple(new)
Geremy Condraf19b3652014-07-29 17:54:54 -07001074 elif o == "--replace_verity_public_key":
1075 OPTIONS.replace_verity_public_key = (True, a)
1076 elif o == "--replace_verity_private_key":
1077 OPTIONS.replace_verity_private_key = (True, a)
Badhri Jagan Sridharan35c9b122016-06-16 19:58:44 -07001078 elif o == "--replace_verity_keyid":
1079 OPTIONS.replace_verity_keyid = (True, a)
Tao Bao639118f2017-06-19 15:48:02 -07001080 elif o == "--avb_vbmeta_key":
1081 OPTIONS.avb_keys['vbmeta'] = a
1082 elif o == "--avb_vbmeta_algorithm":
1083 OPTIONS.avb_algorithms['vbmeta'] = a
1084 elif o == "--avb_vbmeta_extra_args":
1085 OPTIONS.avb_extra_args['vbmeta'] = a
1086 elif o == "--avb_boot_key":
1087 OPTIONS.avb_keys['boot'] = a
1088 elif o == "--avb_boot_algorithm":
1089 OPTIONS.avb_algorithms['boot'] = a
1090 elif o == "--avb_boot_extra_args":
1091 OPTIONS.avb_extra_args['boot'] = a
1092 elif o == "--avb_dtbo_key":
1093 OPTIONS.avb_keys['dtbo'] = a
1094 elif o == "--avb_dtbo_algorithm":
1095 OPTIONS.avb_algorithms['dtbo'] = a
1096 elif o == "--avb_dtbo_extra_args":
1097 OPTIONS.avb_extra_args['dtbo'] = a
1098 elif o == "--avb_system_key":
1099 OPTIONS.avb_keys['system'] = a
1100 elif o == "--avb_system_algorithm":
1101 OPTIONS.avb_algorithms['system'] = a
1102 elif o == "--avb_system_extra_args":
1103 OPTIONS.avb_extra_args['system'] = a
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001104 elif o == "--avb_system_other_key":
1105 OPTIONS.avb_keys['system_other'] = a
1106 elif o == "--avb_system_other_algorithm":
1107 OPTIONS.avb_algorithms['system_other'] = a
1108 elif o == "--avb_system_other_extra_args":
1109 OPTIONS.avb_extra_args['system_other'] = a
Tao Bao639118f2017-06-19 15:48:02 -07001110 elif o == "--avb_vendor_key":
1111 OPTIONS.avb_keys['vendor'] = a
1112 elif o == "--avb_vendor_algorithm":
1113 OPTIONS.avb_algorithms['vendor'] = a
1114 elif o == "--avb_vendor_extra_args":
1115 OPTIONS.avb_extra_args['vendor'] = a
Tao Baod403e7b2019-05-06 12:55:42 -07001116 elif o == "--avb_vbmeta_system_key":
1117 OPTIONS.avb_keys['vbmeta_system'] = a
1118 elif o == "--avb_vbmeta_system_algorithm":
1119 OPTIONS.avb_algorithms['vbmeta_system'] = a
1120 elif o == "--avb_vbmeta_system_extra_args":
1121 OPTIONS.avb_extra_args['vbmeta_system'] = a
1122 elif o == "--avb_vbmeta_vendor_key":
1123 OPTIONS.avb_keys['vbmeta_vendor'] = a
1124 elif o == "--avb_vbmeta_vendor_algorithm":
1125 OPTIONS.avb_algorithms['vbmeta_vendor'] = a
1126 elif o == "--avb_vbmeta_vendor_extra_args":
1127 OPTIONS.avb_extra_args['vbmeta_vendor'] = a
Tao Baoaa7e9932019-03-15 09:37:01 -07001128 elif o == "--avb_apex_extra_args":
1129 OPTIONS.avb_extra_args['apex'] = a
Doug Zongkereef39442009-04-02 12:14:19 -07001130 else:
1131 return False
1132 return True
1133
Tao Bao639118f2017-06-19 15:48:02 -07001134 args = common.ParseOptions(
1135 argv, __doc__,
1136 extra_opts="e:d:k:ot:",
1137 extra_long_opts=[
Tao Bao0c28d2d2017-12-24 10:37:38 -08001138 "extra_apks=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001139 "extra_apex_payload_key=",
Tao Bao93c2a012018-06-19 12:19:35 -07001140 "skip_apks_with_path_prefix=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001141 "default_key_mappings=",
1142 "key_mapping=",
1143 "replace_ota_keys",
1144 "tag_changes=",
1145 "replace_verity_public_key=",
1146 "replace_verity_private_key=",
1147 "replace_verity_keyid=",
Tao Baoaa7e9932019-03-15 09:37:01 -07001148 "avb_apex_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001149 "avb_vbmeta_algorithm=",
1150 "avb_vbmeta_key=",
1151 "avb_vbmeta_extra_args=",
1152 "avb_boot_algorithm=",
1153 "avb_boot_key=",
1154 "avb_boot_extra_args=",
1155 "avb_dtbo_algorithm=",
1156 "avb_dtbo_key=",
1157 "avb_dtbo_extra_args=",
1158 "avb_system_algorithm=",
1159 "avb_system_key=",
1160 "avb_system_extra_args=",
Bowgo Tsaie4544b12019-02-27 10:15:51 +08001161 "avb_system_other_algorithm=",
1162 "avb_system_other_key=",
1163 "avb_system_other_extra_args=",
Tao Bao0c28d2d2017-12-24 10:37:38 -08001164 "avb_vendor_algorithm=",
1165 "avb_vendor_key=",
1166 "avb_vendor_extra_args=",
Tao Baod403e7b2019-05-06 12:55:42 -07001167 "avb_vbmeta_system_algorithm=",
1168 "avb_vbmeta_system_key=",
1169 "avb_vbmeta_system_extra_args=",
1170 "avb_vbmeta_vendor_algorithm=",
1171 "avb_vbmeta_vendor_key=",
1172 "avb_vbmeta_vendor_extra_args=",
Tao Bao639118f2017-06-19 15:48:02 -07001173 ],
1174 extra_option_handler=option_handler)
Doug Zongkereef39442009-04-02 12:14:19 -07001175
1176 if len(args) != 2:
1177 common.Usage(__doc__)
1178 sys.exit(1)
1179
Tao Baobadceb22019-03-15 09:33:43 -07001180 common.InitLogging()
1181
Doug Zongkereef39442009-04-02 12:14:19 -07001182 input_zip = zipfile.ZipFile(args[0], "r")
Tao Bao2b8f4892017-06-13 12:54:58 -07001183 output_zip = zipfile.ZipFile(args[1], "w",
1184 compression=zipfile.ZIP_DEFLATED,
1185 allowZip64=True)
Doug Zongkereef39442009-04-02 12:14:19 -07001186
Doug Zongker831840e2011-09-22 10:28:04 -07001187 misc_info = common.LoadInfoDict(input_zip)
1188
1189 BuildKeyMap(misc_info, key_mapping_options)
1190
Tao Baoaa7e9932019-03-15 09:37:01 -07001191 apk_keys_info, compressed_extension = common.ReadApkCerts(input_zip)
1192 apk_keys = GetApkCerts(apk_keys_info)
Doug Zongkereb338ef2009-05-20 16:50:49 -07001193
Tao Baoaa7e9932019-03-15 09:37:01 -07001194 apex_keys_info = ReadApexKeysInfo(input_zip)
1195 apex_keys = GetApexKeys(apex_keys_info, apk_keys)
1196
1197 CheckApkAndApexKeysAvailable(
1198 input_zip,
1199 set(apk_keys.keys()) | set(apex_keys.keys()),
Tao Baoe1343992019-03-19 12:24:03 -07001200 compressed_extension,
1201 apex_keys)
Tao Baoaa7e9932019-03-15 09:37:01 -07001202
1203 key_passwords = common.GetKeyPasswords(
1204 set(apk_keys.values()) | set(itertools.chain(*apex_keys.values())))
Tao Bao9aa4b9b2016-09-29 17:53:56 -07001205 platform_api_level, _ = GetApiLevelAndCodename(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001206 codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip)
Alex Klyubin2cfd1d12016-01-13 10:32:47 -08001207
Doug Zongker412c02f2014-02-13 10:58:24 -08001208 ProcessTargetFiles(input_zip, output_zip, misc_info,
Tao Baoaa7e9932019-03-15 09:37:01 -07001209 apk_keys, apex_keys, key_passwords,
1210 platform_api_level, codename_to_api_level_map,
Narayan Kamatha07bf042017-08-14 14:49:21 +01001211 compressed_extension)
Doug Zongker8e931bf2009-04-06 15:21:45 -07001212
Tao Bao2ed665a2015-04-01 11:21:55 -07001213 common.ZipClose(input_zip)
1214 common.ZipClose(output_zip)
Doug Zongkereef39442009-04-02 12:14:19 -07001215
Tianjie Xub48589a2016-08-03 19:21:52 -07001216 # Skip building userdata.img and cache.img when signing the target files.
Tianjie Xu616fbeb2017-05-23 14:51:02 -07001217 new_args = ["--is_signing"]
1218 # add_img_to_target_files builds the system image from scratch, so the
1219 # recovery patch is guaranteed to be regenerated there.
1220 if OPTIONS.rebuild_recovery:
1221 new_args.append("--rebuild_recovery")
1222 new_args.append(args[1])
Tianjie Xub48589a2016-08-03 19:21:52 -07001223 add_img_to_target_files.main(new_args)
Doug Zongker3c84f562014-07-31 11:06:30 -07001224
Tao Bao0c28d2d2017-12-24 10:37:38 -08001225 print("done.")
Doug Zongkereef39442009-04-02 12:14:19 -07001226
1227
1228if __name__ == '__main__':
1229 try:
1230 main(sys.argv[1:])
Tao Bao0c28d2d2017-12-24 10:37:38 -08001231 except common.ExternalError as e:
1232 print("\n ERROR: %s\n" % (e,))
Doug Zongkereef39442009-04-02 12:14:19 -07001233 sys.exit(1)
Tao Bao639118f2017-06-19 15:48:02 -07001234 finally:
1235 common.Cleanup()