blob: e3db16154eaa0f4075dfc82506936201fbfb77cc [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
Tianjie Xu6b2e1552017-06-01 11:32:32 -0700460 verity_supported = (image_props.get("verity") == "true" or
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800461 image_props.get("avb_enable") == "true")
Tianjie Xu6b2e1552017-06-01 11:32:32 -0700462 is_avb_enable = image_props.get("avb_hashtree_enable") == "true"
463 if verity_supported and (is_verity_partition or is_avb_enable):
Tao Bao35f4ebc2018-09-27 15:31:11 -0700464 image_size = image_props.get("image_size")
465 if image_size:
Shashikant Baviskar16a73892019-02-07 10:57:21 +0900466 image_size_key = what + "_image_size"
467 info_dict[image_size_key] = int(image_size)
Tianjie Xuf1a13182017-01-19 17:39:30 -0800468
Yifan Hongc767f7c2018-11-08 15:41:24 -0800469 use_dynamic_size = (
Tao Bao2764aee2018-11-21 11:02:48 -0800470 info_dict.get("use_dynamic_partition_size") == "true" and
471 what in shlex.split(info_dict.get("dynamic_partition_list", "").strip()))
Yifan Hongc767f7c2018-11-08 15:41:24 -0800472 if use_dynamic_size:
473 info_dict.update(build_image.GlobalDictFromImageProp(image_props, what))
474
Doug Zongker3c84f562014-07-31 11:06:30 -0700475
Tao Bao886d8832018-02-27 11:46:19 -0800476def AddUserdata(output_zip):
Ying Wang2a048392015-06-25 13:56:53 -0700477 """Create a userdata image and store it in output_zip.
478
479 In most case we just create and store an empty userdata.img;
480 But the invoker can also request to create userdata.img with real
481 data from the target files, by setting "userdata_img_with_data=true"
482 in OPTIONS.info_dict.
483 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700484
Tao Bao886d8832018-02-27 11:46:19 -0800485 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "userdata.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800486 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700487 logger.info("userdata.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800488 return
489
Elliott Hughes305b0882016-06-15 17:04:54 -0700490 # Skip userdata.img if no size.
Tao Bao2c15d9e2015-07-09 11:51:16 -0700491 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "data")
Elliott Hughes305b0882016-06-15 17:04:54 -0700492 if not image_props.get("partition_size"):
Doug Zongker3c84f562014-07-31 11:06:30 -0700493 return
494
Tao Bao32fcdab2018-10-12 10:30:39 -0700495 logger.info("creating userdata.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700496
Bryan Henrye6d547d2018-07-31 18:32:00 -0700497 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700498
Tao Baofa863c82017-05-23 23:49:03 -0700499 if OPTIONS.info_dict.get("userdata_img_with_data") == "true":
500 user_dir = os.path.join(OPTIONS.input_tmp, "DATA")
Ying Wang2a048392015-06-25 13:56:53 -0700501 else:
Tao Bao1c830bf2017-12-25 10:43:47 -0800502 user_dir = common.MakeTempDir()
Ying Wang2a048392015-06-25 13:56:53 -0700503
Tao Baoc6bd70a2018-09-27 16:58:00 -0700504 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700505
506 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800507 # Always use compression for useradata image.
508 # As it's likely huge and consist of lots of 0s.
509 img.Write(zipfile.ZIP_DEFLATED)
Doug Zongker3c84f562014-07-31 11:06:30 -0700510
511
Tao Bao744c4c72018-08-20 21:09:07 -0700512def AddVBMeta(output_zip, partitions, name, needed_partitions):
513 """Creates a VBMeta image and stores it in output_zip.
514
515 It generates the requested VBMeta image. The requested image could be for
516 top-level or chained VBMeta image, which is determined based on the name.
Tao Baobf70c312017-07-11 17:27:55 -0700517
518 Args:
519 output_zip: The output zip file, which needs to be already open.
520 partitions: A dict that's keyed by partition names with image paths as
Hongguang Chenf23364d2020-04-27 18:36:36 -0700521 values. Only valid partition names are accepted, as partitions listed
522 in common.AVB_PARTITIONS and custom partitions listed in
523 OPTIONS.info_dict.get("avb_custom_images_partition_list")
David Anderson7709ab22018-10-15 14:41:34 -0700524 name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
Tao Bao744c4c72018-08-20 21:09:07 -0700525 needed_partitions: Partitions whose descriptors should be included into the
526 generated VBMeta image.
527
Tao Bao71064202018-10-22 15:08:02 -0700528 Returns:
529 Path to the created image.
530
Tao Bao744c4c72018-08-20 21:09:07 -0700531 Raises:
532 AssertionError: On invalid input args.
Tao Baobf70c312017-07-11 17:27:55 -0700533 """
Tao Bao744c4c72018-08-20 21:09:07 -0700534 assert needed_partitions, "Needed partitions must be specified"
535
536 img = OutputFile(
537 output_zip, OPTIONS.input_tmp, "IMAGES", "{}.img".format(name))
Tao Bao93e7ebe2019-01-13 23:23:01 -0800538 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700539 logger.info("%s.img already exists; not rebuilding...", name)
Tao Bao93e7ebe2019-01-13 23:23:01 -0800540 return img.name
Tao Bao262bf3f2017-07-11 17:27:55 -0700541
Daniel Norman276f0622019-07-26 14:13:51 -0700542 common.BuildVBMeta(img.name, partitions, name, needed_partitions)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800543 img.Write()
Tao Bao71064202018-10-22 15:08:02 -0700544 return img.name
David Zeuthen2ce63ed2016-09-15 13:43:54 -0400545
546
Tao Bao886d8832018-02-27 11:46:19 -0800547def AddPartitionTable(output_zip):
David Zeuthen25328622016-04-08 15:08:03 -0400548 """Create a partition table image and store it in output_zip."""
549
Tao Bao886d8832018-02-27 11:46:19 -0800550 img = OutputFile(
551 output_zip, OPTIONS.input_tmp, "IMAGES", "partition-table.img")
552 bpt = OutputFile(
Bryan Henryf130a232018-04-26 11:59:33 -0700553 output_zip, OPTIONS.input_tmp, "META", "partition-table.bpt")
David Zeuthen25328622016-04-08 15:08:03 -0400554
555 # use BPTTOOL from environ, or "bpttool" if empty or not set.
556 bpttool = os.getenv("BPTTOOL") or "bpttool"
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800557 cmd = [bpttool, "make_table", "--output_json", bpt.name,
558 "--output_gpt", img.name]
David Zeuthen25328622016-04-08 15:08:03 -0400559 input_files_str = OPTIONS.info_dict["board_bpt_input_files"]
560 input_files = input_files_str.split(" ")
561 for i in input_files:
562 cmd.extend(["--input", i])
563 disk_size = OPTIONS.info_dict.get("board_bpt_disk_size")
564 if disk_size:
565 cmd.extend(["--disk_size", disk_size])
566 args = OPTIONS.info_dict.get("board_bpt_make_table_args")
567 if args:
568 cmd.extend(shlex.split(args))
Tao Bao2764aee2018-11-21 11:02:48 -0800569 common.RunAndCheckOutput(cmd)
David Zeuthen25328622016-04-08 15:08:03 -0400570
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800571 img.Write()
572 bpt.Write()
David Zeuthen25328622016-04-08 15:08:03 -0400573
574
Tao Bao886d8832018-02-27 11:46:19 -0800575def AddCache(output_zip):
Doug Zongker3c84f562014-07-31 11:06:30 -0700576 """Create an empty cache image and store it in output_zip."""
577
Tao Bao886d8832018-02-27 11:46:19 -0800578 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "cache.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800579 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700580 logger.info("cache.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800581 return
582
Tao Bao2c15d9e2015-07-09 11:51:16 -0700583 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "cache")
Doug Zongker3c84f562014-07-31 11:06:30 -0700584 # The build system has to explicitly request for cache.img.
585 if "fs_type" not in image_props:
586 return
587
Tao Bao32fcdab2018-10-12 10:30:39 -0700588 logger.info("creating cache.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700589
Bryan Henrye6d547d2018-07-31 18:32:00 -0700590 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700591
Tao Bao1c830bf2017-12-25 10:43:47 -0800592 user_dir = common.MakeTempDir()
Tao Baoc6bd70a2018-09-27 16:58:00 -0700593 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700594
595 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800596 img.Write()
Doug Zongker3c84f562014-07-31 11:06:30 -0700597
598
Tao Bao5277d102018-04-17 23:47:21 -0700599def CheckAbOtaImages(output_zip, ab_partitions):
600 """Checks that all the listed A/B partitions have their images available.
Tao Baobea20ac2018-01-17 17:57:49 -0800601
Tao Bao5277d102018-04-17 23:47:21 -0700602 The images need to be available under IMAGES/ or RADIO/, with the former takes
603 a priority.
Tao Baobea20ac2018-01-17 17:57:49 -0800604
605 Args:
606 output_zip: The output zip file (needs to be already open), or None to
Tao Bao5277d102018-04-17 23:47:21 -0700607 find images in OPTIONS.input_tmp/.
Tao Baobea20ac2018-01-17 17:57:49 -0800608 ab_partitions: The list of A/B partitions.
609
610 Raises:
611 AssertionError: If it can't find an image.
612 """
613 for partition in ab_partitions:
Daniel Norman78554ea2021-09-14 10:29:38 -0700614 img_name = partition + ".img"
Tao Baobea20ac2018-01-17 17:57:49 -0800615
Tao Baoa2ff4c92018-01-17 12:14:43 -0800616 # Assert that the image is present under IMAGES/ now.
Tao Baobea20ac2018-01-17 17:57:49 -0800617 if output_zip:
618 # Zip spec says: All slashes MUST be forward slashes.
Tao Bao5277d102018-04-17 23:47:21 -0700619 images_path = "IMAGES/" + img_name
620 radio_path = "RADIO/" + img_name
621 available = (images_path in output_zip.namelist() or
622 radio_path in output_zip.namelist())
Tao Baobea20ac2018-01-17 17:57:49 -0800623 else:
Tao Bao5277d102018-04-17 23:47:21 -0700624 images_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
625 radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
626 available = os.path.exists(images_path) or os.path.exists(radio_path)
627
628 assert available, "Failed to find " + img_name
Tao Baobea20ac2018-01-17 17:57:49 -0800629
630
Tao Baobea20ac2018-01-17 17:57:49 -0800631def AddPackRadioImages(output_zip, images):
632 """Copies images listed in META/pack_radioimages.txt from RADIO/ to IMAGES/.
633
634 Args:
635 output_zip: The output zip file (needs to be already open), or None to
636 write images to OPTIONS.input_tmp/.
637 images: A list of image names.
638
639 Raises:
640 AssertionError: If a listed image can't be found.
641 """
642 for image in images:
643 img_name = image.strip()
644 _, ext = os.path.splitext(img_name)
645 if not ext:
646 img_name += ".img"
Tao Baoa2ff4c92018-01-17 12:14:43 -0800647
Tao Baobea20ac2018-01-17 17:57:49 -0800648 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
649 if os.path.exists(prebuilt_path):
Tao Bao32fcdab2018-10-12 10:30:39 -0700650 logger.info("%s already exists, no need to overwrite...", img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800651 continue
652
653 img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
654 assert os.path.exists(img_radio_path), \
655 "Failed to find %s at %s" % (img_name, img_radio_path)
Tao Baoa2ff4c92018-01-17 12:14:43 -0800656
Tao Baobea20ac2018-01-17 17:57:49 -0800657 if output_zip:
Tao Baoa2ff4c92018-01-17 12:14:43 -0800658 common.ZipWrite(output_zip, img_radio_path, "IMAGES/" + img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800659 else:
660 shutil.copy(img_radio_path, prebuilt_path)
661
662
David Anderson1ef03e22018-08-30 13:11:47 -0700663def AddSuperEmpty(output_zip):
664 """Create a super_empty.img and store it in output_zip."""
665
666 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "super_empty.img")
Yifan Hong055e6cf2018-11-29 13:51:48 -0800667 build_super_image.BuildSuperImage(OPTIONS.info_dict, img.name)
David Anderson1ef03e22018-08-30 13:11:47 -0700668 img.Write()
669
670
Yifan Hongc767f7c2018-11-08 15:41:24 -0800671def AddSuperSplit(output_zip):
672 """Create split super_*.img and store it in output_zip."""
673
Yifan Hong055e6cf2018-11-29 13:51:48 -0800674 outdir = os.path.join(OPTIONS.input_tmp, "OTA")
Yifan Honge98427a2018-12-07 10:08:27 -0800675 built = build_super_image.BuildSuperImage(OPTIONS.input_tmp, outdir)
Yifan Hongc767f7c2018-11-08 15:41:24 -0800676
Yifan Honge98427a2018-12-07 10:08:27 -0800677 if built:
678 for dev in OPTIONS.info_dict['super_block_devices'].strip().split():
679 img = OutputFile(output_zip, OPTIONS.input_tmp, "OTA",
680 "super_" + dev + ".img")
681 img.Write()
Yifan Hongc767f7c2018-11-08 15:41:24 -0800682
683
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700684def ReplaceUpdatedFiles(zip_filename, files_list):
Tao Bao89d7ab22017-12-14 17:05:33 -0800685 """Updates all the ZIP entries listed in files_list.
Tianjie Xu38af07f2017-05-25 17:38:53 -0700686
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700687 For now the list includes META/care_map.pb, and the related files under
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700688 SYSTEM/ after rebuilding recovery.
689 """
Tao Bao89d7ab22017-12-14 17:05:33 -0800690 common.ZipDelete(zip_filename, files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -0700691 output_zip = zipfile.ZipFile(zip_filename, "a",
692 compression=zipfile.ZIP_DEFLATED,
693 allowZip64=True)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700694 for item in files_list:
Tianjie Xu38af07f2017-05-25 17:38:53 -0700695 file_path = os.path.join(OPTIONS.input_tmp, item)
696 assert os.path.exists(file_path)
697 common.ZipWrite(output_zip, file_path, arcname=item)
698 common.ZipClose(output_zip)
699
700
Chris Gross435b8fe2020-09-15 09:53:44 -0700701def HasPartition(partition_name):
702 """Determines if the target files archive should build a given partition."""
703
704 return ((os.path.isdir(
705 os.path.join(OPTIONS.input_tmp, partition_name.upper())) and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800706 OPTIONS.info_dict.get(
707 "building_{}_image".format(partition_name)) == "true") or
708 os.path.exists(
709 os.path.join(OPTIONS.input_tmp, "IMAGES",
710 "{}.img".format(partition_name))))
Chris Gross435b8fe2020-09-15 09:53:44 -0700711
Tianjiea5fca032021-06-01 22:06:28 -0700712
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500713def AddApexInfo(output_zip):
Tianjiea5fca032021-06-01 22:06:28 -0700714 apex_infos = GetApexInfoFromTargetFiles(OPTIONS.input_tmp, 'system',
715 compressed_only=False)
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500716 apex_metadata_proto = ota_metadata_pb2.ApexMetadata()
717 apex_metadata_proto.apex_info.extend(apex_infos)
718 apex_info_bytes = apex_metadata_proto.SerializeToString()
719
720 output_file = os.path.join(OPTIONS.input_tmp, "META", "apex_info.pb")
721 with open(output_file, "wb") as ofile:
722 ofile.write(apex_info_bytes)
723 if output_zip:
724 arc_name = "META/apex_info.pb"
725 if arc_name in output_zip.namelist():
726 OPTIONS.replace_updated_files_list.append(arc_name)
727 else:
728 common.ZipWrite(output_zip, output_file, arc_name)
729
Chris Gross435b8fe2020-09-15 09:53:44 -0700730
Tianjiec3bf3d02021-07-14 15:56:37 -0700731def AddVbmetaDigest(output_zip):
732 """Write the vbmeta digest to the output dir and zipfile."""
733
734 # Calculate the vbmeta digest and put the result in to META/
735 boot_images = OPTIONS.info_dict.get("boot_images")
736 # Disable the digest calculation if the target_file is used as a container
Bowgo Tsaiaba5c9e2021-09-27 14:08:41 +0800737 # for boot images. A boot container might contain boot-5.4.img, boot-5.10.img
738 # etc., instead of just a boot.img and will fail in vbmeta digest calculation.
739 boot_container = boot_images and (
740 len(boot_images.split()) >= 2 or boot_images.split()[0] != 'boot.img')
Tianjiec3bf3d02021-07-14 15:56:37 -0700741 if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800742 OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"):
Tianjiec3bf3d02021-07-14 15:56:37 -0700743 avbtool = OPTIONS.info_dict["avb_avbtool"]
744 digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool)
745 vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META",
746 "vbmeta_digest.txt")
747 with open(vbmeta_digest_txt, 'w') as f:
748 f.write(digest)
749 # writes to the output zipfile
750 if output_zip:
751 arc_name = "META/vbmeta_digest.txt"
752 if arc_name in output_zip.namelist():
753 OPTIONS.replace_updated_files_list.append(arc_name)
754 else:
755 common.ZipWriteStr(output_zip, arc_name, digest)
756
757
Doug Zongker3c84f562014-07-31 11:06:30 -0700758def AddImagesToTargetFiles(filename):
Tao Baoae396d92017-11-20 11:56:43 -0800759 """Creates and adds images (boot/recovery/system/...) to a target_files.zip.
760
761 It works with either a zip file (zip mode), or a directory that contains the
762 files to be packed into a target_files.zip (dir mode). The latter is used when
763 being called from build/make/core/Makefile.
764
765 The images will be created under IMAGES/ in the input target_files.zip.
766
767 Args:
Tao Baodba59ee2018-01-09 13:21:02 -0800768 filename: the target_files.zip, or the zip root directory.
Tao Baoae396d92017-11-20 11:56:43 -0800769 """
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800770 if os.path.isdir(filename):
771 OPTIONS.input_tmp = os.path.abspath(filename)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800772 else:
Tao Baodba59ee2018-01-09 13:21:02 -0800773 OPTIONS.input_tmp = common.UnzipTemp(filename)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700774
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800775 if not OPTIONS.add_missing:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800776 if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")):
Tao Bao32fcdab2018-10-12 10:30:39 -0700777 logger.warning("target_files appears to already contain images.")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800778 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700779
Tao Bao410ad8b2018-08-24 12:08:38 -0700780 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True)
Tao Baodba59ee2018-01-09 13:21:02 -0800781
782 has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
Chris Grossa784ef12019-04-22 11:09:57 -0700783 has_boot = OPTIONS.info_dict.get("no_boot") != "true"
Devin Mooreafdd7c72021-12-13 22:04:08 +0000784 has_init_boot = OPTIONS.info_dict.get("init_boot") == "true"
Steve Mucklee1b10862019-07-10 10:49:37 -0700785 has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"
Lucas Weif57333f2022-02-24 10:30:15 +0800786 has_vendor_kernel_boot = OPTIONS.info_dict.get("vendor_kernel_boot") == "true"
Tao Baodba59ee2018-01-09 13:21:02 -0800787
Ramji Jiyani13a41372022-01-27 07:05:08 +0000788 # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system_dlkm, system, system_other}.img
Chris Gross435b8fe2020-09-15 09:53:44 -0700789 # can be built from source, or dropped into target_files.zip as a prebuilt blob.
790 has_vendor = HasPartition("vendor")
791 has_odm = HasPartition("odm")
792 has_vendor_dlkm = HasPartition("vendor_dlkm")
793 has_odm_dlkm = HasPartition("odm_dlkm")
Ramji Jiyani13a41372022-01-27 07:05:08 +0000794 has_system_dlkm = HasPartition("system_dlkm")
Chris Gross435b8fe2020-09-15 09:53:44 -0700795 has_product = HasPartition("product")
796 has_system_ext = HasPartition("system_ext")
797 has_system = HasPartition("system")
798 has_system_other = HasPartition("system_other")
Chris Gross203191b2020-05-30 02:39:12 +0000799 has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true"
800 has_cache = OPTIONS.info_dict.get("building_cache_image") == "true"
Doug Zongker3c84f562014-07-31 11:06:30 -0700801
Tao Baodba59ee2018-01-09 13:21:02 -0800802 # Set up the output destination. It writes to the given directory for dir
803 # mode; otherwise appends to the given ZIP.
804 if os.path.isdir(filename):
805 output_zip = None
806 else:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800807 output_zip = zipfile.ZipFile(filename, "a",
808 compression=zipfile.ZIP_DEFLATED,
809 allowZip64=True)
Tao Baoae396d92017-11-20 11:56:43 -0800810
811 # Always make input_tmp/IMAGES available, since we may stage boot / recovery
812 # images there even under zip mode. The directory will be cleaned up as part
813 # of OPTIONS.input_tmp.
814 images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES")
815 if not os.path.isdir(images_dir):
816 os.makedirs(images_dir)
Doug Zongker3c84f562014-07-31 11:06:30 -0700817
Tao Baobf70c312017-07-11 17:27:55 -0700818 # A map between partition names and their paths, which could be used when
819 # generating AVB vbmeta image.
Tao Bao3ed35d32019-10-07 20:48:48 -0700820 partitions = {}
Tao Baobf70c312017-07-11 17:27:55 -0700821
Doug Zongkerfc44a512014-08-26 13:10:25 -0700822 def banner(s):
Tao Baoa3705452019-06-24 15:33:41 -0700823 logger.info("\n\n++++ %s ++++\n\n", s)
Doug Zongker3c84f562014-07-31 11:06:30 -0700824
Chris Grossa784ef12019-04-22 11:09:57 -0700825 boot_image = None
Greg Kaisere086f722021-09-14 19:32:27 +0000826 if has_boot:
Chris Grossa784ef12019-04-22 11:09:57 -0700827 banner("boot")
Steve Muckle9793cf62020-04-08 18:27:00 -0700828 boot_images = OPTIONS.info_dict.get("boot_images")
829 if boot_images is None:
830 boot_images = "boot.img"
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800831 for index, b in enumerate(boot_images.split()):
Steve Muckle9793cf62020-04-08 18:27:00 -0700832 # common.GetBootableImage() returns the image directly if present.
833 boot_image = common.GetBootableImage(
834 "IMAGES/" + b, b, OPTIONS.input_tmp, "BOOT")
835 # boot.img may be unavailable in some targets (e.g. aosp_arm64).
836 if boot_image:
837 boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b)
Roopesh Nataraja3e15f6e2020-06-08 19:54:13 -0700838 # Although multiple boot images can be generated, include the image
839 # descriptor of only the first boot image in vbmeta
840 if index == 0:
Steve Muckle9793cf62020-04-08 18:27:00 -0700841 partitions['boot'] = boot_image_path
842 if not os.path.exists(boot_image_path):
843 boot_image.WriteToDir(OPTIONS.input_tmp)
844 if output_zip:
845 boot_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -0700846
Devin Mooreafdd7c72021-12-13 22:04:08 +0000847 if has_init_boot:
848 banner("init_boot")
849 init_boot_image = common.GetBootableImage(
850 "IMAGES/init_boot.img", "init_boot.img", OPTIONS.input_tmp, "INIT_BOOT")
851 if init_boot_image:
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800852 partitions['init_boot'] = os.path.join(
853 OPTIONS.input_tmp, "IMAGES", "init_boot.img")
Devin Mooreafdd7c72021-12-13 22:04:08 +0000854 if not os.path.exists(partitions['init_boot']):
855 init_boot_image.WriteToDir(OPTIONS.input_tmp)
856 if output_zip:
857 init_boot_image.AddToZip(output_zip)
858
Greg Kaisere086f722021-09-14 19:32:27 +0000859 if has_vendor_boot:
Steve Mucklee1b10862019-07-10 10:49:37 -0700860 banner("vendor_boot")
861 vendor_boot_image = common.GetVendorBootImage(
862 "IMAGES/vendor_boot.img", "vendor_boot.img", OPTIONS.input_tmp,
863 "VENDOR_BOOT")
864 if vendor_boot_image:
865 partitions['vendor_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
866 "vendor_boot.img")
867 if not os.path.exists(partitions['vendor_boot']):
868 vendor_boot_image.WriteToDir(OPTIONS.input_tmp)
869 if output_zip:
870 vendor_boot_image.AddToZip(output_zip)
871
Lucas Weif57333f2022-02-24 10:30:15 +0800872 if has_vendor_kernel_boot:
873 banner("vendor_kernel_boot")
874 vendor_kernel_boot_image = common.GetVendorBootImage(
875 "IMAGES/vendor_kernel_boot.img", "vendor_kernel_boot.img", OPTIONS.input_tmp,
876 "VENDOR_KERNEL_BOOT")
877 if vendor_kernel_boot_image:
878 partitions['vendor_kernel_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
879 "vendor_kernel_boot.img")
880 if not os.path.exists(partitions['vendor_kernel_boot']):
881 vendor_kernel_boot_image.WriteToDir(OPTIONS.input_tmp)
882 if output_zip:
883 vendor_kernel_boot_image.AddToZip(output_zip)
884
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800885 recovery_image = None
Greg Kaisere086f722021-09-14 19:32:27 +0000886 if has_recovery:
Tao Baodb45efa2015-10-27 19:25:18 -0700887 banner("recovery")
Tao Bao262bf3f2017-07-11 17:27:55 -0700888 recovery_image = common.GetBootableImage(
889 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
890 assert recovery_image, "Failed to create recovery.img."
Tao Baobf70c312017-07-11 17:27:55 -0700891 partitions['recovery'] = os.path.join(
Tao Bao262bf3f2017-07-11 17:27:55 -0700892 OPTIONS.input_tmp, "IMAGES", "recovery.img")
Tao Baobf70c312017-07-11 17:27:55 -0700893 if not os.path.exists(partitions['recovery']):
Tao Bao262bf3f2017-07-11 17:27:55 -0700894 recovery_image.WriteToDir(OPTIONS.input_tmp)
895 if output_zip:
896 recovery_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -0700897
Tao Baod42e97e2016-11-30 12:11:57 -0800898 banner("recovery (two-step image)")
899 # The special recovery.img for two-step package use.
900 recovery_two_step_image = common.GetBootableImage(
Tao Bao04808502019-07-25 23:11:41 -0700901 "OTA/recovery-two-step.img", "recovery-two-step.img",
Tao Baod42e97e2016-11-30 12:11:57 -0800902 OPTIONS.input_tmp, "RECOVERY", two_step_image=True)
Tao Bao262bf3f2017-07-11 17:27:55 -0700903 assert recovery_two_step_image, "Failed to create recovery-two-step.img."
904 recovery_two_step_image_path = os.path.join(
Tao Bao04808502019-07-25 23:11:41 -0700905 OPTIONS.input_tmp, "OTA", "recovery-two-step.img")
Tao Bao262bf3f2017-07-11 17:27:55 -0700906 if not os.path.exists(recovery_two_step_image_path):
907 recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800908 if output_zip:
909 recovery_two_step_image.AddToZip(output_zip)
Tao Baod42e97e2016-11-30 12:11:57 -0800910
Daniel Norman78554ea2021-09-14 10:29:38 -0700911 def add_partition(partition, has_partition, add_func, add_args):
912 if has_partition:
913 banner(partition)
914 partitions[partition] = add_func(output_zip, *add_args)
Tao Baobf70c312017-07-11 17:27:55 -0700915
Daniel Norman78554ea2021-09-14 10:29:38 -0700916 add_partition_calls = (
917 ("system", has_system, AddSystem, [recovery_image, boot_image]),
918 ("vendor", has_vendor, AddVendor, [recovery_image, boot_image]),
919 ("product", has_product, AddProduct, []),
920 ("system_ext", has_system_ext, AddSystemExt, []),
921 ("odm", has_odm, AddOdm, []),
922 ("vendor_dlkm", has_vendor_dlkm, AddVendorDlkm, []),
923 ("odm_dlkm", has_odm_dlkm, AddOdmDlkm, []),
Ramji Jiyani13a41372022-01-27 07:05:08 +0000924 ("system_dlkm", has_system_dlkm, AddSystemDlkm, []),
Daniel Norman78554ea2021-09-14 10:29:38 -0700925 ("system_other", has_system_other, AddSystemOther, []),
926 )
927 for call in add_partition_calls:
928 add_partition(*call)
Tao Baobf70c312017-07-11 17:27:55 -0700929
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500930 AddApexInfo(output_zip)
931
Tianjie Xub48589a2016-08-03 19:21:52 -0700932 if not OPTIONS.is_signing:
Greg Kaisere086f722021-09-14 19:32:27 +0000933 banner("userdata")
934 AddUserdata(output_zip)
935 banner("cache")
936 AddCache(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -0700937
938 if OPTIONS.info_dict.get("board_bpt_enable") == "true":
David Zeuthen25328622016-04-08 15:08:03 -0400939 banner("partition-table")
940 AddPartitionTable(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -0700941
Daniel Norman78554ea2021-09-14 10:29:38 -0700942 add_partition("dtbo",
943 OPTIONS.info_dict.get("has_dtbo") == "true", AddDtbo, [])
944 add_partition("pvmfw",
945 OPTIONS.info_dict.get("has_pvmfw") == "true", AddPvmfw, [])
Andrew Sculle077cf72021-02-18 10:27:29 +0000946
Hongguang Chenf23364d2020-04-27 18:36:36 -0700947 # Custom images.
948 custom_partitions = OPTIONS.info_dict.get(
949 "avb_custom_images_partition_list", "").strip().split()
950 for partition_name in custom_partitions:
951 partition_name = partition_name.strip()
952 banner("custom images for " + partition_name)
953 partitions[partition_name] = AddCustomImages(output_zip, partition_name)
954
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800955 if OPTIONS.info_dict.get("avb_enable") == "true":
Tao Bao744c4c72018-08-20 21:09:07 -0700956 # vbmeta_partitions includes the partitions that should be included into
957 # top-level vbmeta.img, which are the ones that are not included in any
958 # chained VBMeta image plus the chained VBMeta images themselves.
Hongguang Chenf23364d2020-04-27 18:36:36 -0700959 # Currently custom_partitions are all chained to VBMeta image.
960 vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)
Tao Bao744c4c72018-08-20 21:09:07 -0700961
David Anderson7709ab22018-10-15 14:41:34 -0700962 vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +0000963 if vbmeta_system:
David Anderson7709ab22018-10-15 14:41:34 -0700964 banner("vbmeta_system")
Tao Bao71064202018-10-22 15:08:02 -0700965 partitions["vbmeta_system"] = AddVBMeta(
David Anderson7709ab22018-10-15 14:41:34 -0700966 output_zip, partitions, "vbmeta_system", vbmeta_system.split())
Tao Bao744c4c72018-08-20 21:09:07 -0700967 vbmeta_partitions = [
968 item for item in vbmeta_partitions
David Anderson7709ab22018-10-15 14:41:34 -0700969 if item not in vbmeta_system.split()]
970 vbmeta_partitions.append("vbmeta_system")
Tao Bao744c4c72018-08-20 21:09:07 -0700971
972 vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +0000973 if vbmeta_vendor:
Tao Bao744c4c72018-08-20 21:09:07 -0700974 banner("vbmeta_vendor")
Tao Bao71064202018-10-22 15:08:02 -0700975 partitions["vbmeta_vendor"] = AddVBMeta(
Tao Bao744c4c72018-08-20 21:09:07 -0700976 output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
977 vbmeta_partitions = [
978 item for item in vbmeta_partitions
979 if item not in vbmeta_vendor.split()]
980 vbmeta_partitions.append("vbmeta_vendor")
981
Greg Kaisere086f722021-09-14 19:32:27 +0000982 if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
Bowgo Tsai82182252020-11-13 11:28:17 +0800983 banner("vbmeta")
984 AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
Doug Zongker3c84f562014-07-31 11:06:30 -0700985
Tao Bao48a2feb2019-06-28 11:00:05 -0700986 if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
Greg Kaisere086f722021-09-14 19:32:27 +0000987 if OPTIONS.info_dict.get("build_super_empty_partition") == "true":
Yo Chiange86bab42021-03-25 10:12:28 +0000988 banner("super_empty")
989 AddSuperEmpty(output_zip)
David Anderson1ef03e22018-08-30 13:11:47 -0700990
Greg Kaisere086f722021-09-14 19:32:27 +0000991 if OPTIONS.info_dict.get("build_super_partition") == "true":
Tao Bao519d1822018-12-27 12:47:23 -0800992 if OPTIONS.info_dict.get(
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800993 "build_retrofit_dynamic_partitions_ota_package") == "true":
Yifan Hongc767f7c2018-11-08 15:41:24 -0800994 banner("super split images")
995 AddSuperSplit(output_zip)
Yifan Hongc767f7c2018-11-08 15:41:24 -0800996
Tianjie Xuaaca4212016-06-28 14:34:03 -0700997 banner("radio")
Tao Baobea20ac2018-01-17 17:57:49 -0800998 ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META",
999 "ab_partitions.txt")
1000 if os.path.exists(ab_partitions_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001001 with open(ab_partitions_txt) as f:
Daniel Norman78554ea2021-09-14 10:29:38 -07001002 ab_partitions = f.read().splitlines()
Tianjie Xucfa86222016-03-07 16:31:19 -08001003
Greg Kaisere086f722021-09-14 19:32:27 +00001004 # For devices using A/B update, make sure we have all the needed images
1005 # ready under IMAGES/ or RADIO/.
1006 CheckAbOtaImages(output_zip, ab_partitions)
Tianjie Xuaaca4212016-06-28 14:34:03 -07001007
Greg Kaisere086f722021-09-14 19:32:27 +00001008 # Generate care_map.pb for ab_partitions, then write this file to
1009 # target_files package.
1010 output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb")
1011 AddCareMapForAbOta(output_zip if output_zip else output_care_map,
1012 ab_partitions, partitions)
Tianjie Xucfa86222016-03-07 16:31:19 -08001013
Tao Bao95a95c32017-06-16 15:30:23 -07001014 # Radio images that need to be packed into IMAGES/, and product-img.zip.
Tao Baobea20ac2018-01-17 17:57:49 -08001015 pack_radioimages_txt = os.path.join(
Tao Bao95a95c32017-06-16 15:30:23 -07001016 OPTIONS.input_tmp, "META", "pack_radioimages.txt")
Tao Baobea20ac2018-01-17 17:57:49 -08001017 if os.path.exists(pack_radioimages_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001018 with open(pack_radioimages_txt) as f:
Tao Baobea20ac2018-01-17 17:57:49 -08001019 AddPackRadioImages(output_zip, f.readlines())
Tao Bao95a95c32017-06-16 15:30:23 -07001020
Greg Kaisere086f722021-09-14 19:32:27 +00001021 AddVbmetaDigest(output_zip)
Tianjiebbde59f2021-05-03 21:18:56 -07001022
Dan Willemsen2ee00d52017-03-05 19:51:56 -08001023 if output_zip:
1024 common.ZipClose(output_zip)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -07001025 if OPTIONS.replace_updated_files_list:
1026 ReplaceUpdatedFiles(output_zip.filename,
1027 OPTIONS.replace_updated_files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -07001028
Doug Zongker3c84f562014-07-31 11:06:30 -07001029
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001030def OptimizeCompressedEntries(zipfile_path):
1031 """Convert files that do not compress well to uncompressed storage
1032
1033 EROFS images tend to be compressed already, so compressing them again
1034 yields little space savings. Leaving them uncompressed will make
1035 downstream tooling's job easier, and save compute time.
1036 """
1037 if not zipfile.is_zipfile(zipfile_path):
1038 return
1039 entries_to_store = []
1040 with tempfile.TemporaryDirectory() as tmpdir:
1041 with zipfile.ZipFile(zipfile_path, "r", allowZip64=True) as zfp:
1042 for zinfo in zfp.filelist:
1043 if not zinfo.filename.startswith("IMAGES/") and not zinfo.filename.startswith("META"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001044 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001045 # Don't try to store userdata.img uncompressed, it's usually huge.
1046 if zinfo.filename.endswith("userdata.img"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001047 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001048 if zinfo.compress_size > zinfo.file_size * 0.80 and zinfo.compress_type != zipfile.ZIP_STORED:
1049 entries_to_store.append(zinfo)
1050 zfp.extract(zinfo, tmpdir)
Kelvin Zhang70876142022-02-09 16:05:29 -08001051 if len(entries_to_store) == 0:
1052 return
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001053 # Remove these entries, then re-add them as ZIP_STORED
Kelvin Zhang70876142022-02-09 16:05:29 -08001054 ZipDelete(zipfile_path, [entry.filename for entry in entries_to_store])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001055 with zipfile.ZipFile(zipfile_path, "a", allowZip64=True) as zfp:
1056 for entry in entries_to_store:
1057 zfp.write(os.path.join(tmpdir, entry.filename), entry.filename, compress_type=zipfile.ZIP_STORED)
1058
1059
Doug Zongker3c84f562014-07-31 11:06:30 -07001060def main(argv):
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001061 def option_handler(o, a):
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001062 if o in ("-a", "--add_missing"):
1063 OPTIONS.add_missing = True
1064 elif o in ("-r", "--rebuild_recovery",):
1065 OPTIONS.rebuild_recovery = True
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001066 elif o == "--replace_verity_private_key":
1067 OPTIONS.replace_verity_private_key = (True, a)
1068 elif o == "--replace_verity_public_key":
1069 OPTIONS.replace_verity_public_key = (True, a)
Tianjie Xub48589a2016-08-03 19:21:52 -07001070 elif o == "--is_signing":
1071 OPTIONS.is_signing = True
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001072 else:
1073 return False
1074 return True
1075
Dan Albert8b72aef2015-03-23 19:13:21 -07001076 args = common.ParseOptions(
1077 argv, __doc__, extra_opts="ar",
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001078 extra_long_opts=["add_missing", "rebuild_recovery",
1079 "replace_verity_public_key=",
1080 "replace_verity_private_key=",
Greg Kaisere086f722021-09-14 19:32:27 +00001081 "is_signing"],
Dan Albert8b72aef2015-03-23 19:13:21 -07001082 extra_option_handler=option_handler)
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001083
Doug Zongker3c84f562014-07-31 11:06:30 -07001084 if len(args) != 1:
1085 common.Usage(__doc__)
1086 sys.exit(1)
1087
Tao Bao32fcdab2018-10-12 10:30:39 -07001088 common.InitLogging()
1089
Doug Zongker3c84f562014-07-31 11:06:30 -07001090 AddImagesToTargetFiles(args[0])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001091 OptimizeCompressedEntries(args[0])
Tao Bao32fcdab2018-10-12 10:30:39 -07001092 logger.info("done.")
Doug Zongker3c84f562014-07-31 11:06:30 -07001093
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001094
Doug Zongker3c84f562014-07-31 11:06:30 -07001095if __name__ == '__main__':
1096 try:
1097 common.CloseInheritedPipes()
1098 main(sys.argv[1:])
Doug Zongkerfc44a512014-08-26 13:10:25 -07001099 finally:
1100 common.Cleanup()