aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYifan Hong2018-11-29 14:06:31 -0600
committerYifan Hong2018-12-03 13:33:44 -0600
commit2b891ac0247e4d41e150bc2fe33547e76253efbe (patch)
tree118abb526ec476e6ecfbada5f58a76cb90bf1dd3 /tools/releasetools
parent9814cb6b235f5f93f96e3f2f08c5d4c4a0b6a9f7 (diff)
downloadplatform-build-2b891ac0247e4d41e150bc2fe33547e76253efbe.tar.gz
platform-build-2b891ac0247e4d41e150bc2fe33547e76253efbe.tar.xz
platform-build-2b891ac0247e4d41e150bc2fe33547e76253efbe.zip
Build super.img from images in target_files
For non-retrofit (launch) devices, super.img is used for factory, so source images should be from target_files. In this change, build-superimage-target procedure is converted to a more flexible script so that it can be built. Bug: 119322123 Test: build target files for device launch with dynamic partitions Change-Id: I6ee0cc3e145357dfc74be248f81f5f8f4e51fc5c
Diffstat (limited to 'tools/releasetools')
-rwxr-xr-xtools/releasetools/build_super_image.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/tools/releasetools/build_super_image.py b/tools/releasetools/build_super_image.py
new file mode 100755
index 000000000..6efd3f45b
--- /dev/null
+++ b/tools/releasetools/build_super_image.py
@@ -0,0 +1,202 @@
1#!/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
27 `dump_dynamic_partitions_info' for details.
28 In addition:
29 - "ab_update" needs to be true for A/B devices.
30 - If source images should be included in the output image (for super.img
31 and super split images), a list of "*_image" should be paths of each
32 source images.
33
34output_dir_or_file:
35 If a single super image is built (for super_empty.img, or super.img for
36 launch devices), this argument is the output file.
37 If a collection of split images are built (for retrofit devices), this
38 argument is the output directory.
39"""
40
41from __future__ import print_function
42
43import logging
44import os.path
45import shlex
46import sys
47import zipfile
48
49import common
50import sparse_img
51
52if sys.hexversion < 0x02070000:
53 print("Python 2.7 or newer is required.", file=sys.stderr)
54 sys.exit(1)
55
56logger = logging.getLogger(__name__)
57
58
59UNZIP_PATTERN = ["IMAGES/*", "META/*"]
60
61
62def GetPartitionSizeFromImage(img):
63 try:
64 simg = sparse_img.SparseImage(img)
65 return simg.blocksize * simg.total_blocks
66 except ValueError:
67 return os.path.getsize(img)
68
69
70def BuildSuperImageFromDict(info_dict, output):
71
72 cmd = [info_dict["lpmake"],
73 "--metadata-size", "65536",
74 "--super-name", info_dict["super_metadata_device"]]
75
76 ab_update = info_dict.get("ab_update") == "true"
77 retrofit = info_dict.get("dynamic_partition_retrofit") == "true"
78 block_devices = shlex.split(info_dict.get("super_block_devices", "").strip())
79 groups = shlex.split(info_dict.get("super_partition_groups", "").strip())
80
81 if ab_update:
82 cmd += ["--metadata-slots", "2"]
83 else:
84 cmd += ["--metadata-slots", "1"]
85
86 if ab_update and retrofit:
87 cmd.append("--auto-slot-suffixing")
88
89 for device in block_devices:
90 size = info_dict["super_{}_device_size".format(device)]
91 cmd += ["--device", "{}:{}".format(device, size)]
92
93 append_suffix = ab_update and not retrofit
94 has_image = False
95 for group in groups:
96 group_size = info_dict["super_{}_group_size".format(group)]
97 if append_suffix:
98 cmd += ["--group", "{}_a:{}".format(group, group_size),
99 "--group", "{}_b:{}".format(group, group_size)]
100 else:
101 cmd += ["--group", "{}:{}".format(group, group_size)]
102
103 partition_list = shlex.split(
104 info_dict["super_{}_partition_list".format(group)].strip())
105
106 for partition in partition_list:
107 image = info_dict.get("{}_image".format(partition))
108 image_size = 0
109 if image:
110 image_size = GetPartitionSizeFromImage(image)
111 has_image = True
112 if append_suffix:
113 cmd += ["--partition",
114 "{}_a:readonly:{}:{}_a".format(partition, image_size, group),
115 "--partition",
116 "{}_b:readonly:0:{}_b".format(partition, group)]
117 if image:
118 # For A/B devices, super partition always contains sub-partitions in
119 # the _a slot, because this image should only be used for
120 # bootstrapping / initializing the device. When flashing the image,
121 # bootloader fastboot should always mark _a slot as bootable.
122 cmd += ["--image", "{}_a={}".format(partition, image)]
123 else:
124 cmd += ["--partition",
125 "{}:readonly:{}:{}".format(partition, image_size, group)]
126 if image:
127 cmd += ["--image", "{}={}".format(partition, image)]
128
129 if has_image:
130 cmd.append("--sparse")
131
132 cmd += ["--output", output]
133
134 common.RunAndCheckOutput(cmd)
135
136 if retrofit and has_image:
137 logger.info("Done writing images to directory %s", output)
138 else:
139 logger.info("Done writing image %s", output)
140
141
142def BuildSuperImageFromExtractedTargetFiles(inp, out):
143 info_dict = common.LoadInfoDict(inp)
144 partition_list = shlex.split(
145 info_dict.get("dynamic_partition_list", "").strip())
146 for partition in partition_list:
147 info_dict["{}_image".format(partition)] = os.path.join(
148 inp, "IMAGES", "{}.img".format(partition))
149 return BuildSuperImageFromDict(info_dict, out)
150
151
152def BuildSuperImageFromTargetFiles(inp, out):
153 input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN)
154 return BuildSuperImageFromExtractedTargetFiles(input_tmp, out)
155
156
157def BuildSuperImage(inp, out):
158
159 if isinstance(inp, dict):
160 logger.info("Building super image from info dict...")
161 return BuildSuperImageFromDict(inp, out)
162
163 if isinstance(inp, str):
164 if os.path.isdir(inp):
165 logger.info("Building super image from extracted target files...")
166 return BuildSuperImageFromExtractedTargetFiles(inp, out)
167
168 if zipfile.is_zipfile(inp):
169 logger.info("Building super image from target files...")
170 return BuildSuperImageFromTargetFiles(inp, out)
171
172 if os.path.isfile(inp):
173 with open(inp) as f:
174 lines = f.read()
175 logger.info("Building super image from info dict...")
176 return BuildSuperImageFromDict(common.LoadDictionaryFromLines(lines.split("\n")), out)
177
178 raise ValueError("{} is not a dictionary or a valid path".format(inp))
179
180
181def main(argv):
182
183 args = common.ParseOptions(argv, __doc__)
184
185 if len(args) != 2:
186 common.Usage(__doc__)
187 sys.exit(1)
188
189 common.InitLogging()
190
191 BuildSuperImage(args[0], args[1])
192
193
194if __name__ == "__main__":
195 try:
196 common.CloseInheritedPipes()
197 main(sys.argv[1:])
198 except common.ExternalError:
199 logger.exception("\n ERROR:\n")
200 sys.exit(1)
201 finally:
202 common.Cleanup()