blob: ac61e609d3cf6dd64a6ba3cce3483e562106b09a [file] [log] [blame]
Yifan Hong2b891ac2018-11-29 12:06:31 -08001#!/usr/bin/env python
2#
3# Copyright (C) 2018 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"""
18Usage: build_super_image input_file output_dir_or_file
19
20input_file: one of the following:
21 - directory containing extracted target files. It will load info from
22 META/misc_info.txt and build full super image / split images using source
23 images from IMAGES/.
24 - target files package. Same as above, but extracts the archive before
25 building super image.
26 - a dictionary file containing input arguments to build. Check
Yifan Hong69e0d612019-03-11 15:55:33 -070027 `dump-super-image-info' for details.
Yifan Hong2b891ac2018-11-29 12:06:31 -080028 In addition:
Yifan Hong2b891ac2018-11-29 12:06:31 -080029 - If source images should be included in the output image (for super.img
30 and super split images), a list of "*_image" should be paths of each
31 source images.
32
33output_dir_or_file:
34 If a single super image is built (for super_empty.img, or super.img for
35 launch devices), this argument is the output file.
36 If a collection of split images are built (for retrofit devices), this
37 argument is the output directory.
38"""
39
40from __future__ import print_function
41
42import logging
43import os.path
44import shlex
45import sys
46import zipfile
47
48import common
49import sparse_img
50
51if sys.hexversion < 0x02070000:
52 print("Python 2.7 or newer is required.", file=sys.stderr)
53 sys.exit(1)
54
55logger = logging.getLogger(__name__)
56
57
Steven Laverf43fa9d2019-11-14 15:42:10 -080058UNZIP_PATTERN = ["IMAGES/*", "META/*", "*/build.prop"]
Yifan Hong2b891ac2018-11-29 12:06:31 -080059
60
Yifan Hongcc46eae2019-01-02 11:51:19 -080061def GetArgumentsForImage(partition, group, image=None):
Yifan Hong7ad83b62019-04-04 10:57:39 -070062 image_size = sparse_img.GetImagePartitionSize(image) if image else 0
Yifan Hongcc46eae2019-01-02 11:51:19 -080063
64 cmd = ["--partition",
65 "{}:readonly:{}:{}".format(partition, image_size, group)]
66 if image:
67 cmd += ["--image", "{}={}".format(partition, image)]
68
69 return cmd
70
71
Yifan Hong2b891ac2018-11-29 12:06:31 -080072def BuildSuperImageFromDict(info_dict, output):
73
74 cmd = [info_dict["lpmake"],
75 "--metadata-size", "65536",
76 "--super-name", info_dict["super_metadata_device"]]
77
78 ab_update = info_dict.get("ab_update") == "true"
David Anderson117b52f2019-12-13 15:44:41 -080079 virtual_ab = info_dict.get("virtual_ab") == "true"
80 virtual_ab_retrofit = info_dict.get("virtual_ab_retrofit") == "true"
Yifan Hong2b891ac2018-11-29 12:06:31 -080081 retrofit = info_dict.get("dynamic_partition_retrofit") == "true"
82 block_devices = shlex.split(info_dict.get("super_block_devices", "").strip())
83 groups = shlex.split(info_dict.get("super_partition_groups", "").strip())
84
David Anderson212e5df2018-12-17 12:52:25 -080085 if ab_update and retrofit:
Yifan Hong2b891ac2018-11-29 12:06:31 -080086 cmd += ["--metadata-slots", "2"]
David Anderson212e5df2018-12-17 12:52:25 -080087 elif ab_update:
88 cmd += ["--metadata-slots", "3"]
Yifan Hong2b891ac2018-11-29 12:06:31 -080089 else:
David Anderson212e5df2018-12-17 12:52:25 -080090 cmd += ["--metadata-slots", "2"]
Yifan Hong2b891ac2018-11-29 12:06:31 -080091
92 if ab_update and retrofit:
93 cmd.append("--auto-slot-suffixing")
David Anderson117b52f2019-12-13 15:44:41 -080094 if virtual_ab and not virtual_ab_retrofit:
95 cmd.append("--virtual-ab")
Yifan Hong2b891ac2018-11-29 12:06:31 -080096
97 for device in block_devices:
98 size = info_dict["super_{}_device_size".format(device)]
99 cmd += ["--device", "{}:{}".format(device, size)]
100
101 append_suffix = ab_update and not retrofit
102 has_image = False
103 for group in groups:
104 group_size = info_dict["super_{}_group_size".format(group)]
105 if append_suffix:
106 cmd += ["--group", "{}_a:{}".format(group, group_size),
107 "--group", "{}_b:{}".format(group, group_size)]
108 else:
109 cmd += ["--group", "{}:{}".format(group, group_size)]
110
111 partition_list = shlex.split(
112 info_dict["super_{}_partition_list".format(group)].strip())
113
114 for partition in partition_list:
115 image = info_dict.get("{}_image".format(partition))
Yifan Hong2b891ac2018-11-29 12:06:31 -0800116 if image:
Yifan Hong2b891ac2018-11-29 12:06:31 -0800117 has_image = True
Yifan Hongcc46eae2019-01-02 11:51:19 -0800118
119 if not append_suffix:
120 cmd += GetArgumentsForImage(partition, group, image)
121 continue
122
123 # For A/B devices, super partition always contains sub-partitions in
124 # the _a slot, because this image should only be used for
125 # bootstrapping / initializing the device. When flashing the image,
126 # bootloader fastboot should always mark _a slot as bootable.
127 cmd += GetArgumentsForImage(partition + "_a", group + "_a", image)
128
129 other_image = None
130 if partition == "system" and "system_other_image" in info_dict:
131 other_image = info_dict["system_other_image"]
132 has_image = True
133
134 cmd += GetArgumentsForImage(partition + "_b", group + "_b", other_image)
Yifan Hong2b891ac2018-11-29 12:06:31 -0800135
Yifan Hongcb35bd92019-04-02 16:29:59 -0700136 if info_dict.get("build_non_sparse_super_partition") != "true":
Yifan Hong2b891ac2018-11-29 12:06:31 -0800137 cmd.append("--sparse")
138
139 cmd += ["--output", output]
140
141 common.RunAndCheckOutput(cmd)
142
143 if retrofit and has_image:
144 logger.info("Done writing images to directory %s", output)
145 else:
146 logger.info("Done writing image %s", output)
147
Yifan Honge98427a2018-12-07 10:08:27 -0800148 return True
149
Yifan Hong2b891ac2018-11-29 12:06:31 -0800150
151def BuildSuperImageFromExtractedTargetFiles(inp, out):
152 info_dict = common.LoadInfoDict(inp)
153 partition_list = shlex.split(
154 info_dict.get("dynamic_partition_list", "").strip())
Yifan Hongcc46eae2019-01-02 11:51:19 -0800155
156 if "system" in partition_list:
157 image_path = os.path.join(inp, "IMAGES", "system_other.img")
158 if os.path.isfile(image_path):
159 info_dict["system_other_image"] = image_path
160
Yifan Honge98427a2018-12-07 10:08:27 -0800161 missing_images = []
Yifan Hong2b891ac2018-11-29 12:06:31 -0800162 for partition in partition_list:
Yifan Honge98427a2018-12-07 10:08:27 -0800163 image_path = os.path.join(inp, "IMAGES", "{}.img".format(partition))
164 if not os.path.isfile(image_path):
165 missing_images.append(image_path)
166 else:
167 info_dict["{}_image".format(partition)] = image_path
168 if missing_images:
169 logger.warning("Skip building super image because the following "
170 "images are missing from target files:\n%s",
171 "\n".join(missing_images))
172 return False
Yifan Hong2b891ac2018-11-29 12:06:31 -0800173 return BuildSuperImageFromDict(info_dict, out)
174
175
176def BuildSuperImageFromTargetFiles(inp, out):
177 input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN)
178 return BuildSuperImageFromExtractedTargetFiles(input_tmp, out)
179
180
181def BuildSuperImage(inp, out):
182
183 if isinstance(inp, dict):
184 logger.info("Building super image from info dict...")
185 return BuildSuperImageFromDict(inp, out)
186
187 if isinstance(inp, str):
188 if os.path.isdir(inp):
189 logger.info("Building super image from extracted target files...")
190 return BuildSuperImageFromExtractedTargetFiles(inp, out)
191
192 if zipfile.is_zipfile(inp):
193 logger.info("Building super image from target files...")
194 return BuildSuperImageFromTargetFiles(inp, out)
195
196 if os.path.isfile(inp):
Yifan Hong2b891ac2018-11-29 12:06:31 -0800197 logger.info("Building super image from info dict...")
jiajia tang92b60782021-04-23 19:48:11 +0800198 return BuildSuperImageFromDict(common.LoadDictionaryFromFile(inp), out)
Yifan Hong2b891ac2018-11-29 12:06:31 -0800199
200 raise ValueError("{} is not a dictionary or a valid path".format(inp))
201
202
203def main(argv):
204
205 args = common.ParseOptions(argv, __doc__)
206
207 if len(args) != 2:
208 common.Usage(__doc__)
209 sys.exit(1)
210
211 common.InitLogging()
212
213 BuildSuperImage(args[0], args[1])
214
215
216if __name__ == "__main__":
217 try:
218 common.CloseInheritedPipes()
219 main(sys.argv[1:])
220 except common.ExternalError:
221 logger.exception("\n ERROR:\n")
222 sys.exit(1)
223 finally:
224 common.Cleanup()