blob: b1772663a9e9dce2d6c26500b1ad7b7c352046fc [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 Zhangf294c872022-10-06 14:21:36 -070067from common import ZipDelete, PARTITIONS_WITH_CARE_MAP, ExternalError, RunAndCheckOutput, MakeTempFile, ZipWrite
68import rangelib
69import sparse_img
Doug Zongker3c84f562014-07-31 11:06:30 -070070
Tao Bao6b9fef52017-12-01 16:13:22 -080071if sys.hexversion < 0x02070000:
72 print("Python 2.7 or newer is required.", file=sys.stderr)
73 sys.exit(1)
74
Tao Bao32fcdab2018-10-12 10:30:39 -070075logger = logging.getLogger(__name__)
Doug Zongker3c84f562014-07-31 11:06:30 -070076
Tao Bao32fcdab2018-10-12 10:30:39 -070077OPTIONS = common.OPTIONS
Michael Runge2e0d8fc2014-11-13 21:41:08 -080078OPTIONS.add_missing = False
79OPTIONS.rebuild_recovery = False
Tianjie Xu9ac4cb02017-06-09 16:58:03 -070080OPTIONS.replace_updated_files_list = []
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
Kelvin Zhangf294c872022-10-06 14:21:36 -070090def GetCareMap(which, imgname):
91 """Returns the care_map string for the given partition.
92
93 Args:
94 which: The partition name, must be listed in PARTITIONS_WITH_CARE_MAP.
95 imgname: The filename of the image.
96
97 Returns:
98 (which, care_map_ranges): care_map_ranges is the raw string of the care_map
99 RangeSet; or None.
100 """
101 assert which in PARTITIONS_WITH_CARE_MAP
102
103 # which + "_image_size" contains the size that the actual filesystem image
104 # resides in, which is all that needs to be verified. The additional blocks in
105 # the image file contain verity metadata, by reading which would trigger
106 # invalid reads.
107 image_size = OPTIONS.info_dict.get(which + "_image_size")
108 if not image_size:
109 return None
110
111 disable_sparse = OPTIONS.info_dict.get(which + "_disable_sparse")
112
113 image_blocks = int(image_size) // 4096 - 1
114 # It's OK for image_blocks to be 0, because care map ranges are inclusive.
115 # So 0-0 means "just block 0", which is valid.
116 assert image_blocks >= 0, "blocks for {} must be non-negative, image size: {}".format(
117 which, image_size)
118
119 # For sparse images, we will only check the blocks that are listed in the care
120 # map, i.e. the ones with meaningful data.
121 if "extfs_sparse_flag" in OPTIONS.info_dict and not disable_sparse:
122 simg = sparse_img.SparseImage(imgname)
123 care_map_ranges = simg.care_map.intersect(
124 rangelib.RangeSet("0-{}".format(image_blocks)))
125
126 # Otherwise for non-sparse images, we read all the blocks in the filesystem
127 # image.
128 else:
129 care_map_ranges = rangelib.RangeSet("0-{}".format(image_blocks))
130
131 return [which, care_map_ranges.to_string_raw()]
132
133
134def AddCareMapForAbOta(output_file, ab_partitions, image_paths):
135 """Generates and adds care_map.pb for a/b partition that has care_map.
136
137 Args:
138 output_file: The output zip file (needs to be already open),
139 or file path to write care_map.pb.
140 ab_partitions: The list of A/B partitions.
141 image_paths: A map from the partition name to the image path.
142 """
143 if not output_file:
144 raise ExternalError('Expected output_file for AddCareMapForAbOta')
145
146 care_map_list = []
147 for partition in ab_partitions:
148 partition = partition.strip()
149 if partition not in PARTITIONS_WITH_CARE_MAP:
150 continue
151
152 verity_block_device = "{}_verity_block_device".format(partition)
153 avb_hashtree_enable = "avb_{}_hashtree_enable".format(partition)
154 if (verity_block_device in OPTIONS.info_dict or
155 OPTIONS.info_dict.get(avb_hashtree_enable) == "true"):
156 if partition not in image_paths:
157 logger.warning('Potential partition with care_map missing from images: %s',
158 partition)
159 continue
160 image_path = image_paths[partition]
161 if not os.path.exists(image_path):
162 raise ExternalError('Expected image at path {}'.format(image_path))
163
164 care_map = GetCareMap(partition, image_path)
165 if not care_map:
166 continue
167 care_map_list += care_map
168
169 # adds fingerprint field to the care_map
170 # TODO(xunchang) revisit the fingerprint calculation for care_map.
171 partition_props = OPTIONS.info_dict.get(partition + ".build.prop")
172 prop_name_list = ["ro.{}.build.fingerprint".format(partition),
173 "ro.{}.build.thumbprint".format(partition)]
174
175 present_props = [x for x in prop_name_list if
176 partition_props and partition_props.GetProp(x)]
177 if not present_props:
178 logger.warning(
179 "fingerprint is not present for partition %s", partition)
180 property_id, fingerprint = "unknown", "unknown"
181 else:
182 property_id = present_props[0]
183 fingerprint = partition_props.GetProp(property_id)
184 care_map_list += [property_id, fingerprint]
185
186 if not care_map_list:
187 return
188
189 # Converts the list into proto buf message by calling care_map_generator; and
190 # writes the result to a temp file.
191 temp_care_map_text = MakeTempFile(prefix="caremap_text-",
192 suffix=".txt")
193 with open(temp_care_map_text, 'w') as text_file:
194 text_file.write('\n'.join(care_map_list))
195
196 temp_care_map = MakeTempFile(prefix="caremap-", suffix=".pb")
197 care_map_gen_cmd = ["care_map_generator", temp_care_map_text, temp_care_map]
198 RunAndCheckOutput(care_map_gen_cmd)
199
200 if not isinstance(output_file, zipfile.ZipFile):
201 shutil.copy(temp_care_map, output_file)
202 return
203 # output_file is a zip file
204 care_map_path = "META/care_map.pb"
205 if care_map_path in output_file.namelist():
206 # Copy the temp file into the OPTIONS.input_tmp dir and update the
207 # replace_updated_files_list used by add_img_to_target_files
208 if not OPTIONS.replace_updated_files_list:
209 OPTIONS.replace_updated_files_list = []
210 shutil.copy(temp_care_map, os.path.join(OPTIONS.input_tmp, care_map_path))
211 OPTIONS.replace_updated_files_list.append(care_map_path)
212 else:
213 ZipWrite(output_file, temp_care_map, arcname=care_map_path)
214
215
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800216class OutputFile(object):
Tao Bao93e7ebe2019-01-13 23:23:01 -0800217 """A helper class to write a generated file to the given dir or zip.
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800218
Tao Bao93e7ebe2019-01-13 23:23:01 -0800219 When generating images, we want the outputs to go into the given zip file, or
220 the given dir.
221
222 Attributes:
223 name: The name of the output file, regardless of the final destination.
224 """
225
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500226 def __init__(self, output_zip, input_dir, *args):
Tao Bao93e7ebe2019-01-13 23:23:01 -0800227 # We write the intermediate output file under the given input_dir, even if
228 # the final destination is a zip archive.
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500229 self.name = os.path.join(input_dir, *args)
Tao Bao93e7ebe2019-01-13 23:23:01 -0800230 self._output_zip = output_zip
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800231 if self._output_zip:
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500232 self._zip_name = os.path.join(*args)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800233
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800234 def Write(self, compress_type=None):
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800235 if self._output_zip:
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800236 common.ZipWrite(self._output_zip, self.name,
237 self._zip_name, compress_type=compress_type)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800238
Tao Baoe30a6a62018-08-27 10:57:19 -0700239
Tao Bao886d8832018-02-27 11:46:19 -0800240def AddSystem(output_zip, recovery_img=None, boot_img=None):
Doug Zongker3c84f562014-07-31 11:06:30 -0700241 """Turn the contents of SYSTEM into a system image and store it in
David Zeuthend995f4b2016-01-29 16:59:17 -0500242 output_zip. Returns the name of the system image file."""
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800243
Tao Bao886d8832018-02-27 11:46:19 -0800244 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800245 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700246 logger.info("system.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800247 return img.name
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800248
249 def output_sink(fn, data):
Tao Baoa3705452019-06-24 15:33:41 -0700250 output_file = os.path.join(OPTIONS.input_tmp, "SYSTEM", fn)
251 with open(output_file, "wb") as ofile:
252 ofile.write(data)
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800253
Daniel Normana4911da2019-03-15 14:36:21 -0700254 if output_zip:
255 arc_name = "SYSTEM/" + fn
256 if arc_name in output_zip.namelist():
257 OPTIONS.replace_updated_files_list.append(arc_name)
258 else:
Tao Baoa3705452019-06-24 15:33:41 -0700259 common.ZipWrite(output_zip, output_file, arc_name)
Tianjie Xu38af07f2017-05-25 17:38:53 -0700260
Bill Peckhame868aec2019-09-17 17:06:47 -0700261 board_uses_vendorimage = OPTIONS.info_dict.get(
262 "board_uses_vendorimage") == "true"
263
264 if (OPTIONS.rebuild_recovery and not board_uses_vendorimage and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800265 recovery_img is not None and boot_img is not None):
Bill Peckhame868aec2019-09-17 17:06:47 -0700266 logger.info("Building new recovery patch on system at system/vendor")
Dan Albert8b72aef2015-03-23 19:13:21 -0700267 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
268 boot_img, info_dict=OPTIONS.info_dict)
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800269
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800270 block_list = OutputFile(output_zip, OPTIONS.input_tmp,
271 "IMAGES", "system.map")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800272 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system", img,
273 block_list=block_list)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800274 return img.name
Doug Zongkerfc44a512014-08-26 13:10:25 -0700275
276
Tao Bao886d8832018-02-27 11:46:19 -0800277def AddSystemOther(output_zip):
Alex Light4e358ab2016-06-16 14:47:10 -0700278 """Turn the contents of SYSTEM_OTHER into a system_other image
279 and store it in output_zip."""
280
Tao Bao886d8832018-02-27 11:46:19 -0800281 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system_other.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800282 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700283 logger.info("system_other.img already exists; no need to rebuild...")
Alex Light4e358ab2016-06-16 14:47:10 -0700284 return
285
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800286 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "system_other", img)
Alex Light4e358ab2016-06-16 14:47:10 -0700287
288
Bill Peckhame868aec2019-09-17 17:06:47 -0700289def AddVendor(output_zip, recovery_img=None, boot_img=None):
Doug Zongkerfc44a512014-08-26 13:10:25 -0700290 """Turn the contents of VENDOR into a vendor image and store in it
291 output_zip."""
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800292
Tao Bao886d8832018-02-27 11:46:19 -0800293 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800294 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700295 logger.info("vendor.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800296 return img.name
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800297
Bill Peckhame868aec2019-09-17 17:06:47 -0700298 def output_sink(fn, data):
Iavor-Valentin Iftime756b5612022-02-09 15:56:14 +0000299 output_file = os.path.join(OPTIONS.input_tmp, "VENDOR", fn)
300 with open(output_file, "wb") as ofile:
301 ofile.write(data)
Bill Peckhame868aec2019-09-17 17:06:47 -0700302
303 if output_zip:
304 arc_name = "VENDOR/" + fn
305 if arc_name in output_zip.namelist():
306 OPTIONS.replace_updated_files_list.append(arc_name)
307 else:
Iavor-Valentin Iftime756b5612022-02-09 15:56:14 +0000308 common.ZipWrite(output_zip, output_file, arc_name)
Bill Peckhame868aec2019-09-17 17:06:47 -0700309
310 board_uses_vendorimage = OPTIONS.info_dict.get(
311 "board_uses_vendorimage") == "true"
312
313 if (OPTIONS.rebuild_recovery and board_uses_vendorimage and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800314 recovery_img is not None and boot_img is not None):
Bill Peckhame868aec2019-09-17 17:06:47 -0700315 logger.info("Building new recovery patch on vendor")
316 common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img,
317 boot_img, info_dict=OPTIONS.info_dict)
318
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800319 block_list = OutputFile(output_zip, OPTIONS.input_tmp,
320 "IMAGES", "vendor.map")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800321 CreateImage(OPTIONS.input_tmp, OPTIONS.info_dict, "vendor", img,
322 block_list=block_list)
323 return img.name
Doug Zongker3c84f562014-07-31 11:06:30 -0700324
Yueyao Zhu889ee5e2017-05-12 17:50:46 -0700325
Tao Bao886d8832018-02-27 11:46:19 -0800326def AddProduct(output_zip):
327 """Turn the contents of PRODUCT into a product image and store it in
328 output_zip."""
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900329
Tao Bao886d8832018-02-27 11:46:19 -0800330 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "product.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800331 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700332 logger.info("product.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800333 return img.name
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900334
Tao Bao886d8832018-02-27 11:46:19 -0800335 block_list = OutputFile(
336 output_zip, OPTIONS.input_tmp, "IMAGES", "product.map")
337 CreateImage(
338 OPTIONS.input_tmp, OPTIONS.info_dict, "product", img,
339 block_list=block_list)
Jaekyun Seokb7735d82017-11-27 17:04:47 +0900340 return img.name
341
342
Justin Yun6151e3f2019-06-25 15:58:13 +0900343def AddSystemExt(output_zip):
344 """Turn the contents of SYSTEM_EXT into a system_ext image and store it in
345 output_zip."""
Dario Freni5f681e12018-05-29 13:09:01 +0100346
347 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES",
Justin Yun6151e3f2019-06-25 15:58:13 +0900348 "system_ext.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800349 if os.path.exists(img.name):
Justin Yun6151e3f2019-06-25 15:58:13 +0900350 logger.info("system_ext.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800351 return img.name
Dario Freni5f681e12018-05-29 13:09:01 +0100352
353 block_list = OutputFile(
Justin Yun6151e3f2019-06-25 15:58:13 +0900354 output_zip, OPTIONS.input_tmp, "IMAGES", "system_ext.map")
Dario Freni5f681e12018-05-29 13:09:01 +0100355 CreateImage(
Justin Yun6151e3f2019-06-25 15:58:13 +0900356 OPTIONS.input_tmp, OPTIONS.info_dict, "system_ext", img,
Dario Freni5f681e12018-05-29 13:09:01 +0100357 block_list=block_list)
358 return img.name
359
360
Bowgo Tsaid624fa62017-11-14 23:42:30 +0800361def AddOdm(output_zip):
362 """Turn the contents of ODM into an odm image and store it in output_zip."""
363
364 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "odm.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800365 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700366 logger.info("odm.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800367 return img.name
Bowgo Tsaid624fa62017-11-14 23:42:30 +0800368
369 block_list = OutputFile(
370 output_zip, OPTIONS.input_tmp, "IMAGES", "odm.map")
371 CreateImage(
372 OPTIONS.input_tmp, OPTIONS.info_dict, "odm", img,
373 block_list=block_list)
374 return img.name
375
376
Yifan Hongcfb917a2020-05-07 14:58:20 -0700377def AddVendorDlkm(output_zip):
378 """Turn the contents of VENDOR_DLKM into an vendor_dlkm image and store it in output_zip."""
379
380 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.img")
381 if os.path.exists(img.name):
382 logger.info("vendor_dlkm.img already exists; no need to rebuild...")
383 return img.name
384
385 block_list = OutputFile(
386 output_zip, OPTIONS.input_tmp, "IMAGES", "vendor_dlkm.map")
387 CreateImage(
388 OPTIONS.input_tmp, OPTIONS.info_dict, "vendor_dlkm", img,
389 block_list=block_list)
390 return img.name
391
Tianjiebbde59f2021-05-03 21:18:56 -0700392
Yifan Hongf496f1b2020-07-15 16:52:59 -0700393def AddOdmDlkm(output_zip):
394 """Turn the contents of OdmDlkm into an odm_dlkm image and store it in output_zip."""
395
396 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.img")
397 if os.path.exists(img.name):
398 logger.info("odm_dlkm.img already exists; no need to rebuild...")
399 return img.name
400
401 block_list = OutputFile(
402 output_zip, OPTIONS.input_tmp, "IMAGES", "odm_dlkm.map")
403 CreateImage(
404 OPTIONS.input_tmp, OPTIONS.info_dict, "odm_dlkm", img,
405 block_list=block_list)
406 return img.name
407
Kelvin Zhangf294c872022-10-06 14:21:36 -0700408
Ramji Jiyani13a41372022-01-27 07:05:08 +0000409def AddSystemDlkm(output_zip):
410 """Turn the contents of SystemDlkm into an system_dlkm image and store it in output_zip."""
411
412 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "system_dlkm.img")
413 if os.path.exists(img.name):
414 logger.info("system_dlkm.img already exists; no need to rebuild...")
415 return img.name
416
417 block_list = OutputFile(
418 output_zip, OPTIONS.input_tmp, "IMAGES", "system_dlkm.map")
419 CreateImage(
420 OPTIONS.input_tmp, OPTIONS.info_dict, "system_dlkm", img,
421 block_list=block_list)
422 return img.name
423
Yifan Hongcfb917a2020-05-07 14:58:20 -0700424
Tao Bao886d8832018-02-27 11:46:19 -0800425def AddDtbo(output_zip):
Tao Baoc633ed02017-05-30 21:46:33 -0700426 """Adds the DTBO image.
427
Tao Bao886d8832018-02-27 11:46:19 -0800428 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
Tao Baoc633ed02017-05-30 21:46:33 -0700429 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
430 """
Tao Bao886d8832018-02-27 11:46:19 -0800431 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "dtbo.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800432 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700433 logger.info("dtbo.img already exists; no need to rebuild...")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800434 return img.name
Tao Baoc633ed02017-05-30 21:46:33 -0700435
436 dtbo_prebuilt_path = os.path.join(
437 OPTIONS.input_tmp, "PREBUILT_IMAGES", "dtbo.img")
438 assert os.path.exists(dtbo_prebuilt_path)
439 shutil.copy(dtbo_prebuilt_path, img.name)
440
441 # AVB-sign the image as needed.
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800442 if OPTIONS.info_dict.get("avb_enable") == "true":
Rupert Shuttleworth72942742020-12-08 06:18:35 +0000443 # Signing requires +w
444 os.chmod(img.name, os.stat(img.name).st_mode | stat.S_IWUSR)
445
Tao Baof88e0ce2019-03-18 14:01:38 -0700446 avbtool = OPTIONS.info_dict["avb_avbtool"]
Tao Bao3ebfdde2017-05-23 23:06:55 -0700447 part_size = OPTIONS.info_dict["dtbo_size"]
Tao Baoc633ed02017-05-30 21:46:33 -0700448 # The AVB hash footer will be replaced if already present.
449 cmd = [avbtool, "add_hash_footer", "--image", img.name,
450 "--partition_size", str(part_size), "--partition_name", "dtbo"]
Bowgo Tsai3e599ea2017-05-26 18:30:04 +0800451 common.AppendAVBSigningArgs(cmd, "dtbo")
452 args = OPTIONS.info_dict.get("avb_dtbo_add_hash_footer_args")
Tao Baoc633ed02017-05-30 21:46:33 -0700453 if args and args.strip():
454 cmd.extend(shlex.split(args))
Tao Bao2764aee2018-11-21 11:02:48 -0800455 common.RunAndCheckOutput(cmd)
Tao Baoc633ed02017-05-30 21:46:33 -0700456
457 img.Write()
458 return img.name
459
Tianjiebbde59f2021-05-03 21:18:56 -0700460
Andrew Sculle077cf72021-02-18 10:27:29 +0000461def AddPvmfw(output_zip):
462 """Adds the pvmfw image.
463
464 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
465 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
466 """
467 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "pvmfw.img")
468 if os.path.exists(img.name):
469 logger.info("pvmfw.img already exists; no need to rebuild...")
470 return img.name
471
472 pvmfw_prebuilt_path = os.path.join(
473 OPTIONS.input_tmp, "PREBUILT_IMAGES", "pvmfw.img")
474 assert os.path.exists(pvmfw_prebuilt_path)
475 shutil.copy(pvmfw_prebuilt_path, img.name)
476
477 # AVB-sign the image as needed.
478 if OPTIONS.info_dict.get("avb_enable") == "true":
479 # Signing requires +w
480 os.chmod(img.name, os.stat(img.name).st_mode | stat.S_IWUSR)
481
482 avbtool = OPTIONS.info_dict["avb_avbtool"]
483 part_size = OPTIONS.info_dict["pvmfw_size"]
484 # The AVB hash footer will be replaced if already present.
485 cmd = [avbtool, "add_hash_footer", "--image", img.name,
486 "--partition_size", str(part_size), "--partition_name", "pvmfw"]
487 common.AppendAVBSigningArgs(cmd, "pvmfw")
488 args = OPTIONS.info_dict.get("avb_pvmfw_add_hash_footer_args")
489 if args and args.strip():
490 cmd.extend(shlex.split(args))
491 common.RunAndCheckOutput(cmd)
492
493 img.Write()
494 return img.name
495
Tianjiebbde59f2021-05-03 21:18:56 -0700496
Hongguang Chenf23364d2020-04-27 18:36:36 -0700497def AddCustomImages(output_zip, partition_name):
498 """Adds and signs custom images in IMAGES/.
499
500 Args:
501 output_zip: The output zip file (needs to be already open), or None to
502 write images to OPTIONS.input_tmp/.
503
504 Uses the image under IMAGES/ if it already exists. Otherwise looks for the
505 image under PREBUILT_IMAGES/, signs it as needed, and returns the image name.
506
507 Raises:
508 AssertionError: If image can't be found.
509 """
510
Hongguang Chenf23364d2020-04-27 18:36:36 -0700511 key_path = OPTIONS.info_dict.get("avb_{}_key_path".format(partition_name))
512 algorithm = OPTIONS.info_dict.get("avb_{}_algorithm".format(partition_name))
513 extra_args = OPTIONS.info_dict.get(
514 "avb_{}_add_hashtree_footer_args".format(partition_name))
515 partition_size = OPTIONS.info_dict.get(
516 "avb_{}_partition_size".format(partition_name))
517
518 builder = verity_utils.CreateCustomImageBuilder(
519 OPTIONS.info_dict, partition_name, partition_size,
520 key_path, algorithm, extra_args)
521
522 for img_name in OPTIONS.info_dict.get(
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800523 "avb_{}_image_list".format(partition_name)).split():
524 custom_image = OutputFile(
525 output_zip, OPTIONS.input_tmp, "IMAGES", img_name)
Hongguang Chenf23364d2020-04-27 18:36:36 -0700526 if os.path.exists(custom_image.name):
527 continue
528
529 custom_image_prebuilt_path = os.path.join(
530 OPTIONS.input_tmp, "PREBUILT_IMAGES", img_name)
531 assert os.path.exists(custom_image_prebuilt_path), \
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800532 "Failed to find %s at %s" % (img_name, custom_image_prebuilt_path)
Hongguang Chenf23364d2020-04-27 18:36:36 -0700533
534 shutil.copy(custom_image_prebuilt_path, custom_image.name)
535
536 if builder is not None:
537 builder.Build(custom_image.name)
538
539 custom_image.Write()
540
541 default = os.path.join(OPTIONS.input_tmp, "IMAGES", partition_name + ".img")
542 assert os.path.exists(default), \
543 "There should be one %s.img" % (partition_name)
544 return default
545
Doug Zongker3c84f562014-07-31 11:06:30 -0700546
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800547def CreateImage(input_dir, info_dict, what, output_file, block_list=None):
Tao Baoa3705452019-06-24 15:33:41 -0700548 logger.info("creating %s.img...", what)
Doug Zongker3c84f562014-07-31 11:06:30 -0700549
Doug Zongker3c84f562014-07-31 11:06:30 -0700550 image_props = build_image.ImagePropFromGlobalDict(info_dict, what)
Bryan Henrye6d547d2018-07-31 18:32:00 -0700551 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700552
Doug Zongker3c84f562014-07-31 11:06:30 -0700553 if what == "system":
554 fs_config_prefix = ""
555 else:
556 fs_config_prefix = what + "_"
557
558 fs_config = os.path.join(
559 input_dir, "META/" + fs_config_prefix + "filesystem_config.txt")
Dan Albert8b72aef2015-03-23 19:13:21 -0700560 if not os.path.exists(fs_config):
561 fs_config = None
Doug Zongker3c84f562014-07-31 11:06:30 -0700562
Ying Wanga2292c92015-03-24 19:07:40 -0700563 # Override values loaded from info_dict.
564 if fs_config:
565 image_props["fs_config"] = fs_config
Ying Wanga2292c92015-03-24 19:07:40 -0700566 if block_list:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800567 image_props["block_list"] = block_list.name
Ying Wanga2292c92015-03-24 19:07:40 -0700568
Tao Baod86e3112017-09-22 15:45:33 -0700569 # Use repeatable ext4 FS UUID and hash_seed UUID (based on partition name and
Tianjiefdda51d2021-05-05 14:46:35 -0700570 # build fingerprint). Also use the legacy build id, because the vbmeta digest
571 # isn't available at this point.
572 build_info = common.BuildInfo(info_dict, use_legacy_id=True)
Yifan Hongc08cbf02020-09-15 19:07:39 +0000573 uuid_seed = what + "-" + build_info.GetPartitionFingerprint(what)
Tao Baod86e3112017-09-22 15:45:33 -0700574 image_props["uuid"] = str(uuid.uuid5(uuid.NAMESPACE_URL, uuid_seed))
575 hash_seed = "hash_seed-" + uuid_seed
576 image_props["hash_seed"] = str(uuid.uuid5(uuid.NAMESPACE_URL, hash_seed))
577
Tao Baoc6bd70a2018-09-27 16:58:00 -0700578 build_image.BuildImage(
579 os.path.join(input_dir, what.upper()), image_props, output_file.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700580
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800581 output_file.Write()
582 if block_list:
583 block_list.Write()
584
Shashikant Baviskar16a73892019-02-07 10:57:21 +0900585 # Set the '_image_size' for given image size.
Tianjie Xuf1a13182017-01-19 17:39:30 -0800586 is_verity_partition = "verity_block_device" in image_props
hungweichen65ba3752022-08-17 10:14:01 +0000587 verity_supported = (image_props.get("avb_enable") == "true")
Tianjie Xu6b2e1552017-06-01 11:32:32 -0700588 is_avb_enable = image_props.get("avb_hashtree_enable") == "true"
589 if verity_supported and (is_verity_partition or is_avb_enable):
Tao Bao35f4ebc2018-09-27 15:31:11 -0700590 image_size = image_props.get("image_size")
591 if image_size:
Shashikant Baviskar16a73892019-02-07 10:57:21 +0900592 image_size_key = what + "_image_size"
593 info_dict[image_size_key] = int(image_size)
Tianjie Xuf1a13182017-01-19 17:39:30 -0800594
Yifan Hongc767f7c2018-11-08 15:41:24 -0800595 use_dynamic_size = (
Tao Bao2764aee2018-11-21 11:02:48 -0800596 info_dict.get("use_dynamic_partition_size") == "true" and
597 what in shlex.split(info_dict.get("dynamic_partition_list", "").strip()))
Yifan Hongc767f7c2018-11-08 15:41:24 -0800598 if use_dynamic_size:
599 info_dict.update(build_image.GlobalDictFromImageProp(image_props, what))
600
Doug Zongker3c84f562014-07-31 11:06:30 -0700601
Tao Bao886d8832018-02-27 11:46:19 -0800602def AddUserdata(output_zip):
Ying Wang2a048392015-06-25 13:56:53 -0700603 """Create a userdata image and store it in output_zip.
604
605 In most case we just create and store an empty userdata.img;
606 But the invoker can also request to create userdata.img with real
607 data from the target files, by setting "userdata_img_with_data=true"
608 in OPTIONS.info_dict.
609 """
Doug Zongker3c84f562014-07-31 11:06:30 -0700610
Tao Bao886d8832018-02-27 11:46:19 -0800611 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "userdata.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800612 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700613 logger.info("userdata.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800614 return
615
Elliott Hughes305b0882016-06-15 17:04:54 -0700616 # Skip userdata.img if no size.
Tao Bao2c15d9e2015-07-09 11:51:16 -0700617 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "data")
Elliott Hughes305b0882016-06-15 17:04:54 -0700618 if not image_props.get("partition_size"):
Doug Zongker3c84f562014-07-31 11:06:30 -0700619 return
620
Tao Bao32fcdab2018-10-12 10:30:39 -0700621 logger.info("creating userdata.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700622
Bryan Henrye6d547d2018-07-31 18:32:00 -0700623 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700624
Tao Baofa863c82017-05-23 23:49:03 -0700625 if OPTIONS.info_dict.get("userdata_img_with_data") == "true":
626 user_dir = os.path.join(OPTIONS.input_tmp, "DATA")
Ying Wang2a048392015-06-25 13:56:53 -0700627 else:
Tao Bao1c830bf2017-12-25 10:43:47 -0800628 user_dir = common.MakeTempDir()
Ying Wang2a048392015-06-25 13:56:53 -0700629
Tao Baoc6bd70a2018-09-27 16:58:00 -0700630 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700631
632 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800633 # Always use compression for useradata image.
634 # As it's likely huge and consist of lots of 0s.
635 img.Write(zipfile.ZIP_DEFLATED)
Doug Zongker3c84f562014-07-31 11:06:30 -0700636
637
Tao Bao744c4c72018-08-20 21:09:07 -0700638def AddVBMeta(output_zip, partitions, name, needed_partitions):
639 """Creates a VBMeta image and stores it in output_zip.
640
641 It generates the requested VBMeta image. The requested image could be for
642 top-level or chained VBMeta image, which is determined based on the name.
Tao Baobf70c312017-07-11 17:27:55 -0700643
644 Args:
645 output_zip: The output zip file, which needs to be already open.
646 partitions: A dict that's keyed by partition names with image paths as
Hongguang Chenf23364d2020-04-27 18:36:36 -0700647 values. Only valid partition names are accepted, as partitions listed
648 in common.AVB_PARTITIONS and custom partitions listed in
649 OPTIONS.info_dict.get("avb_custom_images_partition_list")
David Anderson7709ab22018-10-15 14:41:34 -0700650 name: Name of the VBMeta partition, e.g. 'vbmeta', 'vbmeta_system'.
Tao Bao744c4c72018-08-20 21:09:07 -0700651 needed_partitions: Partitions whose descriptors should be included into the
652 generated VBMeta image.
653
Tao Bao71064202018-10-22 15:08:02 -0700654 Returns:
655 Path to the created image.
656
Tao Bao744c4c72018-08-20 21:09:07 -0700657 Raises:
658 AssertionError: On invalid input args.
Tao Baobf70c312017-07-11 17:27:55 -0700659 """
Tao Bao744c4c72018-08-20 21:09:07 -0700660 assert needed_partitions, "Needed partitions must be specified"
661
662 img = OutputFile(
663 output_zip, OPTIONS.input_tmp, "IMAGES", "{}.img".format(name))
Tao Bao93e7ebe2019-01-13 23:23:01 -0800664 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700665 logger.info("%s.img already exists; not rebuilding...", name)
Tao Bao93e7ebe2019-01-13 23:23:01 -0800666 return img.name
Tao Bao262bf3f2017-07-11 17:27:55 -0700667
Daniel Norman276f0622019-07-26 14:13:51 -0700668 common.BuildVBMeta(img.name, partitions, name, needed_partitions)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800669 img.Write()
Tao Bao71064202018-10-22 15:08:02 -0700670 return img.name
David Zeuthen2ce63ed2016-09-15 13:43:54 -0400671
672
Tao Bao886d8832018-02-27 11:46:19 -0800673def AddPartitionTable(output_zip):
David Zeuthen25328622016-04-08 15:08:03 -0400674 """Create a partition table image and store it in output_zip."""
675
Tao Bao886d8832018-02-27 11:46:19 -0800676 img = OutputFile(
677 output_zip, OPTIONS.input_tmp, "IMAGES", "partition-table.img")
678 bpt = OutputFile(
Bryan Henryf130a232018-04-26 11:59:33 -0700679 output_zip, OPTIONS.input_tmp, "META", "partition-table.bpt")
David Zeuthen25328622016-04-08 15:08:03 -0400680
681 # use BPTTOOL from environ, or "bpttool" if empty or not set.
682 bpttool = os.getenv("BPTTOOL") or "bpttool"
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800683 cmd = [bpttool, "make_table", "--output_json", bpt.name,
684 "--output_gpt", img.name]
David Zeuthen25328622016-04-08 15:08:03 -0400685 input_files_str = OPTIONS.info_dict["board_bpt_input_files"]
jiajia tange5ddfcd2022-06-21 10:36:12 +0800686 input_files = input_files_str.split()
David Zeuthen25328622016-04-08 15:08:03 -0400687 for i in input_files:
688 cmd.extend(["--input", i])
689 disk_size = OPTIONS.info_dict.get("board_bpt_disk_size")
690 if disk_size:
691 cmd.extend(["--disk_size", disk_size])
692 args = OPTIONS.info_dict.get("board_bpt_make_table_args")
693 if args:
694 cmd.extend(shlex.split(args))
Tao Bao2764aee2018-11-21 11:02:48 -0800695 common.RunAndCheckOutput(cmd)
David Zeuthen25328622016-04-08 15:08:03 -0400696
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800697 img.Write()
698 bpt.Write()
David Zeuthen25328622016-04-08 15:08:03 -0400699
700
Tao Bao886d8832018-02-27 11:46:19 -0800701def AddCache(output_zip):
Doug Zongker3c84f562014-07-31 11:06:30 -0700702 """Create an empty cache image and store it in output_zip."""
703
Tao Bao886d8832018-02-27 11:46:19 -0800704 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "cache.img")
Tao Bao93e7ebe2019-01-13 23:23:01 -0800705 if os.path.exists(img.name):
Tao Bao32fcdab2018-10-12 10:30:39 -0700706 logger.info("cache.img already exists; no need to rebuild...")
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800707 return
708
Tao Bao2c15d9e2015-07-09 11:51:16 -0700709 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "cache")
Doug Zongker3c84f562014-07-31 11:06:30 -0700710 # The build system has to explicitly request for cache.img.
711 if "fs_type" not in image_props:
712 return
713
Tao Bao32fcdab2018-10-12 10:30:39 -0700714 logger.info("creating cache.img...")
Doug Zongker3c84f562014-07-31 11:06:30 -0700715
Bryan Henrye6d547d2018-07-31 18:32:00 -0700716 image_props["timestamp"] = FIXED_FILE_TIMESTAMP
Tao Bao822f5842015-09-30 16:01:14 -0700717
Tao Bao1c830bf2017-12-25 10:43:47 -0800718 user_dir = common.MakeTempDir()
Tao Baoc6bd70a2018-09-27 16:58:00 -0700719 build_image.BuildImage(user_dir, image_props, img.name)
Doug Zongker3c84f562014-07-31 11:06:30 -0700720
721 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800722 img.Write()
Doug Zongker3c84f562014-07-31 11:06:30 -0700723
724
Tao Bao5277d102018-04-17 23:47:21 -0700725def CheckAbOtaImages(output_zip, ab_partitions):
726 """Checks that all the listed A/B partitions have their images available.
Tao Baobea20ac2018-01-17 17:57:49 -0800727
Tao Bao5277d102018-04-17 23:47:21 -0700728 The images need to be available under IMAGES/ or RADIO/, with the former takes
729 a priority.
Tao Baobea20ac2018-01-17 17:57:49 -0800730
731 Args:
732 output_zip: The output zip file (needs to be already open), or None to
Tao Bao5277d102018-04-17 23:47:21 -0700733 find images in OPTIONS.input_tmp/.
Tao Baobea20ac2018-01-17 17:57:49 -0800734 ab_partitions: The list of A/B partitions.
735
736 Raises:
737 AssertionError: If it can't find an image.
738 """
739 for partition in ab_partitions:
Daniel Norman78554ea2021-09-14 10:29:38 -0700740 img_name = partition + ".img"
Tao Baobea20ac2018-01-17 17:57:49 -0800741
Tao Baoa2ff4c92018-01-17 12:14:43 -0800742 # Assert that the image is present under IMAGES/ now.
Tao Baobea20ac2018-01-17 17:57:49 -0800743 if output_zip:
744 # Zip spec says: All slashes MUST be forward slashes.
Tao Bao5277d102018-04-17 23:47:21 -0700745 images_path = "IMAGES/" + img_name
746 radio_path = "RADIO/" + img_name
747 available = (images_path in output_zip.namelist() or
748 radio_path in output_zip.namelist())
Tao Baobea20ac2018-01-17 17:57:49 -0800749 else:
Tao Bao5277d102018-04-17 23:47:21 -0700750 images_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
751 radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
752 available = os.path.exists(images_path) or os.path.exists(radio_path)
753
754 assert available, "Failed to find " + img_name
Tao Baobea20ac2018-01-17 17:57:49 -0800755
756
Tao Baobea20ac2018-01-17 17:57:49 -0800757def AddPackRadioImages(output_zip, images):
758 """Copies images listed in META/pack_radioimages.txt from RADIO/ to IMAGES/.
759
760 Args:
761 output_zip: The output zip file (needs to be already open), or None to
762 write images to OPTIONS.input_tmp/.
763 images: A list of image names.
764
765 Raises:
766 AssertionError: If a listed image can't be found.
767 """
768 for image in images:
769 img_name = image.strip()
770 _, ext = os.path.splitext(img_name)
771 if not ext:
772 img_name += ".img"
Tao Baoa2ff4c92018-01-17 12:14:43 -0800773
Tao Baobea20ac2018-01-17 17:57:49 -0800774 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name)
775 if os.path.exists(prebuilt_path):
Tao Bao32fcdab2018-10-12 10:30:39 -0700776 logger.info("%s already exists, no need to overwrite...", img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800777 continue
778
779 img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name)
780 assert os.path.exists(img_radio_path), \
781 "Failed to find %s at %s" % (img_name, img_radio_path)
Tao Baoa2ff4c92018-01-17 12:14:43 -0800782
Tao Baobea20ac2018-01-17 17:57:49 -0800783 if output_zip:
Tao Baoa2ff4c92018-01-17 12:14:43 -0800784 common.ZipWrite(output_zip, img_radio_path, "IMAGES/" + img_name)
Tao Baobea20ac2018-01-17 17:57:49 -0800785 else:
786 shutil.copy(img_radio_path, prebuilt_path)
787
788
David Anderson1ef03e22018-08-30 13:11:47 -0700789def AddSuperEmpty(output_zip):
790 """Create a super_empty.img and store it in output_zip."""
791
792 img = OutputFile(output_zip, OPTIONS.input_tmp, "IMAGES", "super_empty.img")
Yifan Hong055e6cf2018-11-29 13:51:48 -0800793 build_super_image.BuildSuperImage(OPTIONS.info_dict, img.name)
David Anderson1ef03e22018-08-30 13:11:47 -0700794 img.Write()
795
796
Yifan Hongc767f7c2018-11-08 15:41:24 -0800797def AddSuperSplit(output_zip):
798 """Create split super_*.img and store it in output_zip."""
799
Yifan Hong055e6cf2018-11-29 13:51:48 -0800800 outdir = os.path.join(OPTIONS.input_tmp, "OTA")
Yifan Honge98427a2018-12-07 10:08:27 -0800801 built = build_super_image.BuildSuperImage(OPTIONS.input_tmp, outdir)
Yifan Hongc767f7c2018-11-08 15:41:24 -0800802
Yifan Honge98427a2018-12-07 10:08:27 -0800803 if built:
804 for dev in OPTIONS.info_dict['super_block_devices'].strip().split():
805 img = OutputFile(output_zip, OPTIONS.input_tmp, "OTA",
806 "super_" + dev + ".img")
807 img.Write()
Yifan Hongc767f7c2018-11-08 15:41:24 -0800808
809
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700810def ReplaceUpdatedFiles(zip_filename, files_list):
Tao Bao89d7ab22017-12-14 17:05:33 -0800811 """Updates all the ZIP entries listed in files_list.
Tianjie Xu38af07f2017-05-25 17:38:53 -0700812
Tianjie Xu4c05f4a2018-09-14 16:24:41 -0700813 For now the list includes META/care_map.pb, and the related files under
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700814 SYSTEM/ after rebuilding recovery.
815 """
Tao Bao89d7ab22017-12-14 17:05:33 -0800816 common.ZipDelete(zip_filename, files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -0700817 output_zip = zipfile.ZipFile(zip_filename, "a",
818 compression=zipfile.ZIP_DEFLATED,
819 allowZip64=True)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -0700820 for item in files_list:
Tianjie Xu38af07f2017-05-25 17:38:53 -0700821 file_path = os.path.join(OPTIONS.input_tmp, item)
822 assert os.path.exists(file_path)
823 common.ZipWrite(output_zip, file_path, arcname=item)
824 common.ZipClose(output_zip)
825
826
Chris Gross435b8fe2020-09-15 09:53:44 -0700827def HasPartition(partition_name):
828 """Determines if the target files archive should build a given partition."""
829
830 return ((os.path.isdir(
831 os.path.join(OPTIONS.input_tmp, partition_name.upper())) and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800832 OPTIONS.info_dict.get(
833 "building_{}_image".format(partition_name)) == "true") or
834 os.path.exists(
835 os.path.join(OPTIONS.input_tmp, "IMAGES",
836 "{}.img".format(partition_name))))
Chris Gross435b8fe2020-09-15 09:53:44 -0700837
Tianjiea5fca032021-06-01 22:06:28 -0700838
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500839def AddApexInfo(output_zip):
Tianjiea5fca032021-06-01 22:06:28 -0700840 apex_infos = GetApexInfoFromTargetFiles(OPTIONS.input_tmp, 'system',
841 compressed_only=False)
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -0500842 apex_metadata_proto = ota_metadata_pb2.ApexMetadata()
843 apex_metadata_proto.apex_info.extend(apex_infos)
844 apex_info_bytes = apex_metadata_proto.SerializeToString()
845
846 output_file = os.path.join(OPTIONS.input_tmp, "META", "apex_info.pb")
847 with open(output_file, "wb") as ofile:
848 ofile.write(apex_info_bytes)
849 if output_zip:
850 arc_name = "META/apex_info.pb"
851 if arc_name in output_zip.namelist():
852 OPTIONS.replace_updated_files_list.append(arc_name)
853 else:
854 common.ZipWrite(output_zip, output_file, arc_name)
855
Chris Gross435b8fe2020-09-15 09:53:44 -0700856
Tianjiec3bf3d02021-07-14 15:56:37 -0700857def AddVbmetaDigest(output_zip):
858 """Write the vbmeta digest to the output dir and zipfile."""
859
860 # Calculate the vbmeta digest and put the result in to META/
861 boot_images = OPTIONS.info_dict.get("boot_images")
862 # Disable the digest calculation if the target_file is used as a container
Bowgo Tsaiaba5c9e2021-09-27 14:08:41 +0800863 # for boot images. A boot container might contain boot-5.4.img, boot-5.10.img
864 # etc., instead of just a boot.img and will fail in vbmeta digest calculation.
865 boot_container = boot_images and (
866 len(boot_images.split()) >= 2 or boot_images.split()[0] != 'boot.img')
Tianjiec3bf3d02021-07-14 15:56:37 -0700867 if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container and
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800868 OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"):
Tianjiec3bf3d02021-07-14 15:56:37 -0700869 avbtool = OPTIONS.info_dict["avb_avbtool"]
870 digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool)
871 vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META",
872 "vbmeta_digest.txt")
873 with open(vbmeta_digest_txt, 'w') as f:
874 f.write(digest)
875 # writes to the output zipfile
876 if output_zip:
877 arc_name = "META/vbmeta_digest.txt"
878 if arc_name in output_zip.namelist():
879 OPTIONS.replace_updated_files_list.append(arc_name)
880 else:
881 common.ZipWriteStr(output_zip, arc_name, digest)
882
883
Doug Zongker3c84f562014-07-31 11:06:30 -0700884def AddImagesToTargetFiles(filename):
Tao Baoae396d92017-11-20 11:56:43 -0800885 """Creates and adds images (boot/recovery/system/...) to a target_files.zip.
886
887 It works with either a zip file (zip mode), or a directory that contains the
888 files to be packed into a target_files.zip (dir mode). The latter is used when
889 being called from build/make/core/Makefile.
890
891 The images will be created under IMAGES/ in the input target_files.zip.
892
893 Args:
Tao Baodba59ee2018-01-09 13:21:02 -0800894 filename: the target_files.zip, or the zip root directory.
Tao Baoae396d92017-11-20 11:56:43 -0800895 """
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800896 if os.path.isdir(filename):
897 OPTIONS.input_tmp = os.path.abspath(filename)
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800898 else:
Tao Baodba59ee2018-01-09 13:21:02 -0800899 OPTIONS.input_tmp = common.UnzipTemp(filename)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700900
Michael Runge2e0d8fc2014-11-13 21:41:08 -0800901 if not OPTIONS.add_missing:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800902 if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")):
Tao Bao32fcdab2018-10-12 10:30:39 -0700903 logger.warning("target_files appears to already contain images.")
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800904 sys.exit(1)
Doug Zongkerfc44a512014-08-26 13:10:25 -0700905
Tao Bao410ad8b2018-08-24 12:08:38 -0700906 OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True)
Tao Baodba59ee2018-01-09 13:21:02 -0800907
908 has_recovery = OPTIONS.info_dict.get("no_recovery") != "true"
Chris Grossa784ef12019-04-22 11:09:57 -0700909 has_boot = OPTIONS.info_dict.get("no_boot") != "true"
Devin Mooreafdd7c72021-12-13 22:04:08 +0000910 has_init_boot = OPTIONS.info_dict.get("init_boot") == "true"
Steve Mucklee1b10862019-07-10 10:49:37 -0700911 has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true"
Kelvin Zhangf294c872022-10-06 14:21:36 -0700912 has_vendor_kernel_boot = OPTIONS.info_dict.get(
913 "vendor_kernel_boot") == "true"
Tao Baodba59ee2018-01-09 13:21:02 -0800914
Ramji Jiyani13a41372022-01-27 07:05:08 +0000915 # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system_dlkm, system, system_other}.img
Chris Gross435b8fe2020-09-15 09:53:44 -0700916 # can be built from source, or dropped into target_files.zip as a prebuilt blob.
917 has_vendor = HasPartition("vendor")
918 has_odm = HasPartition("odm")
919 has_vendor_dlkm = HasPartition("vendor_dlkm")
920 has_odm_dlkm = HasPartition("odm_dlkm")
Ramji Jiyani13a41372022-01-27 07:05:08 +0000921 has_system_dlkm = HasPartition("system_dlkm")
Chris Gross435b8fe2020-09-15 09:53:44 -0700922 has_product = HasPartition("product")
923 has_system_ext = HasPartition("system_ext")
924 has_system = HasPartition("system")
925 has_system_other = HasPartition("system_other")
Chris Gross203191b2020-05-30 02:39:12 +0000926 has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true"
927 has_cache = OPTIONS.info_dict.get("building_cache_image") == "true"
Doug Zongker3c84f562014-07-31 11:06:30 -0700928
Tao Baodba59ee2018-01-09 13:21:02 -0800929 # Set up the output destination. It writes to the given directory for dir
930 # mode; otherwise appends to the given ZIP.
931 if os.path.isdir(filename):
932 output_zip = None
933 else:
Dan Willemsen2ee00d52017-03-05 19:51:56 -0800934 output_zip = zipfile.ZipFile(filename, "a",
935 compression=zipfile.ZIP_DEFLATED,
936 allowZip64=True)
Tao Baoae396d92017-11-20 11:56:43 -0800937
938 # Always make input_tmp/IMAGES available, since we may stage boot / recovery
939 # images there even under zip mode. The directory will be cleaned up as part
940 # of OPTIONS.input_tmp.
941 images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES")
942 if not os.path.isdir(images_dir):
943 os.makedirs(images_dir)
Doug Zongker3c84f562014-07-31 11:06:30 -0700944
Tao Baobf70c312017-07-11 17:27:55 -0700945 # A map between partition names and their paths, which could be used when
946 # generating AVB vbmeta image.
Tao Bao3ed35d32019-10-07 20:48:48 -0700947 partitions = {}
Tao Baobf70c312017-07-11 17:27:55 -0700948
Doug Zongkerfc44a512014-08-26 13:10:25 -0700949 def banner(s):
Tao Baoa3705452019-06-24 15:33:41 -0700950 logger.info("\n\n++++ %s ++++\n\n", s)
Doug Zongker3c84f562014-07-31 11:06:30 -0700951
Chris Grossa784ef12019-04-22 11:09:57 -0700952 boot_image = None
Greg Kaisere086f722021-09-14 19:32:27 +0000953 if has_boot:
Chris Grossa784ef12019-04-22 11:09:57 -0700954 banner("boot")
Steve Muckle9793cf62020-04-08 18:27:00 -0700955 boot_images = OPTIONS.info_dict.get("boot_images")
956 if boot_images is None:
957 boot_images = "boot.img"
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800958 for index, b in enumerate(boot_images.split()):
Steve Muckle9793cf62020-04-08 18:27:00 -0700959 # common.GetBootableImage() returns the image directly if present.
960 boot_image = common.GetBootableImage(
961 "IMAGES/" + b, b, OPTIONS.input_tmp, "BOOT")
962 # boot.img may be unavailable in some targets (e.g. aosp_arm64).
963 if boot_image:
964 boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b)
Roopesh Nataraja3e15f6e2020-06-08 19:54:13 -0700965 # Although multiple boot images can be generated, include the image
966 # descriptor of only the first boot image in vbmeta
967 if index == 0:
Steve Muckle9793cf62020-04-08 18:27:00 -0700968 partitions['boot'] = boot_image_path
969 if not os.path.exists(boot_image_path):
970 boot_image.WriteToDir(OPTIONS.input_tmp)
971 if output_zip:
972 boot_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -0700973
Devin Mooreafdd7c72021-12-13 22:04:08 +0000974 if has_init_boot:
975 banner("init_boot")
976 init_boot_image = common.GetBootableImage(
977 "IMAGES/init_boot.img", "init_boot.img", OPTIONS.input_tmp, "INIT_BOOT")
978 if init_boot_image:
Kelvin Zhang834f5d42022-01-21 12:44:44 -0800979 partitions['init_boot'] = os.path.join(
980 OPTIONS.input_tmp, "IMAGES", "init_boot.img")
Devin Mooreafdd7c72021-12-13 22:04:08 +0000981 if not os.path.exists(partitions['init_boot']):
982 init_boot_image.WriteToDir(OPTIONS.input_tmp)
983 if output_zip:
984 init_boot_image.AddToZip(output_zip)
985
Greg Kaisere086f722021-09-14 19:32:27 +0000986 if has_vendor_boot:
Steve Mucklee1b10862019-07-10 10:49:37 -0700987 banner("vendor_boot")
988 vendor_boot_image = common.GetVendorBootImage(
989 "IMAGES/vendor_boot.img", "vendor_boot.img", OPTIONS.input_tmp,
990 "VENDOR_BOOT")
991 if vendor_boot_image:
992 partitions['vendor_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
993 "vendor_boot.img")
994 if not os.path.exists(partitions['vendor_boot']):
995 vendor_boot_image.WriteToDir(OPTIONS.input_tmp)
996 if output_zip:
997 vendor_boot_image.AddToZip(output_zip)
998
Lucas Weif57333f2022-02-24 10:30:15 +0800999 if has_vendor_kernel_boot:
1000 banner("vendor_kernel_boot")
Lucas Wei03230252022-04-18 16:00:40 +08001001 vendor_kernel_boot_image = common.GetVendorKernelBootImage(
Lucas Weif57333f2022-02-24 10:30:15 +08001002 "IMAGES/vendor_kernel_boot.img", "vendor_kernel_boot.img", OPTIONS.input_tmp,
1003 "VENDOR_KERNEL_BOOT")
1004 if vendor_kernel_boot_image:
1005 partitions['vendor_kernel_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES",
Kelvin Zhangf294c872022-10-06 14:21:36 -07001006 "vendor_kernel_boot.img")
Lucas Weif57333f2022-02-24 10:30:15 +08001007 if not os.path.exists(partitions['vendor_kernel_boot']):
1008 vendor_kernel_boot_image.WriteToDir(OPTIONS.input_tmp)
1009 if output_zip:
1010 vendor_kernel_boot_image.AddToZip(output_zip)
1011
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001012 recovery_image = None
Greg Kaisere086f722021-09-14 19:32:27 +00001013 if has_recovery:
Tao Baodb45efa2015-10-27 19:25:18 -07001014 banner("recovery")
Tao Bao262bf3f2017-07-11 17:27:55 -07001015 recovery_image = common.GetBootableImage(
1016 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
1017 assert recovery_image, "Failed to create recovery.img."
Tao Baobf70c312017-07-11 17:27:55 -07001018 partitions['recovery'] = os.path.join(
Tao Bao262bf3f2017-07-11 17:27:55 -07001019 OPTIONS.input_tmp, "IMAGES", "recovery.img")
Tao Baobf70c312017-07-11 17:27:55 -07001020 if not os.path.exists(partitions['recovery']):
Tao Bao262bf3f2017-07-11 17:27:55 -07001021 recovery_image.WriteToDir(OPTIONS.input_tmp)
1022 if output_zip:
1023 recovery_image.AddToZip(output_zip)
Doug Zongker3c84f562014-07-31 11:06:30 -07001024
Tao Baod42e97e2016-11-30 12:11:57 -08001025 banner("recovery (two-step image)")
1026 # The special recovery.img for two-step package use.
1027 recovery_two_step_image = common.GetBootableImage(
Tao Bao04808502019-07-25 23:11:41 -07001028 "OTA/recovery-two-step.img", "recovery-two-step.img",
Tao Baod42e97e2016-11-30 12:11:57 -08001029 OPTIONS.input_tmp, "RECOVERY", two_step_image=True)
Tao Bao262bf3f2017-07-11 17:27:55 -07001030 assert recovery_two_step_image, "Failed to create recovery-two-step.img."
1031 recovery_two_step_image_path = os.path.join(
Tao Bao04808502019-07-25 23:11:41 -07001032 OPTIONS.input_tmp, "OTA", "recovery-two-step.img")
Tao Bao262bf3f2017-07-11 17:27:55 -07001033 if not os.path.exists(recovery_two_step_image_path):
1034 recovery_two_step_image.WriteToDir(OPTIONS.input_tmp)
Dan Willemsen2ee00d52017-03-05 19:51:56 -08001035 if output_zip:
1036 recovery_two_step_image.AddToZip(output_zip)
Tao Baod42e97e2016-11-30 12:11:57 -08001037
Daniel Norman78554ea2021-09-14 10:29:38 -07001038 def add_partition(partition, has_partition, add_func, add_args):
1039 if has_partition:
1040 banner(partition)
1041 partitions[partition] = add_func(output_zip, *add_args)
Tao Baobf70c312017-07-11 17:27:55 -07001042
Daniel Norman78554ea2021-09-14 10:29:38 -07001043 add_partition_calls = (
1044 ("system", has_system, AddSystem, [recovery_image, boot_image]),
1045 ("vendor", has_vendor, AddVendor, [recovery_image, boot_image]),
1046 ("product", has_product, AddProduct, []),
1047 ("system_ext", has_system_ext, AddSystemExt, []),
1048 ("odm", has_odm, AddOdm, []),
1049 ("vendor_dlkm", has_vendor_dlkm, AddVendorDlkm, []),
1050 ("odm_dlkm", has_odm_dlkm, AddOdmDlkm, []),
Ramji Jiyani13a41372022-01-27 07:05:08 +00001051 ("system_dlkm", has_system_dlkm, AddSystemDlkm, []),
Daniel Norman78554ea2021-09-14 10:29:38 -07001052 ("system_other", has_system_other, AddSystemOther, []),
1053 )
1054 for call in add_partition_calls:
1055 add_partition(*call)
Tao Baobf70c312017-07-11 17:27:55 -07001056
Kelvin Zhang5f0fcee2021-01-19 15:30:46 -05001057 AddApexInfo(output_zip)
1058
Tianjie Xub48589a2016-08-03 19:21:52 -07001059 if not OPTIONS.is_signing:
Greg Kaisere086f722021-09-14 19:32:27 +00001060 banner("userdata")
1061 AddUserdata(output_zip)
1062 banner("cache")
1063 AddCache(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -07001064
1065 if OPTIONS.info_dict.get("board_bpt_enable") == "true":
David Zeuthen25328622016-04-08 15:08:03 -04001066 banner("partition-table")
1067 AddPartitionTable(output_zip)
Tao Baoc633ed02017-05-30 21:46:33 -07001068
Daniel Norman78554ea2021-09-14 10:29:38 -07001069 add_partition("dtbo",
1070 OPTIONS.info_dict.get("has_dtbo") == "true", AddDtbo, [])
1071 add_partition("pvmfw",
1072 OPTIONS.info_dict.get("has_pvmfw") == "true", AddPvmfw, [])
Andrew Sculle077cf72021-02-18 10:27:29 +00001073
Hongguang Chenf23364d2020-04-27 18:36:36 -07001074 # Custom images.
1075 custom_partitions = OPTIONS.info_dict.get(
1076 "avb_custom_images_partition_list", "").strip().split()
1077 for partition_name in custom_partitions:
1078 partition_name = partition_name.strip()
1079 banner("custom images for " + partition_name)
1080 partitions[partition_name] = AddCustomImages(output_zip, partition_name)
1081
Bowgo Tsai3e599ea2017-05-26 18:30:04 +08001082 if OPTIONS.info_dict.get("avb_enable") == "true":
Tao Bao744c4c72018-08-20 21:09:07 -07001083 # vbmeta_partitions includes the partitions that should be included into
1084 # top-level vbmeta.img, which are the ones that are not included in any
1085 # chained VBMeta image plus the chained VBMeta images themselves.
Hongguang Chenf23364d2020-04-27 18:36:36 -07001086 # Currently custom_partitions are all chained to VBMeta image.
1087 vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions)
Tao Bao744c4c72018-08-20 21:09:07 -07001088
David Anderson7709ab22018-10-15 14:41:34 -07001089 vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +00001090 if vbmeta_system:
David Anderson7709ab22018-10-15 14:41:34 -07001091 banner("vbmeta_system")
Tao Bao71064202018-10-22 15:08:02 -07001092 partitions["vbmeta_system"] = AddVBMeta(
David Anderson7709ab22018-10-15 14:41:34 -07001093 output_zip, partitions, "vbmeta_system", vbmeta_system.split())
Tao Bao744c4c72018-08-20 21:09:07 -07001094 vbmeta_partitions = [
1095 item for item in vbmeta_partitions
David Anderson7709ab22018-10-15 14:41:34 -07001096 if item not in vbmeta_system.split()]
1097 vbmeta_partitions.append("vbmeta_system")
Tao Bao744c4c72018-08-20 21:09:07 -07001098
1099 vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip()
Greg Kaisere086f722021-09-14 19:32:27 +00001100 if vbmeta_vendor:
Tao Bao744c4c72018-08-20 21:09:07 -07001101 banner("vbmeta_vendor")
Tao Bao71064202018-10-22 15:08:02 -07001102 partitions["vbmeta_vendor"] = AddVBMeta(
Tao Bao744c4c72018-08-20 21:09:07 -07001103 output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split())
1104 vbmeta_partitions = [
1105 item for item in vbmeta_partitions
1106 if item not in vbmeta_vendor.split()]
1107 vbmeta_partitions.append("vbmeta_vendor")
1108
Greg Kaisere086f722021-09-14 19:32:27 +00001109 if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true":
Bowgo Tsai82182252020-11-13 11:28:17 +08001110 banner("vbmeta")
1111 AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions)
Doug Zongker3c84f562014-07-31 11:06:30 -07001112
Tao Bao48a2feb2019-06-28 11:00:05 -07001113 if OPTIONS.info_dict.get("use_dynamic_partitions") == "true":
Greg Kaisere086f722021-09-14 19:32:27 +00001114 if OPTIONS.info_dict.get("build_super_empty_partition") == "true":
Yo Chiange86bab42021-03-25 10:12:28 +00001115 banner("super_empty")
1116 AddSuperEmpty(output_zip)
David Anderson1ef03e22018-08-30 13:11:47 -07001117
Greg Kaisere086f722021-09-14 19:32:27 +00001118 if OPTIONS.info_dict.get("build_super_partition") == "true":
Tao Bao519d1822018-12-27 12:47:23 -08001119 if OPTIONS.info_dict.get(
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001120 "build_retrofit_dynamic_partitions_ota_package") == "true":
Yifan Hongc767f7c2018-11-08 15:41:24 -08001121 banner("super split images")
1122 AddSuperSplit(output_zip)
Yifan Hongc767f7c2018-11-08 15:41:24 -08001123
Tianjie Xuaaca4212016-06-28 14:34:03 -07001124 banner("radio")
Tao Baobea20ac2018-01-17 17:57:49 -08001125 ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META",
1126 "ab_partitions.txt")
1127 if os.path.exists(ab_partitions_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001128 with open(ab_partitions_txt) as f:
Daniel Norman78554ea2021-09-14 10:29:38 -07001129 ab_partitions = f.read().splitlines()
Tianjie Xucfa86222016-03-07 16:31:19 -08001130
Greg Kaisere086f722021-09-14 19:32:27 +00001131 # For devices using A/B update, make sure we have all the needed images
1132 # ready under IMAGES/ or RADIO/.
1133 CheckAbOtaImages(output_zip, ab_partitions)
Tianjie Xuaaca4212016-06-28 14:34:03 -07001134
Greg Kaisere086f722021-09-14 19:32:27 +00001135 # Generate care_map.pb for ab_partitions, then write this file to
1136 # target_files package.
1137 output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb")
1138 AddCareMapForAbOta(output_zip if output_zip else output_care_map,
1139 ab_partitions, partitions)
Tianjie Xucfa86222016-03-07 16:31:19 -08001140
Tao Bao95a95c32017-06-16 15:30:23 -07001141 # Radio images that need to be packed into IMAGES/, and product-img.zip.
Tao Baobea20ac2018-01-17 17:57:49 -08001142 pack_radioimages_txt = os.path.join(
Tao Bao95a95c32017-06-16 15:30:23 -07001143 OPTIONS.input_tmp, "META", "pack_radioimages.txt")
Tao Baobea20ac2018-01-17 17:57:49 -08001144 if os.path.exists(pack_radioimages_txt):
Tao Baoa3705452019-06-24 15:33:41 -07001145 with open(pack_radioimages_txt) as f:
Tao Baobea20ac2018-01-17 17:57:49 -08001146 AddPackRadioImages(output_zip, f.readlines())
Tao Bao95a95c32017-06-16 15:30:23 -07001147
Greg Kaisere086f722021-09-14 19:32:27 +00001148 AddVbmetaDigest(output_zip)
Tianjiebbde59f2021-05-03 21:18:56 -07001149
Dan Willemsen2ee00d52017-03-05 19:51:56 -08001150 if output_zip:
1151 common.ZipClose(output_zip)
Tianjie Xu9ac4cb02017-06-09 16:58:03 -07001152 if OPTIONS.replace_updated_files_list:
1153 ReplaceUpdatedFiles(output_zip.filename,
1154 OPTIONS.replace_updated_files_list)
Tianjie Xu38af07f2017-05-25 17:38:53 -07001155
Doug Zongker3c84f562014-07-31 11:06:30 -07001156
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001157def OptimizeCompressedEntries(zipfile_path):
1158 """Convert files that do not compress well to uncompressed storage
1159
1160 EROFS images tend to be compressed already, so compressing them again
1161 yields little space savings. Leaving them uncompressed will make
1162 downstream tooling's job easier, and save compute time.
1163 """
1164 if not zipfile.is_zipfile(zipfile_path):
1165 return
1166 entries_to_store = []
1167 with tempfile.TemporaryDirectory() as tmpdir:
1168 with zipfile.ZipFile(zipfile_path, "r", allowZip64=True) as zfp:
1169 for zinfo in zfp.filelist:
1170 if not zinfo.filename.startswith("IMAGES/") and not zinfo.filename.startswith("META"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001171 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001172 # Don't try to store userdata.img uncompressed, it's usually huge.
1173 if zinfo.filename.endswith("userdata.img"):
Kelvin Zhang9d021e92022-02-07 16:37:15 -08001174 continue
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001175 if zinfo.compress_size > zinfo.file_size * 0.80 and zinfo.compress_type != zipfile.ZIP_STORED:
1176 entries_to_store.append(zinfo)
1177 zfp.extract(zinfo, tmpdir)
Kelvin Zhang70876142022-02-09 16:05:29 -08001178 if len(entries_to_store) == 0:
1179 return
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001180 # Remove these entries, then re-add them as ZIP_STORED
Kelvin Zhang70876142022-02-09 16:05:29 -08001181 ZipDelete(zipfile_path, [entry.filename for entry in entries_to_store])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001182 with zipfile.ZipFile(zipfile_path, "a", allowZip64=True) as zfp:
1183 for entry in entries_to_store:
Kelvin Zhangf294c872022-10-06 14:21:36 -07001184 zfp.write(os.path.join(tmpdir, entry.filename),
1185 entry.filename, compress_type=zipfile.ZIP_STORED)
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001186
1187
Doug Zongker3c84f562014-07-31 11:06:30 -07001188def main(argv):
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001189 def option_handler(o, a):
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001190 if o in ("-a", "--add_missing"):
1191 OPTIONS.add_missing = True
1192 elif o in ("-r", "--rebuild_recovery",):
1193 OPTIONS.rebuild_recovery = True
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001194 elif o == "--replace_verity_private_key":
hungweichendd3fca02022-08-19 06:33:25 +00001195 raise ValueError("--replace_verity_private_key is no longer supported,"
1196 " please switch to AVB")
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001197 elif o == "--replace_verity_public_key":
hungweichendd3fca02022-08-19 06:33:25 +00001198 raise ValueError("--replace_verity_public_key is no longer supported,"
1199 " please switch to AVB")
Tianjie Xub48589a2016-08-03 19:21:52 -07001200 elif o == "--is_signing":
1201 OPTIONS.is_signing = True
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001202 else:
1203 return False
1204 return True
1205
Dan Albert8b72aef2015-03-23 19:13:21 -07001206 args = common.ParseOptions(
1207 argv, __doc__, extra_opts="ar",
Baligh Uddin59f4ff12015-09-16 21:20:30 -07001208 extra_long_opts=["add_missing", "rebuild_recovery",
1209 "replace_verity_public_key=",
1210 "replace_verity_private_key=",
Greg Kaisere086f722021-09-14 19:32:27 +00001211 "is_signing"],
Dan Albert8b72aef2015-03-23 19:13:21 -07001212 extra_option_handler=option_handler)
Michael Runge2e0d8fc2014-11-13 21:41:08 -08001213
Doug Zongker3c84f562014-07-31 11:06:30 -07001214 if len(args) != 1:
1215 common.Usage(__doc__)
1216 sys.exit(1)
1217
Tao Bao32fcdab2018-10-12 10:30:39 -07001218 common.InitLogging()
1219
Doug Zongker3c84f562014-07-31 11:06:30 -07001220 AddImagesToTargetFiles(args[0])
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001221 OptimizeCompressedEntries(args[0])
Tao Bao32fcdab2018-10-12 10:30:39 -07001222 logger.info("done.")
Doug Zongker3c84f562014-07-31 11:06:30 -07001223
Kelvin Zhang834f5d42022-01-21 12:44:44 -08001224
Doug Zongker3c84f562014-07-31 11:06:30 -07001225if __name__ == '__main__':
1226 try:
1227 common.CloseInheritedPipes()
1228 main(sys.argv[1:])
Doug Zongkerfc44a512014-08-26 13:10:25 -07001229 finally:
1230 common.Cleanup()