blob: b3961886724bc0dc3e4a6b6a62b540bc6ccebdb2 [file] [log] [blame]
Doug Zongker3c84f562014-07-31 11:06:30 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2014 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"""
18Given a target-files zipfile that does not contain images (ie, does
19not have an IMAGES/ top-level subdirectory), produce the images and
20add them to the zipfile.
21
Tianjie Xub48589a2016-08-03 19:21:52 -070022Usage: add_img_to_target_files [flag] target_files
23
24 -a (--add_missing)
25 Build and add missing images to "IMAGES/". If this option is
26 not specified, this script will simply exit when "IMAGES/"
27 directory exists in the target file.
28
29 -r (--rebuild_recovery)
30 Rebuild the recovery patch and write it to the system image. Only
Tao Bao4978fa92019-06-04 16:26:45 -070031 meaningful when system image needs to be rebuilt and there're separate
32 boot / recovery images.
Tianjie Xub48589a2016-08-03 19:21:52 -070033
34 --replace_verity_private_key
35 Replace the private key used for verity signing. (same as the option
36 in sign_target_files_apks)
37
38 --replace_verity_public_key
39 Replace the certificate (public key) used for verity verification. (same
40 as the option in sign_target_files_apks)
41
42 --is_signing
43 Skip building & adding the images for "userdata" and "cache" if we
44 are signing the target files.
Doug Zongker3c84f562014-07-31 11:06:30 -070045"""
46
Tao Bao89fbb0f2017-01-10 10:47:58 -080047from __future__ import print_function
48
Tao Bao822f5842015-09-30 16:01:14 -070049import datetime
Tao Bao32fcdab2018-10-12 10:30:39 -070050import logging
Doug Zongker3c84f562014-07-31 11:06:30 -070051import os
David Zeuthend995f4b2016-01-29 16:59:17 -050052import shlex
Ying Wang2a048392015-06-25 13:56:53 -070053import shutil
Rupert Shuttleworth72942742020-12-08 06:18:35 +000054import stat
Tao Bao6b9fef52017-12-01 16:13:22 -080055import sys
Tao Baod86e3112017-09-22 15:45:33 -070056import uuid
Kelvin Zhang834f5d42022-01-21 12:44:44 -080057import tempfile
Doug Zongker3c84f562014-07-31 11:06:30 -070058import zipfile
59
Doug Zongker3c84f562014-07-31 11:06:30 -070060import build_image
Yifan Hong055e6cf2018-11-29 13:51:48 -080061import build_super_image
Doug Zongker3c84f562014-07-31 11:06:30 -070062import common
Hongguang Chenf23364d2020-04-27 18:36:36 -070063import verity_utils
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -050064import ota_metadata_pb2
65
Daniel Normane9af70a2021-04-15 16:39:22 -070066from apex_utils import GetApexInfoFromTargetFiles
Kelvin Zhang70876142022-02-09 16:05:29 -080067from common import AddCareMapForAbOta, ZipDelete
Doug Zongker3c84f562014-07-31 11:06:30 -070068
Tao Bao6b9fef52017-12-01 16:13:22 -080069if sys.hexversion < 0x02070000:
70 print("Python 2.7 or newer is required.", file=sys.stderr)
71 sys.exit(1)
72
Tao Bao32fcdab2018-10-12 10:30:39 -070073logger = logging.getLogger(__name__)
Doug Zongker3c84f562014-07-31 11:06:30 -070074
Tao Bao32fcdab2018-10-12 10:30:39 -070075OPTIONS = common.OPTIONS
Michael Runge2e0d8fc2014-11-13 21:41:08 -080076OPTIONS.add_missing = False
77OPTIONS.rebuild_recovery = False
Tianjie Xu9ac4cb02017-06-09 16:58:03 -070078OPTIONS.replace_updated_files_list = []
Baligh Uddin59f4ff12015-09-16 21:20:30 -070079OPTIONS.replace_verity_public_key = False
80OPTIONS.replace_verity_private_key = False
Tianjie Xub48589a2016-08-03 19:21:52 -070081OPTIONS.is_signing = False
Doug Zongker3c84f562014-07-31 11:06:30 -070082
Bryan Henrye6d547d2018-07-31 18:32:00 -070083# Use a fixed timestamp (01/01/2009 00:00:00 UTC) for files when packaging
84# images. (b/24377993, b/80600931)
Tao Baoe30a6a62018-08-27 10:57:19 -070085FIXED_FILE_TIMESTAMP = int((
86 datetime.datetime(2009, 1, 1, 0, 0, 0, 0, None) -
87 datetime.datetime.utcfromtimestamp(0)).total_seconds())
Tao Baoa2ff4c92018-01-17 12:14:43 -080088
Bowgo Tsaid624fa62017-11-14 23:42:30 +080089
Dan Willemsen2ee00d52017-03-05 19:51:56 -080090class OutputFile(object):
Tao Bao93e7ebe2019-01-13 23:23:01 -080091 """A helper class to write a generated file to the given dir or zip.
Dan Willemsen2ee00d52017-03-05 19:51:56 -080092
Tao Bao93e7ebe2019-01-13 23:23:01 -080093 When generating images, we want the outputs to go into the given zip file, or
94 the given dir.
95
96 Attributes:
97 name: The name of the output file, regardless of the final destination.
98 """
99
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500100 def __init__(self, output_zip, input_dir, *args):
Tao Bao93e7ebe2019-01-13 23:23:01 -0800101 # We write the intermediate output file under the given input_dir, even if
102 # the final destination is a zip archive.
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500103 self.name = os.path.join(input_dir, *args)
Tao Bao93e7ebe2019-01-13 23:23:01 -0800104 self._output_zip = output_zip
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800105 if self._output_zip:
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500106 self._zip_name = os.path.join(*args)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800107
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800108 def Write(self, compress_type=None):
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800109 if self._output_zip:
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800110 common.ZipWrite(self._output_zip, self.name,
111 self._zip_name, compress_type=compress_type)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800112
Tao Baoe30a6a62018-08-27 10:57:19 -0700113
Tao Bao886d8832018-02-27 11:46:19 -0800114def AddSystem(output_zip, recovery_img=None, boot_img=None):
Doug Zongker3c84f562014-07-31 11:06:30 -0700115 """Turn the contents of SYSTEM into a system image and store it in
David Zeuthend995f4b2016-01-29 16:59:17 -0500116 output_zip. Returns the name of the system image file."""
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800117
Tao Bao886d8832018-02-27 11:46:19 -0800118 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800119 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700120 logger.info("system.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800121 return img.name
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800122
123 def output_sink(fn, data):
Tao Baoa3705452019-06-24 15:33:41 -0700124 output_file = os.path.join(OPTIONS.input_tmp, "SYSTEM", fn)
125 with open(output_file, "wb") as ofile:
126 ofile.write(data)
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800127
Daniel Normana4911da2019-03-15 14:36:21 -0700128 if output_zip:
129 arc_name = "SYSTEM/" + fn
130 if arc_name in output_zip.namelist():
131 OPTIONS.replace_updated_files_list.append(arc_name)
132 else:
Tao Baoa3705452019-06-24 15:33:41 -0700133 common.ZipWrite(output_zip, output_file, arc_name)
Tianjie Xu38af07f2017-05-25 17:38:53 -0700134
Bill Peckhame868aec2019-09-17 17:06:47 -0700135 board_uses_vendorimage = OPTIONS.info_dict.get(
136 "board_uses_vendorimage") == "true"
137
138 if (OPTIONS.rebuild_recovery and not board_uses_vendorimage and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800139 recovery_img is not None and boot_img is not None):
Bill Peckhame868aec2019-09-17 17:06:47 -0700140 logger.info("Building new recovery patch on system at system/vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700141 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
142 boot_img, info_dict=OPTIONS.info_dict)
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800143
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800144 block_list = OutputFile(output_zip, OPTIONS.input_tmp,
145 "IMAGES", "system.map")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800146 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system", img,
147 block_list=block_list)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800148 return img.name
Doug Zongkerfc44a512014-08-26 13:10:25 -0700149
150
Tao Bao886d8832018-02-27 11:46:19 -0800151def AddSystemOther(output_zip):
Alex Light4e358ab2016-06-16 14:47:10 -0700152 """Turn the contents of SYSTEM_OTHER into a system_other image
153 and store it in output_zip."""
154
Tao Bao886d8832018-02-27 11:46:19 -0800155 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system_other.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800156 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700157 logger.info("system_other.img already exists; no need to rebuild...")
Alex Light4e358ab2016-06-16 14:47:10 -0700158 return
159
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800160 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system_other", img)
Alex Light4e358ab2016-06-16 14:47:10 -0700161
162
Bill Peckhame868aec2019-09-17 17:06:47 -0700163def AddVendor(output_zip, recovery_img=None, boot_img=None):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700164 """Turn the contents of VENDOR into a vendor image and store in it
165 output_zip."""
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800166
Tao Bao886d8832018-02-27 11:46:19 -0800167 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800168 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700169 logger.info("vendor.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800170 return img.name
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800171
Bill Peckhame868aec2019-09-17 17:06:47 -0700172 def output_sink(fn, data):
Iavor-Valentin Iftime756b5612022-02-09 15:56:14 +0000173 output_file = os.path.join(OPTIONS.input_tmp, "VENDOR", fn)
174 with open(output_file, "wb") as ofile:
175 ofile.write(data)
Bill Peckhame868aec2019-09-17 17:06:47 -0700176
177 if output_zip:
178 arc_name = "VENDOR/" + fn
179 if arc_name in output_zip.namelist():
180 OPTIONS.replace_updated_files_list.append(arc_name)
181 else:
Iavor-Valentin Iftime756b5612022-02-09 15:56:14 +0000182 common.ZipWrite(output_zip, output_file, arc_name)
Bill Peckhame868aec2019-09-17 17:06:47 -0700183
184 board_uses_vendorimage = OPTIONS.info_dict.get(
185 "board_uses_vendorimage") == "true"
186
187 if (OPTIONS.rebuild_recovery and board_uses_vendorimage and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800188 recovery_img is not None and boot_img is not None):
Bill Peckhame868aec2019-09-17 17:06:47 -0700189 logger.info("Building new recovery patch on vendor")
190 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
191 boot_img, info_dict=OPTIONS.info_dict)
192
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800193 block_list = OutputFile(output_zip, OPTIONS.input_tmp,
194 "IMAGES", "vendor.map")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800195 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "vendor", img,
196 block_list=block_list)
197 return img.name
Doug Zongker3c84f562014-07-31 11:06:30 -0700198
Yueyao Zhu889ee5e2017-05-12 17:50:46 -0700199
Tao Bao886d8832018-02-27 11:46:19 -0800200def AddProduct(output_zip):
201 """Turn the contents of PRODUCT into a product image and store it in
202 output_zip."""
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900203
Tao Bao886d8832018-02-27 11:46:19 -0800204 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "product.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800205 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700206 logger.info("product.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800207 return img.name
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900208
Tao Bao886d8832018-02-27 11:46:19 -0800209 block_list = OutputFile(
210 output_zip, OPTIONS.input_tmp, "IMAGES", "product.map")
211 CreateImage(
212 OPTIONS.input_tmp, OPTIONS.info_dict, "product", img,
213 block_list=block_list)
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900214 return img.name
215
216
Justin Yun6151e3f2019-06-25 15:58:13 +0900217def AddSystemExt(output_zip):
218 """Turn the contents of SYSTEM_EXT into a system_ext image and store it in
219 output_zip."""
Dario Freni5f681e12018-05-29 13:09:01 +0100220
221 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
Justin Yun6151e3f2019-06-25 15:58:13 +0900222 "system_ext.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800223 if os.path.exists(img.name):
Justin Yun6151e3f2019-06-25 15:58:13 +0900224 logger.info("system_ext.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800225 return img.name
Dario Freni5f681e12018-05-29 13:09:01 +0100226
227 block_list = OutputFile(
Justin Yun6151e3f2019-06-25 15:58:13 +0900228 output_zip, OPTIONS.input_tmp, "IMAGES", "system_ext.map")
Dario Freni5f681e12018-05-29 13:09:01 +0100229 CreateImage(
Justin Yun6151e3f2019-06-25 15:58:13 +0900230 OPTIONS.input_tmp, OPTIONS.info_dict, "system_ext", img,
Dario Freni5f681e12018-05-29 13:09:01 +0100231 block_list=block_list)
232 return img.name
233
234
Bowgo Tsaid624fa62017-11-14 23:42:30 +0800235def AddOdm(output_zip):
236 """Turn the contents of ODM into an odm image and store it in output_zip."""
237
238 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "odm.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800239 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700240 logger.info("odm.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800241 return img.name
Bowgo Tsaid624fa62017-11-14 23:42:30 +0800242
243 block_list = OutputFile(
244 output_zip, OPTIONS.input_tmp, "IMAGES", "odm.map")
245 CreateImage(
246 OPTIONS.input_tmp, OPTIONS.info_dict, "odm", img,
247 block_list=block_list)
248 return img.name
249
250
Yifan Hongcfb917a2020-05-07 14:58:20 -0700251def AddVendorDlkm(output_zip):
252 """Turn the contents of VENDOR_DLKM into an vendor_dlkm image and store it in output_zip."""
253
254 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.img")
255 if os.path.exists(img.name):
256 logger.info("vendor_dlkm.img already exists; no need to rebuild...")
257 return img.name
258
259 block_list = OutputFile(
260 output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.map")
261 CreateImage(
262 OPTIONS.input_tmp, OPTIONS.info_dict, "vendor_dlkm", img,
263 block_list=block_list)
264 return img.name
265
Tianjiebbde59f2021-05-03 21:18:56 -0700266
Yifan Hongf496f1b2020-07-15 16:52:59 -0700267def AddOdmDlkm(output_zip):
268 """Turn the contents of OdmDlkm into an odm_dlkm image and store it in output_zip."""
269
270 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.img")
271 if os.path.exists(img.name):
272 logger.info("odm_dlkm.img already exists; no need to rebuild...")
273 return img.name
274
275 block_list = OutputFile(
276 output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.map")
277 CreateImage(
278 OPTIONS.input_tmp, OPTIONS.info_dict, "odm_dlkm", img,
279 block_list=block_list)
280 return img.name
281
Ramji Jiyani13a41372022-01-27 07:05:08 +0000282def AddSystemDlkm(output_zip):
283 """Turn the contents of SystemDlkm into an system_dlkm image and store it in output_zip."""
284
285 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system_dlkm.img")
286 if os.path.exists(img.name):
287 logger.info("system_dlkm.img already exists; no need to rebuild...")
288 return img.name
289
290 block_list = OutputFile(
291 output_zip, OPTIONS.input_tmp, "IMAGES", "system_dlkm.map")
292 CreateImage(
293 OPTIONS.input_tmp, OPTIONS.info_dict, "system_dlkm", img,
294 block_list=block_list)
295 return img.name
296
Yifan Hongcfb917a2020-05-07 14:58:20 -0700297
Tao Bao886d8832018-02-27 11:46:19 -0800298def AddDtbo(output_zip):
Tao Baoc633ed02017-05-30 21:46:33 -0700299 """Adds the DTBO image.
300
Tao Bao886d8832018-02-27 11:46:19 -0800301 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
Tao Baoc633ed02017-05-30 21:46:33 -0700302 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
303 """
Tao Bao886d8832018-02-27 11:46:19 -0800304 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "dtbo.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800305 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700306 logger.info("dtbo.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800307 return img.name
Tao Baoc633ed02017-05-30 21:46:33 -0700308
309 dtbo_prebuilt_path = os.path.join(
310 OPTIONS.input_tmp, "PREBUILT_IMAGES", "dtbo.img")
311 assert os.path.exists(dtbo_prebuilt_path)
312 shutil.copy(dtbo_prebuilt_path, img.name)
313
314 # AVB-sign the image as needed.
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800315 if OPTIONS.info_dict.get("avb_enable") == "true":
Rupert Shuttleworth72942742020-12-08 06:18:35 +0000316 # Signing requires +w
317 os.chmod(img.name, os.stat(img.name).st_mode | stat.S_IWUSR)
318
Tao Baof88e0ce2019-03-18 14:01:38 -0700319 avbtool = OPTIONS.info_dict["avb_avbtool"]
Tao Bao3ebfdde2017-05-23 23:06:55 -0700320 part_size = OPTIONS.info_dict["dtbo_size"]
Tao Baoc633ed02017-05-30 21:46:33 -0700321 # The AVB hash footer will be replaced if already present.
322 cmd = [avbtool, "add_hash_footer", "--image", img.name,
323 "--partition_size", str(part_size), "--partition_name", "dtbo"]
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800324 common.AppendAVBSigningArgs(cmd, "dtbo")
325 args = OPTIONS.info_dict.get("avb_dtbo_add_hash_footer_args")
Tao Baoc633ed02017-05-30 21:46:33 -0700326 if args and args.strip():
327 cmd.extend(shlex.split(args))
Tao Bao2764aee2018-11-21 11:02:48 -0800328 common.RunAndCheckOutput(cmd)
Tao Baoc633ed02017-05-30 21:46:33 -0700329
330 img.Write()
331 return img.name
332
Tianjiebbde59f2021-05-03 21:18:56 -0700333
Andrew Sculle077cf72021-02-18 10:27:29 +0000334def AddPvmfw(output_zip):
335 """Adds the pvmfw image.
336
337 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
338 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
339 """
340 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "pvmfw.img")
341 if os.path.exists(img.name):
342 logger.info("pvmfw.img already exists; no need to rebuild...")
343 return img.name
344
345 pvmfw_prebuilt_path = os.path.join(
346 OPTIONS.input_tmp, "PREBUILT_IMAGES", "pvmfw.img")
347 assert os.path.exists(pvmfw_prebuilt_path)
348 shutil.copy(pvmfw_prebuilt_path, img.name)
349
350 # AVB-sign the image as needed.
351 if OPTIONS.info_dict.get("avb_enable") == "true":
352 # Signing requires +w
353 os.chmod(img.name, os.stat(img.name).st_mode | stat.S_IWUSR)
354
355 avbtool = OPTIONS.info_dict["avb_avbtool"]
356 part_size = OPTIONS.info_dict["pvmfw_size"]
357 # The AVB hash footer will be replaced if already present.
358 cmd = [avbtool, "add_hash_footer", "--image", img.name,
359 "--partition_size", str(part_size), "--partition_name", "pvmfw"]
360 common.AppendAVBSigningArgs(cmd, "pvmfw")
361 args = OPTIONS.info_dict.get("avb_pvmfw_add_hash_footer_args")
362 if args and args.strip():
363 cmd.extend(shlex.split(args))
364 common.RunAndCheckOutput(cmd)
365
366 img.Write()
367 return img.name
368
Tianjiebbde59f2021-05-03 21:18:56 -0700369
Hongguang Chenf23364d2020-04-27 18:36:36 -0700370def AddCustomImages(output_zip, partition_name):
371 """Adds and signs custom images in IMAGES/.
372
373 Args:
374 output_zip: The output zip file (needs to be already open), or None to
375 write images to OPTIONS.input_tmp/.
376
377 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
378 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
379
380 Raises:
381 AssertionError: If image can't be found.
382 """
383
Hongguang Chenf23364d2020-04-27 18:36:36 -0700384 key_path = OPTIONS.info_dict.get("avb_{}_key_path".format(partition_name))
385 algorithm = OPTIONS.info_dict.get("avb_{}_algorithm".format(partition_name))
386 extra_args = OPTIONS.info_dict.get(
387 "avb_{}_add_hashtree_footer_args".format(partition_name))
388 partition_size = OPTIONS.info_dict.get(
389 "avb_{}_partition_size".format(partition_name))
390
391 builder = verity_utils.CreateCustomImageBuilder(
392 OPTIONS.info_dict, partition_name, partition_size,
393 key_path, algorithm, extra_args)
394
395 for img_name in OPTIONS.info_dict.get(
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800396 "avb_{}_image_list".format(partition_name)).split():
397 custom_image = OutputFile(
398 output_zip, OPTIONS.input_tmp, "IMAGES", img_name)
Hongguang Chenf23364d2020-04-27 18:36:36 -0700399 if os.path.exists(custom_image.name):
400 continue
401
402 custom_image_prebuilt_path = os.path.join(
403 OPTIONS.input_tmp, "PREBUILT_IMAGES", img_name)
404 assert os.path.exists(custom_image_prebuilt_path), \
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800405 "Failed to find %s at %s" % (img_name, custom_image_prebuilt_path)
Hongguang Chenf23364d2020-04-27 18:36:36 -0700406
407 shutil.copy(custom_image_prebuilt_path, custom_image.name)
408
409 if builder is not None:
410 builder.Build(custom_image.name)
411
412 custom_image.Write()
413
414 default = os.path.join(OPTIONS.input_tmp, "IMAGES", partition_name + ".img")
415 assert os.path.exists(default), \
416 "There should be one %s.img" % (partition_name)
417 return default
418
Doug Zongker3c84f562014-07-31 11:06:30 -0700419
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800420def CreateImage(input_dir, info_dict, what, output_file, block_list=None):
Tao Baoa3705452019-06-24 15:33:41 -0700421 logger.info("creating %s.img...", what)
Doug Zongker3c84f562014-07-31 11:06:30 -0700422
Doug Zongker3c84f562014-07-31 11:06:30 -0700423 image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
Bryan Henrye6d547d2018-07-31 18:32:00 -0700424 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700425
Doug Zongker3c84f562014-07-31 11:06:30 -0700426 if what == "system":
427 fs_config_prefix = ""
428 else:
429 fs_config_prefix = what + "_"
430
431 fs_config = os.path.join(
432 input_dir, "META/" + fs_config_prefix + "filesystem_config.txt")
Dan Albert8b72aef2015-03-23 19:13:21 -0700433 if not os.path.exists(fs_config):
434 fs_config = None
Doug Zongker3c84f562014-07-31 11:06:30 -0700435
Ying Wanga2292c92015-03-24 19:07:40 -0700436 # Override values loaded from info_dict.
437 if fs_config:
438 image_props["fs_config"] = fs_config
Ying Wanga2292c92015-03-24 19:07:40 -0700439 if block_list:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800440 image_props["block_list"] = block_list.name
Ying Wanga2292c92015-03-24 19:07:40 -0700441
Tao Baod86e3112017-09-22 15:45:33 -0700442 # Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
Tianjiefdda51d2021-05-05 14:46:35 -0700443 # build fingerprint). Also use the legacy build id, because the vbmeta digest
444 # isn't available at this point.
445 build_info = common.BuildInfo(info_dict, use_legacy_id=True)
Yifan Hongc08cbf02020-09-15 19:07:39 +0000446 uuid_seed = what + "-" + build_info.GetPartitionFingerprint(what)
Tao Baod86e3112017-09-22 15:45:33 -0700447 image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
448 hash_seed = "hash_seed-" + uuid_seed
449 image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
450
Tao Baoc6bd70a2018-09-27 16:58:00 -0700451 build_image.BuildImage(
452 os.path.join(input_dir, what.upper()), image_props, output_file.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700453
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800454 output_file.Write()
455 if block_list:
456 block_list.Write()
457
Shashikant Baviskar16a73892019-02-07 10:57:21 +0900458 # Set the '_image_size' for given image size.
Tianjie Xuf1a13182017-01-19 17:39:30 -0800459 is_verity_partition = "verity_block_device" in image_props
hungweichen65ba3752022-08-17 10:14:01 +0000460 verity_supported = (image_props.get("avb_enable") == "true")
Tianjie Xu6b2e1552017-06-01 11:32:32 -0700461 is_avb_enable = image_props.get("avb_hashtree_enable") == "true"
462 if verity_supported and (is_verity_partition or is_avb_enable):
Tao Bao35f4ebc2018-09-27 15:31:11 -0700463 image_size = image_props.get("image_size")
464 if image_size:
Shashikant Baviskar16a73892019-02-07 10:57:21 +0900465 image_size_key = what + "_image_size"
466 info_dict[image_size_key] = int(image_size)
Tianjie Xuf1a13182017-01-19 17:39:30 -0800467
Yifan Hongc767f7c2018-11-08 15:41:24 -0800468 use_dynamic_size = (
Tao Bao2764aee2018-11-21 11:02:48 -0800469 info_dict.get("use_dynamic_partition_size") == "true" and
470 what in shlex.split(info_dict.get("dynamic_partition_list", "").strip()))
Yifan Hongc767f7c2018-11-08 15:41:24 -0800471 if use_dynamic_size:
472 info_dict.update(build_image.GlobalDictFromImageProp(image_props, what))
473
Doug Zongker3c84f562014-07-31 11:06:30 -0700474
Tao Bao886d8832018-02-27 11:46:19 -0800475def AddUserdata(output_zip):
Ying Wang2a048392015-06-25 13:56:53 -0700476 """Create a userdata image and store it in output_zip.
477
478 In most case we just create and store an empty userdata.img;
479 But the invoker can also request to create userdata.img with real
480 data from the target files, by setting "userdata_img_with_data=true"
481 in OPTIONS.info_dict.
482 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700483
Tao Bao886d8832018-02-27 11:46:19 -0800484 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "userdata.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800485 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700486 logger.info("userdata.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800487 return
488
Elliott Hughes305b0882016-06-15 17:04:54 -0700489 # Skip userdata.img if no size.
Tao Bao2c15d9e2015-07-09 11:51:16 -0700490 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "data")
Elliott Hughes305b0882016-06-15 17:04:54 -0700491 if not image_props.get("partition_size"):
Doug Zongker3c84f562014-07-31 11:06:30 -0700492 return
493
Tao Bao32fcdab2018-10-12 10:30:39 -0700494 logger.info("creating userdata.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700495
Bryan Henrye6d547d2018-07-31 18:32:00 -0700496 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700497
Tao Baofa863c82017-05-23 23:49:03 -0700498 if OPTIONS.info_dict.get("userdata_img_with_data") == "true":
499 user_dir = os.path.join(OPTIONS.input_tmp, "DATA")
Ying Wang2a048392015-06-25 13:56:53 -0700500 else:
Tao Bao1c830bf2017-12-25 10:43:47 -0800501 user_dir = common.MakeTempDir()
Ying Wang2a048392015-06-25 13:56:53 -0700502
Tao Baoc6bd70a2018-09-27 16:58:00 -0700503 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700504
505 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800506 # Always use compression for useradata image.
507 # As it's likely huge and consist of lots of 0s.
508 img.Write(zipfile.ZIP_DEFLATED)
Doug Zongker3c84f562014-07-31 11:06:30 -0700509
510
Tao Bao744c4c72018-08-20 21:09:07 -0700511def AddVBMeta(output_zip, partitions, name, needed_partitions):
512 """Creates a VBMeta image and stores it in output_zip.
513
514 It generates the requested VBMeta image. The requested image could be for
515 top-level or chained VBMeta image, which is determined based on the name.
Tao Baobf70c312017-07-11 17:27:55 -0700516
517 Args:
518 output_zip: The output zip file, which needs to be already open.
519 partitions: A dict that's keyed by partition names with image paths as
Hongguang Chenf23364d2020-04-27 18:36:36 -0700520 values. Only valid partition names are accepted, as partitions listed
521 in common.AVB_PARTITIONS and custom partitions listed in
522 OPTIONS.info_dict.get("avb_custom_images_partition_list")
David Anderson7709ab22018-10-15 14:41:34 -0700523 name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
Tao Bao744c4c72018-08-20 21:09:07 -0700524 needed_partitions: Partitions whose descriptors should be included into the
525 generated VBMeta image.
526
Tao Bao71064202018-10-22 15:08:02 -0700527 Returns:
528 Path to the created image.
529
Tao Bao744c4c72018-08-20 21:09:07 -0700530 Raises:
531 AssertionError: On invalid input args.
Tao Baobf70c312017-07-11 17:27:55 -0700532 """
Tao Bao744c4c72018-08-20 21:09:07 -0700533 assert needed_partitions, "Needed partitions must be specified"
534
535 img = OutputFile(
536 output_zip, OPTIONS.input_tmp, "IMAGES", "{}.img".format(name))
Tao Bao93e7ebe2019-01-13 23:23:01 -0800537 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700538 logger.info("%s.img already exists; not rebuilding...", name)
Tao Bao93e7ebe2019-01-13 23:23:01 -0800539 return img.name
Tao Bao262bf3f2017-07-11 17:27:55 -0700540
Daniel Norman276f0622019-07-26 14:13:51 -0700541 common.BuildVBMeta(img.name, partitions, name, needed_partitions)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800542 img.Write()
Tao Bao71064202018-10-22 15:08:02 -0700543 return img.name
David Zeuthen2ce63ed2016-09-15 13:43:54 -0400544
545
Tao Bao886d8832018-02-27 11:46:19 -0800546def AddPartitionTable(output_zip):
David Zeuthen25328622016-04-08 15:08:03 -0400547 """Create a partition table image and store it in output_zip."""
548
Tao Bao886d8832018-02-27 11:46:19 -0800549 img = OutputFile(
550 output_zip, OPTIONS.input_tmp, "IMAGES", "partition-table.img")
551 bpt = OutputFile(
Bryan Henryf130a232018-04-26 11:59:33 -0700552 output_zip, OPTIONS.input_tmp, "META", "partition-table.bpt")
David Zeuthen25328622016-04-08 15:08:03 -0400553
554 # use BPTTOOL from environ, or "bpttool" if empty or not set.
555 bpttool = os.getenv("BPTTOOL") or "bpttool"
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800556 cmd = [bpttool, "make_table", "--output_json", bpt.name,
557 "--output_gpt", img.name]
David Zeuthen25328622016-04-08 15:08:03 -0400558 input_files_str = OPTIONS.info_dict["board_bpt_input_files"]
jiajia tange5ddfcd2022-06-21 10:36:12 +0800559 input_files = input_files_str.split()
David Zeuthen25328622016-04-08 15:08:03 -0400560 for i in input_files:
561 cmd.extend(["--input", i])
562 disk_size = OPTIONS.info_dict.get("board_bpt_disk_size")
563 if disk_size:
564 cmd.extend(["--disk_size", disk_size])
565 args = OPTIONS.info_dict.get("board_bpt_make_table_args")
566 if args:
567 cmd.extend(shlex.split(args))
Tao Bao2764aee2018-11-21 11:02:48 -0800568 common.RunAndCheckOutput(cmd)
David Zeuthen25328622016-04-08 15:08:03 -0400569
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800570 img.Write()
571 bpt.Write()
David Zeuthen25328622016-04-08 15:08:03 -0400572
573
Tao Bao886d8832018-02-27 11:46:19 -0800574def AddCache(output_zip):
Doug Zongker3c84f562014-07-31 11:06:30 -0700575 """Create an empty cache image and store it in output_zip."""
576
Tao Bao886d8832018-02-27 11:46:19 -0800577 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "cache.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800578 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700579 logger.info("cache.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800580 return
581
Tao Bao2c15d9e2015-07-09 11:51:16 -0700582 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "cache")
Doug Zongker3c84f562014-07-31 11:06:30 -0700583 # The build system has to explicitly request for cache.img.
584 if "fs_type" not in image_props:
585 return
586
Tao Bao32fcdab2018-10-12 10:30:39 -0700587 logger.info("creating cache.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700588
Bryan Henrye6d547d2018-07-31 18:32:00 -0700589 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700590
Tao Bao1c830bf2017-12-25 10:43:47 -0800591 user_dir = common.MakeTempDir()
Tao Baoc6bd70a2018-09-27 16:58:00 -0700592 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700593
594 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800595 img.Write()
Doug Zongker3c84f562014-07-31 11:06:30 -0700596
597
Tao Bao5277d102018-04-17 23:47:21 -0700598def CheckAbOtaImages(output_zip, ab_partitions):
599 """Checks that all the listed A/B partitions have their images available.
Tao Baobea20ac2018-01-17 17:57:49 -0800600
Tao Bao5277d102018-04-17 23:47:21 -0700601 The images need to be available under IMAGES/ or RADIO/, with the former takes
602 a priority.
Tao Baobea20ac2018-01-17 17:57:49 -0800603
604 Args:
605 output_zip: The output zip file (needs to be already open), or None to
Tao Bao5277d102018-04-17 23:47:21 -0700606 find images in OPTIONS.input_tmp/.
Tao Baobea20ac2018-01-17 17:57:49 -0800607 ab_partitions: The list of A/B partitions.
608
609 Raises:
610 AssertionError: If it can't find an image.
611 """
612 for partition in ab_partitions:
Daniel Norman78554ea2021-09-14 10:29:38 -0700613 img_name = partition + ".img"
Tao Baobea20ac2018-01-17 17:57:49 -0800614
Tao Baoa2ff4c92018-01-17 12:14:43 -0800615 # Assert that the image is present under IMAGES/ now.
Tao Baobea20ac2018-01-17 17:57:49 -0800616 if output_zip:
617 # Zip spec says: All slashes MUST be forward slashes.
Tao Bao5277d102018-04-17 23:47:21 -0700618 images_path = "IMAGES/" + img_name
619 radio_path = "RADIO/" + img_name
620 available = (images_path in output_zip.namelist() or
621 radio_path in output_zip.namelist())
Tao Baobea20ac2018-01-17 17:57:49 -0800622 else:
Tao Bao5277d102018-04-17 23:47:21 -0700623 images_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
624 radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
625 available = os.path.exists(images_path) or os.path.exists(radio_path)
626
627 assert available, "Failed to find " + img_name
Tao Baobea20ac2018-01-17 17:57:49 -0800628
629
Tao Baobea20ac2018-01-17 17:57:49 -0800630def AddPackRadioImages(output_zip, images):
631 """Copies images listed in META/pack_radioimages.txt from RADIO/ to IMAGES/.
632
633 Args:
634 output_zip: The output zip file (needs to be already open), or None to
635 write images to OPTIONS.input_tmp/.
636 images: A list of image names.
637
638 Raises:
639 AssertionError: If a listed image can't be found.
640 """
641 for image in images:
642 img_name = image.strip()
643 _, ext = os.path.splitext(img_name)
644 if not ext:
645 img_name += ".img"
Tao Baoa2ff4c92018-01-17 12:14:43 -0800646
Tao Baobea20ac2018-01-17 17:57:49 -0800647 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
648 if os.path.exists(prebuilt_path):
Tao Bao32fcdab2018-10-12 10:30:39 -0700649 logger.info("%s already exists, no need to overwrite...", img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800650 continue
651
652 img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
653 assert os.path.exists(img_radio_path), \
654 "Failed to find %s at %s" % (img_name, img_radio_path)
Tao Baoa2ff4c92018-01-17 12:14:43 -0800655
Tao Baobea20ac2018-01-17 17:57:49 -0800656 if output_zip:
Tao Baoa2ff4c92018-01-17 12:14:43 -0800657 common.ZipWrite(output_zip, img_radio_path, "IMAGES/" + img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800658 else:
659 shutil.copy(img_radio_path, prebuilt_path)
660
661
David Anderson1ef03e22018-08-30 13:11:47 -0700662def AddSuperEmpty(output_zip):
663 """Create a super_empty.img and store it in output_zip."""
664
665 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "super_empty.img")
Yifan Hong055e6cf2018-11-29 13:51:48 -0800666 build_super_image.BuildSuperImage(OPTIONS.info_dict, img.name)
David Anderson1ef03e22018-08-30 13:11:47 -0700667 img.Write()
668
669
Yifan Hongc767f7c2018-11-08 15:41:24 -0800670def AddSuperSplit(output_zip):
671 """Create split super_*.img and store it in output_zip."""
672
Yifan Hong055e6cf2018-11-29 13:51:48 -0800673 outdir = os.path.join(OPTIONS.input_tmp, "OTA")
Yifan Honge98427a2018-12-07 10:08:27 -0800674 built = build_super_image.BuildSuperImage(OPTIONS.input_tmp, outdir)
Yifan Hongc767f7c2018-11-08 15:41:24 -0800675
Yifan Honge98427a2018-12-07 10:08:27 -0800676 if built:
677 for dev in OPTIONS.info_dict['super_block_devices'].strip().split():
678 img = OutputFile(output_zip, OPTIONS.input_tmp, "OTA",
679 "super_" + dev + ".img")
680 img.Write()
Yifan Hongc767f7c2018-11-08 15:41:24 -0800681
682
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700683def ReplaceUpdatedFiles(zip_filename, files_list):
Tao Bao89d7ab22017-12-14 17:05:33 -0800684 """Updates all the ZIP entries listed in files_list.
Tianjie Xu38af07f2017-05-25 17:38:53 -0700685
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700686 For now the list includes META/care_map.pb, and the related files under
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700687 SYSTEM/ after rebuilding recovery.
688 """
Tao Bao89d7ab22017-12-14 17:05:33 -0800689 common.ZipDelete(zip_filename, files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -0700690 output_zip = zipfile.ZipFile(zip_filename, "a",
691 compression=zipfile.ZIP_DEFLATED,
692 allowZip64=True)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700693 for item in files_list:
Tianjie Xu38af07f2017-05-25 17:38:53 -0700694 file_path = os.path.join(OPTIONS.input_tmp, item)
695 assert os.path.exists(file_path)
696 common.ZipWrite(output_zip, file_path, arcname=item)
697 common.ZipClose(output_zip)
698
699
Chris Gross435b8fe2020-09-15 09:53:44 -0700700def HasPartition(partition_name):
701 """Determines if the target files archive should build a given partition."""
702
703 return ((os.path.isdir(
704 os.path.join(OPTIONS.input_tmp, partition_name.upper())) and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800705 OPTIONS.info_dict.get(
706 "building_{}_image".format(partition_name)) == "true") or
707 os.path.exists(
708 os.path.join(OPTIONS.input_tmp, "IMAGES",
709 "{}.img".format(partition_name))))
Chris Gross435b8fe2020-09-15 09:53:44 -0700710
Tianjiea5fca032021-06-01 22:06:28 -0700711
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500712def AddApexInfo(output_zip):
Tianjiea5fca032021-06-01 22:06:28 -0700713 apex_infos = GetApexInfoFromTargetFiles(OPTIONS.input_tmp, 'system',
714 compressed_only=False)
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500715 apex_metadata_proto = ota_metadata_pb2.ApexMetadata()
716 apex_metadata_proto.apex_info.extend(apex_infos)
717 apex_info_bytes = apex_metadata_proto.SerializeToString()
718
719 output_file = os.path.join(OPTIONS.input_tmp, "META", "apex_info.pb")
720 with open(output_file, "wb") as ofile:
721 ofile.write(apex_info_bytes)
722 if output_zip:
723 arc_name = "META/apex_info.pb"
724 if arc_name in output_zip.namelist():
725 OPTIONS.replace_updated_files_list.append(arc_name)
726 else:
727 common.ZipWrite(output_zip, output_file, arc_name)
728
Chris Gross435b8fe2020-09-15 09:53:44 -0700729
Tianjiec3bf3d02021-07-14 15:56:37 -0700730def AddVbmetaDigest(output_zip):
731 """Write the vbmeta digest to the output dir and zipfile."""
732
733 # Calculate the vbmeta digest and put the result in to META/
734 boot_images = OPTIONS.info_dict.get("boot_images")
735 # Disable the digest calculation if the target_file is used as a container
Bowgo Tsaiaba5c9e2021-09-27 14:08:41 +0800736 # for boot images. A boot container might contain boot-5.4.img, boot-5.10.img
737 # etc., instead of just a boot.img and will fail in vbmeta digest calculation.
738 boot_container = boot_images and (
739 len(boot_images.split()) >= 2 or boot_images.split()[0] != 'boot.img')
Tianjiec3bf3d02021-07-14 15:56:37 -0700740 if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800741 OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"):
Tianjiec3bf3d02021-07-14 15:56:37 -0700742 avbtool = OPTIONS.info_dict["avb_avbtool"]
743 digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool)
744 vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META",
745 "vbmeta_digest.txt")
746 with open(vbmeta_digest_txt, 'w') as f:
747 f.write(digest)
748 # writes to the output zipfile
749 if output_zip:
750 arc_name = "META/vbmeta_digest.txt"
751 if arc_name in output_zip.namelist():
752 OPTIONS.replace_updated_files_list.append(arc_name)
753 else:
754 common.ZipWriteStr(output_zip, arc_name, digest)
755
756
Doug Zongker3c84f562014-07-31 11:06:30 -0700757def AddImagesToTargetFiles(filename):
Tao Baoae396d92017-11-20 11:56:43 -0800758 """Creates and adds images (boot/recovery/system/...) to a target_files.zip.
759
760 It works with either a zip file (zip mode), or a directory that contains the
761 files to be packed into a target_files.zip (dir mode). The latter is used when
762 being called from build/make/core/Makefile.
763
764 The images will be created under IMAGES/ in the input target_files.zip.
765
766 Args:
Tao Baodba59ee2018-01-09 13:21:02 -0800767 filename: the target_files.zip, or the zip root directory.
Tao Baoae396d92017-11-20 11:56:43 -0800768 """
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800769 if os.path.isdir(filename):
770 OPTIONS.input_tmp = os.path.abspath(filename)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800771 else:
Tao Baodba59ee2018-01-09 13:21:02 -0800772 OPTIONS.input_tmp = common.UnzipTemp(filename)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700773
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800774 if not OPTIONS.add_missing:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800775 if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")):
Tao Bao32fcdab2018-10-12 10:30:39 -0700776 logger.warning("target_files appears to already contain images.")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800777 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700778
Tao Bao410ad8b2018-08-24 12:08:38 -0700779 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True)
Tao Baodba59ee2018-01-09 13:21:02 -0800780
781 has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
Chris Grossa784ef12019-04-22 11:09:57 -0700782 has_boot = OPTIONS.info_dict.get("no_boot") != "true"
Devin Mooreafdd7c72021-12-13 22:04:08 +0000783 has_init_boot = OPTIONS.info_dict.get("init_boot") == "true"
Steve Mucklee1b10862019-07-10 10:49:37 -0700784 has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"
Lucas Weif57333f2022-02-24 10:30:15 +0800785 has_vendor_kernel_boot = OPTIONS.info_dict.get("vendor_kernel_boot") == "true"
Tao Baodba59ee2018-01-09 13:21:02 -0800786
Ramji Jiyani13a41372022-01-27 07:05:08 +0000787 # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system_dlkm, system, system_other}.img
Chris Gross435b8fe2020-09-15 09:53:44 -0700788 # can be built from source, or dropped into target_files.zip as a prebuilt blob.
789 has_vendor = HasPartition("vendor")
790 has_odm = HasPartition("odm")
791 has_vendor_dlkm = HasPartition("vendor_dlkm")
792 has_odm_dlkm = HasPartition("odm_dlkm")
Ramji Jiyani13a41372022-01-27 07:05:08 +0000793 has_system_dlkm = HasPartition("system_dlkm")
Chris Gross435b8fe2020-09-15 09:53:44 -0700794 has_product = HasPartition("product")
795 has_system_ext = HasPartition("system_ext")
796 has_system = HasPartition("system")
797 has_system_other = HasPartition("system_other")
Chris Gross203191b2020-05-30 02:39:12 +0000798 has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true"
799 has_cache = OPTIONS.info_dict.get("building_cache_image") == "true"
Doug Zongker3c84f562014-07-31 11:06:30 -0700800
Tao Baodba59ee2018-01-09 13:21:02 -0800801 # Set up the output destination. It writes to the given directory for dir
802 # mode; otherwise appends to the given ZIP.
803 if os.path.isdir(filename):
804 output_zip = None
805 else:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800806 output_zip = zipfile.ZipFile(filename, "a",
807 compression=zipfile.ZIP_DEFLATED,
808 allowZip64=True)
Tao Baoae396d92017-11-20 11:56:43 -0800809
810 # Always make input_tmp/IMAGES available, since we may stage boot / recovery
811 # images there even under zip mode. The directory will be cleaned up as part
812 # of OPTIONS.input_tmp.
813 images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES")
814 if not os.path.isdir(images_dir):
815 os.makedirs(images_dir)
Doug Zongker3c84f562014-07-31 11:06:30 -0700816
Tao Baobf70c312017-07-11 17:27:55 -0700817 # A map between partition names and their paths, which could be used when
818 # generating AVB vbmeta image.
Tao Bao3ed35d32019-10-07 20:48:48 -0700819 partitions = {}
Tao Baobf70c312017-07-11 17:27:55 -0700820
Doug Zongkerfc44a512014-08-26 13:10:25 -0700821 def banner(s):
Tao Baoa3705452019-06-24 15:33:41 -0700822 logger.info("\n\n++++ %s ++++\n\n", s)
Doug Zongker3c84f562014-07-31 11:06:30 -0700823
Chris Grossa784ef12019-04-22 11:09:57 -0700824 boot_image = None
Greg Kaisere086f722021-09-14 19:32:27 +0000825 if has_boot:
Chris Grossa784ef12019-04-22 11:09:57 -0700826 banner("boot")
Steve Muckle9793cf62020-04-08 18:27:00 -0700827 boot_images = OPTIONS.info_dict.get("boot_images")
828 if boot_images is None:
829 boot_images = "boot.img"
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800830 for index, b in enumerate(boot_images.split()):
Steve Muckle9793cf62020-04-08 18:27:00 -0700831 # common.GetBootableImage() returns the image directly if present.
832 boot_image = common.GetBootableImage(
833 "IMAGES/" + b, b, OPTIONS.input_tmp, "BOOT")
834 # boot.img may be unavailable in some targets (e.g. aosp_arm64).
835 if boot_image:
836 boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b)
Roopesh Nataraja3e15f6e2020-06-08 19:54:13 -0700837 # Although multiple boot images can be generated, include the image
838 # descriptor of only the first boot image in vbmeta
839 if index == 0:
Steve Muckle9793cf62020-04-08 18:27:00 -0700840 partitions['boot'] = boot_image_path
841 if not os.path.exists(boot_image_path):
842 boot_image.WriteToDir(OPTIONS.input_tmp)
843 if output_zip:
844 boot_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -0700845
Devin Mooreafdd7c72021-12-13 22:04:08 +0000846 if has_init_boot:
847 banner("init_boot")
848 init_boot_image = common.GetBootableImage(
849 "IMAGES/init_boot.img", "init_boot.img", OPTIONS.input_tmp, "INIT_BOOT")
850 if init_boot_image:
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800851 partitions['init_boot'] = os.path.join(
852 OPTIONS.input_tmp, "IMAGES", "init_boot.img")
Devin Mooreafdd7c72021-12-13 22:04:08 +0000853 if not os.path.exists(partitions['init_boot']):
854 init_boot_image.WriteToDir(OPTIONS.input_tmp)
855 if output_zip:
856 init_boot_image.AddToZip(output_zip)
857
Greg Kaisere086f722021-09-14 19:32:27 +0000858 if has_vendor_boot:
Steve Mucklee1b10862019-07-10 10:49:37 -0700859 banner("vendor_boot")
860 vendor_boot_image = common.GetVendorBootImage(
861 "IMAGES/vendor_boot.img", "vendor_boot.img", OPTIONS.input_tmp,
862 "VENDOR_BOOT")
863 if vendor_boot_image:
864 partitions['vendor_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
865 "vendor_boot.img")
866 if not os.path.exists(partitions['vendor_boot']):
867 vendor_boot_image.WriteToDir(OPTIONS.input_tmp)
868 if output_zip:
869 vendor_boot_image.AddToZip(output_zip)
870
Lucas Weif57333f2022-02-24 10:30:15 +0800871 if has_vendor_kernel_boot:
872 banner("vendor_kernel_boot")
Lucas Wei03230252022-04-18 16:00:40 +0800873 vendor_kernel_boot_image = common.GetVendorKernelBootImage(
Lucas Weif57333f2022-02-24 10:30:15 +0800874 "IMAGES/vendor_kernel_boot.img", "vendor_kernel_boot.img", OPTIONS.input_tmp,
875 "VENDOR_KERNEL_BOOT")
876 if vendor_kernel_boot_image:
877 partitions['vendor_kernel_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
878 "vendor_kernel_boot.img")
879 if not os.path.exists(partitions['vendor_kernel_boot']):
880 vendor_kernel_boot_image.WriteToDir(OPTIONS.input_tmp)
881 if output_zip:
882 vendor_kernel_boot_image.AddToZip(output_zip)
883
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800884 recovery_image = None
Greg Kaisere086f722021-09-14 19:32:27 +0000885 if has_recovery:
Tao Baodb45efa2015-10-27 19:25:18 -0700886 banner("recovery")
Tao Bao262bf3f2017-07-11 17:27:55 -0700887 recovery_image = common.GetBootableImage(
888 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
889 assert recovery_image, "Failed to create recovery.img."
Tao Baobf70c312017-07-11 17:27:55 -0700890 partitions['recovery'] = os.path.join(
Tao Bao262bf3f2017-07-11 17:27:55 -0700891 OPTIONS.input_tmp, "IMAGES", "recovery.img")
Tao Baobf70c312017-07-11 17:27:55 -0700892 if not os.path.exists(partitions['recovery']):
Tao Bao262bf3f2017-07-11 17:27:55 -0700893 recovery_image.WriteToDir(OPTIONS.input_tmp)
894 if output_zip:
895 recovery_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -0700896
Tao Baod42e97e2016-11-30 12:11:57 -0800897 banner("recovery (two-step image)")
898 # The special recovery.img for two-step package use.
899 recovery_two_step_image = common.GetBootableImage(
Tao Bao04808502019-07-25 23:11:41 -0700900 "OTA/recovery-two-step.img", "recovery-two-step.img",
Tao Baod42e97e2016-11-30 12:11:57 -0800901 OPTIONS.input_tmp, "RECOVERY", two_step_image=True)
Tao Bao262bf3f2017-07-11 17:27:55 -0700902 assert recovery_two_step_image, "Failed to create recovery-two-step.img."
903 recovery_two_step_image_path = os.path.join(
Tao Bao04808502019-07-25 23:11:41 -0700904 OPTIONS.input_tmp, "OTA", "recovery-two-step.img")
Tao Bao262bf3f2017-07-11 17:27:55 -0700905 if not os.path.exists(recovery_two_step_image_path):
906 recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800907 if output_zip:
908 recovery_two_step_image.AddToZip(output_zip)
Tao Baod42e97e2016-11-30 12:11:57 -0800909
Daniel Norman78554ea2021-09-14 10:29:38 -0700910 def add_partition(partition, has_partition, add_func, add_args):
911 if has_partition:
912 banner(partition)
913 partitions[partition] = add_func(output_zip, *add_args)
Tao Baobf70c312017-07-11 17:27:55 -0700914
Daniel Norman78554ea2021-09-14 10:29:38 -0700915 add_partition_calls = (
916 ("system", has_system, AddSystem, [recovery_image, boot_image]),
917 ("vendor", has_vendor, AddVendor, [recovery_image, boot_image]),
918 ("product", has_product, AddProduct, []),
919 ("system_ext", has_system_ext, AddSystemExt, []),
920 ("odm", has_odm, AddOdm, []),
921 ("vendor_dlkm", has_vendor_dlkm, AddVendorDlkm, []),
922 ("odm_dlkm", has_odm_dlkm, AddOdmDlkm, []),
Ramji Jiyani13a41372022-01-27 07:05:08 +0000923 ("system_dlkm", has_system_dlkm, AddSystemDlkm, []),
Daniel Norman78554ea2021-09-14 10:29:38 -0700924 ("system_other", has_system_other, AddSystemOther, []),
925 )
926 for call in add_partition_calls:
927 add_partition(*call)
Tao Baobf70c312017-07-11 17:27:55 -0700928
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500929 AddApexInfo(output_zip)
930
Tianjie Xub48589a2016-08-03 19:21:52 -0700931 if not OPTIONS.is_signing:
Greg Kaisere086f722021-09-14 19:32:27 +0000932 banner("userdata")
933 AddUserdata(output_zip)
934 banner("cache")
935 AddCache(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -0700936
937 if OPTIONS.info_dict.get("board_bpt_enable") == "true":
David Zeuthen25328622016-04-08 15:08:03 -0400938 banner("partition-table")
939 AddPartitionTable(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -0700940
Daniel Norman78554ea2021-09-14 10:29:38 -0700941 add_partition("dtbo",
942 OPTIONS.info_dict.get("has_dtbo") == "true", AddDtbo, [])
943 add_partition("pvmfw",
944 OPTIONS.info_dict.get("has_pvmfw") == "true", AddPvmfw, [])
Andrew Sculle077cf72021-02-18 10:27:29 +0000945
Hongguang Chenf23364d2020-04-27 18:36:36 -0700946 # Custom images.
947 custom_partitions = OPTIONS.info_dict.get(
948 "avb_custom_images_partition_list", "").strip().split()
949 for partition_name in custom_partitions:
950 partition_name = partition_name.strip()
951 banner("custom images for " + partition_name)
952 partitions[partition_name] = AddCustomImages(output_zip, partition_name)
953
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800954 if OPTIONS.info_dict.get("avb_enable") == "true":
Tao Bao744c4c72018-08-20 21:09:07 -0700955 # vbmeta_partitions includes the partitions that should be included into
956 # top-level vbmeta.img, which are the ones that are not included in any
957 # chained VBMeta image plus the chained VBMeta images themselves.
Hongguang Chenf23364d2020-04-27 18:36:36 -0700958 # Currently custom_partitions are all chained to VBMeta image.
959 vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)
Tao Bao744c4c72018-08-20 21:09:07 -0700960
David Anderson7709ab22018-10-15 14:41:34 -0700961 vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +0000962 if vbmeta_system:
David Anderson7709ab22018-10-15 14:41:34 -0700963 banner("vbmeta_system")
Tao Bao71064202018-10-22 15:08:02 -0700964 partitions["vbmeta_system"] = AddVBMeta(
David Anderson7709ab22018-10-15 14:41:34 -0700965 output_zip, partitions, "vbmeta_system", vbmeta_system.split())
Tao Bao744c4c72018-08-20 21:09:07 -0700966 vbmeta_partitions = [
967 item for item in vbmeta_partitions
David Anderson7709ab22018-10-15 14:41:34 -0700968 if item not in vbmeta_system.split()]
969 vbmeta_partitions.append("vbmeta_system")
Tao Bao744c4c72018-08-20 21:09:07 -0700970
971 vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +0000972 if vbmeta_vendor:
Tao Bao744c4c72018-08-20 21:09:07 -0700973 banner("vbmeta_vendor")
Tao Bao71064202018-10-22 15:08:02 -0700974 partitions["vbmeta_vendor"] = AddVBMeta(
Tao Bao744c4c72018-08-20 21:09:07 -0700975 output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
976 vbmeta_partitions = [
977 item for item in vbmeta_partitions
978 if item not in vbmeta_vendor.split()]
979 vbmeta_partitions.append("vbmeta_vendor")
980
Greg Kaisere086f722021-09-14 19:32:27 +0000981 if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
Bowgo Tsai82182252020-11-13 11:28:17 +0800982 banner("vbmeta")
983 AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
Doug Zongker3c84f562014-07-31 11:06:30 -0700984
Tao Bao48a2feb2019-06-28 11:00:05 -0700985 if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
Greg Kaisere086f722021-09-14 19:32:27 +0000986 if OPTIONS.info_dict.get("build_super_empty_partition") == "true":
Yo Chiange86bab42021-03-25 10:12:28 +0000987 banner("super_empty")
988 AddSuperEmpty(output_zip)
David Anderson1ef03e22018-08-30 13:11:47 -0700989
Greg Kaisere086f722021-09-14 19:32:27 +0000990 if OPTIONS.info_dict.get("build_super_partition") == "true":
Tao Bao519d1822018-12-27 12:47:23 -0800991 if OPTIONS.info_dict.get(
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800992 "build_retrofit_dynamic_partitions_ota_package") == "true":
Yifan Hongc767f7c2018-11-08 15:41:24 -0800993 banner("super split images")
994 AddSuperSplit(output_zip)
Yifan Hongc767f7c2018-11-08 15:41:24 -0800995
Tianjie Xuaaca4212016-06-28 14:34:03 -0700996 banner("radio")
Tao Baobea20ac2018-01-17 17:57:49 -0800997 ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META",
998 "ab_partitions.txt")
999 if os.path.exists(ab_partitions_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001000 with open(ab_partitions_txt) as f:
Daniel Norman78554ea2021-09-14 10:29:38 -07001001 ab_partitions = f.read().splitlines()
Tianjie Xucfa86222016-03-07 16:31:19 -08001002
Greg Kaisere086f722021-09-14 19:32:27 +00001003 # For devices using A/B update, make sure we have all the needed images
1004 # ready under IMAGES/ or RADIO/.
1005 CheckAbOtaImages(output_zip, ab_partitions)
Tianjie Xuaaca4212016-06-28 14:34:03 -07001006
Greg Kaisere086f722021-09-14 19:32:27 +00001007 # Generate care_map.pb for ab_partitions, then write this file to
1008 # target_files package.
1009 output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb")
1010 AddCareMapForAbOta(output_zip if output_zip else output_care_map,
1011 ab_partitions, partitions)
Tianjie Xucfa86222016-03-07 16:31:19 -08001012
Tao Bao95a95c32017-06-16 15:30:23 -07001013 # Radio images that need to be packed into IMAGES/, and product-img.zip.
Tao Baobea20ac2018-01-17 17:57:49 -08001014 pack_radioimages_txt = os.path.join(
Tao Bao95a95c32017-06-16 15:30:23 -07001015 OPTIONS.input_tmp, "META", "pack_radioimages.txt")
Tao Baobea20ac2018-01-17 17:57:49 -08001016 if os.path.exists(pack_radioimages_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001017 with open(pack_radioimages_txt) as f:
Tao Baobea20ac2018-01-17 17:57:49 -08001018 AddPackRadioImages(output_zip, f.readlines())
Tao Bao95a95c32017-06-16 15:30:23 -07001019
Greg Kaisere086f722021-09-14 19:32:27 +00001020 AddVbmetaDigest(output_zip)
Tianjiebbde59f2021-05-03 21:18:56 -07001021
Dan Willemsen2ee00d52017-03-05 19:51:56 -08001022 if output_zip:
1023 common.ZipClose(output_zip)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -07001024 if OPTIONS.replace_updated_files_list:
1025 ReplaceUpdatedFiles(output_zip.filename,
1026 OPTIONS.replace_updated_files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -07001027
Doug Zongker3c84f562014-07-31 11:06:30 -07001028
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001029def OptimizeCompressedEntries(zipfile_path):
1030 """Convert files that do not compress well to uncompressed storage
1031
1032 EROFS images tend to be compressed already, so compressing them again
1033 yields little space savings. Leaving them uncompressed will make
1034 downstream tooling's job easier, and save compute time.
1035 """
1036 if not zipfile.is_zipfile(zipfile_path):
1037 return
1038 entries_to_store = []
1039 with tempfile.TemporaryDirectory() as tmpdir:
1040 with zipfile.ZipFile(zipfile_path, "r", allowZip64=True) as zfp:
1041 for zinfo in zfp.filelist:
1042 if not zinfo.filename.startswith("IMAGES/") and not zinfo.filename.startswith("META"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001043 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001044 # Don't try to store userdata.img uncompressed, it's usually huge.
1045 if zinfo.filename.endswith("userdata.img"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001046 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001047 if zinfo.compress_size > zinfo.file_size * 0.80 and zinfo.compress_type != zipfile.ZIP_STORED:
1048 entries_to_store.append(zinfo)
1049 zfp.extract(zinfo, tmpdir)
Kelvin Zhang70876142022-02-09 16:05:29 -08001050 if len(entries_to_store) == 0:
1051 return
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001052 # Remove these entries, then re-add them as ZIP_STORED
Kelvin Zhang70876142022-02-09 16:05:29 -08001053 ZipDelete(zipfile_path, [entry.filename for entry in entries_to_store])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001054 with zipfile.ZipFile(zipfile_path, "a", allowZip64=True) as zfp:
1055 for entry in entries_to_store:
1056 zfp.write(os.path.join(tmpdir, entry.filename), entry.filename, compress_type=zipfile.ZIP_STORED)
1057
1058
Doug Zongker3c84f562014-07-31 11:06:30 -07001059def main(argv):
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001060 def option_handler(o, a):
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001061 if o in ("-a", "--add_missing"):
1062 OPTIONS.add_missing = True
1063 elif o in ("-r", "--rebuild_recovery",):
1064 OPTIONS.rebuild_recovery = True
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001065 elif o == "--replace_verity_private_key":
1066 OPTIONS.replace_verity_private_key = (True, a)
1067 elif o == "--replace_verity_public_key":
1068 OPTIONS.replace_verity_public_key = (True, a)
Tianjie Xub48589a2016-08-03 19:21:52 -07001069 elif o == "--is_signing":
1070 OPTIONS.is_signing = True
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001071 else:
1072 return False
1073 return True
1074
Dan Albert8b72aef2015-03-23 19:13:21 -07001075 args = common.ParseOptions(
1076 argv, __doc__, extra_opts="ar",
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001077 extra_long_opts=["add_missing", "rebuild_recovery",
1078 "replace_verity_public_key=",
1079 "replace_verity_private_key=",
Greg Kaisere086f722021-09-14 19:32:27 +00001080 "is_signing"],
Dan Albert8b72aef2015-03-23 19:13:21 -07001081 extra_option_handler=option_handler)
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001082
Doug Zongker3c84f562014-07-31 11:06:30 -07001083 if len(args) != 1:
1084 common.Usage(__doc__)
1085 sys.exit(1)
1086
Tao Bao32fcdab2018-10-12 10:30:39 -07001087 common.InitLogging()
1088
Doug Zongker3c84f562014-07-31 11:06:30 -07001089 AddImagesToTargetFiles(args[0])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001090 OptimizeCompressedEntries(args[0])
Tao Bao32fcdab2018-10-12 10:30:39 -07001091 logger.info("done.")
Doug Zongker3c84f562014-07-31 11:06:30 -07001092
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001093
Doug Zongker3c84f562014-07-31 11:06:30 -07001094if __name__ == '__main__':
1095 try:
1096 common.CloseInheritedPipes()
1097 main(sys.argv[1:])
Doug Zongkerfc44a512014-08-26 13:10:25 -07001098 finally:
1099 common.Cleanup()