blob: 4b94ad83f0607de0ef3f0a358f7b5b560289a7a3 [file] [log] [blame]
Doug Zongkereef39442009-04-02 12:14:19 -07001#!/usr/bin/env python
2#
3# Copyright (C) 2008 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"""
Tao Bao2aac9c92019-08-02 15:50:32 -070018Given an input target-files, produces an image zipfile suitable for use with
19'fastboot update'.
Doug Zongkereef39442009-04-02 12:14:19 -070020
21Usage: img_from_target_files [flags] input_target_files output_image_zip
22
Tao Bao2aac9c92019-08-02 15:50:32 -070023input_target_files: Path to the input target_files zip.
Daniel Normanb8a2f9d2019-04-24 12:55:51 -070024
25Flags:
Doug Zongker55d93282011-01-25 17:03:34 -080026 -z (--bootable_zip)
27 Include only the bootable images (eg 'boot' and 'recovery') in
28 the output.
29
Doug Zongkereef39442009-04-02 12:14:19 -070030"""
31
Tao Bao89fbb0f2017-01-10 10:47:58 -080032from __future__ import print_function
33
Tao Bao32fcdab2018-10-12 10:30:39 -070034import logging
Tao Bao76def242017-11-21 09:25:31 -080035import os
Doug Zongkereef39442009-04-02 12:14:19 -070036import sys
Tao Bao76def242017-11-21 09:25:31 -080037import zipfile
38
39import common
Yifan Hong0e97dbb2019-04-17 14:28:52 -070040from build_super_image import BuildSuperImage
Doug Zongkereef39442009-04-02 12:14:19 -070041
Doug Zongkercf6d5a92014-02-18 10:57:07 -080042if sys.hexversion < 0x02070000:
Tao Bao89fbb0f2017-01-10 10:47:58 -080043 print("Python 2.7 or newer is required.", file=sys.stderr)
Doug Zongkereef39442009-04-02 12:14:19 -070044 sys.exit(1)
45
Tao Bao32fcdab2018-10-12 10:30:39 -070046logger = logging.getLogger(__name__)
Doug Zongkereef39442009-04-02 12:14:19 -070047
48OPTIONS = common.OPTIONS
49
Ying Wanga0febe52013-03-20 11:02:05 -070050
Yifan Hong0e97dbb2019-04-17 14:28:52 -070051def LoadOptions(input_file):
Tao Bao2aac9c92019-08-02 15:50:32 -070052 """Loads information from input_file to OPTIONS.
Yifan Hong0e97dbb2019-04-17 14:28:52 -070053
54 Args:
Tao Bao2aac9c92019-08-02 15:50:32 -070055 input_file: Path to the root dir of an extracted target_files zip.
Yifan Hong0e97dbb2019-04-17 14:28:52 -070056 """
57 info = OPTIONS.info_dict = common.LoadInfoDict(input_file)
58
59 OPTIONS.put_super = info.get("super_image_in_update_package") == "true"
60 OPTIONS.dynamic_partition_list = info.get("dynamic_partition_list",
61 "").strip().split()
62 OPTIONS.super_device_list = info.get("super_block_devices",
63 "").strip().split()
64 OPTIONS.retrofit_dap = info.get("dynamic_partition_retrofit") == "true"
65 OPTIONS.build_super = info.get("build_super_partition") == "true"
66 OPTIONS.sparse_userimages = bool(info.get("extfs_sparse_flag"))
67
68
69def CopyInfo(input_tmp, output_zip):
Tao Bao2aac9c92019-08-02 15:50:32 -070070 """Copies the android-info.txt file from the input to the output."""
Tao Bao2ed665a2015-04-01 11:21:55 -070071 common.ZipWrite(
Yifan Hong0e97dbb2019-04-17 14:28:52 -070072 output_zip, os.path.join(input_tmp, "OTA", "android-info.txt"),
Tao Bao2ed665a2015-04-01 11:21:55 -070073 "android-info.txt")
Doug Zongkereef39442009-04-02 12:14:19 -070074
75
Yifan Hong0e97dbb2019-04-17 14:28:52 -070076def CopyUserImages(input_tmp, output_zip):
Tao Bao2aac9c92019-08-02 15:50:32 -070077 """Copies user images from the unzipped input and write to output_zip.
Yifan Hong0e97dbb2019-04-17 14:28:52 -070078
79 Args:
80 input_tmp: path to the unzipped input.
81 output_zip: a ZipFile instance to write images to.
82 """
83 dynamic_images = [p + ".img" for p in OPTIONS.dynamic_partition_list]
84
85 # Filter out system_other for launch DAP devices because it is in super image.
86 if not OPTIONS.retrofit_dap and "system" in OPTIONS.dynamic_partition_list:
87 dynamic_images.append("system_other.img")
88
89 images_path = os.path.join(input_tmp, "IMAGES")
90 # A target-files zip must contain the images since Lollipop.
91 assert os.path.exists(images_path)
92 for image in sorted(os.listdir(images_path)):
93 if OPTIONS.bootable_only and image not in ("boot.img", "recovery.img"):
94 continue
95 if not image.endswith(".img"):
96 continue
Yifan Hong0e97dbb2019-04-17 14:28:52 -070097 if OPTIONS.put_super:
98 if image == "super_empty.img":
99 continue
100 if image in dynamic_images:
101 continue
102 logger.info("writing %s to archive...", os.path.join("IMAGES", image))
103 common.ZipWrite(output_zip, os.path.join(images_path, image), image)
104
105
106def WriteSuperImages(input_tmp, output_zip):
Tao Bao2aac9c92019-08-02 15:50:32 -0700107 """Writes super images from the unzipped input into output_zip.
108
109 This is only done if super_image_in_update_package is set to "true".
Yifan Hong0e97dbb2019-04-17 14:28:52 -0700110
111 - For retrofit dynamic partition devices, copy split super images from target
112 files package.
113 - For devices launched with dynamic partitions, build super image from target
114 files package.
115
116 Args:
117 input_tmp: path to the unzipped input.
118 output_zip: a ZipFile instance to write images to.
119 """
120 if not OPTIONS.build_super or not OPTIONS.put_super:
121 return
122
123 if OPTIONS.retrofit_dap:
124 # retrofit devices already have split super images under OTA/
125 images_path = os.path.join(input_tmp, "OTA")
126 for device in OPTIONS.super_device_list:
127 image = "super_%s.img" % device
128 image_path = os.path.join(images_path, image)
129 assert os.path.exists(image_path)
130 logger.info("writing %s to archive...", os.path.join("OTA", image))
131 common.ZipWrite(output_zip, image_path, image)
132 else:
133 # super image for non-retrofit devices aren't in target files package,
134 # so build it.
135 super_file = common.MakeTempFile("super_", ".img")
136 logger.info("building super image %s...", super_file)
137 BuildSuperImage(input_tmp, super_file)
138 logger.info("writing super.img to archive...")
139 common.ZipWrite(output_zip, super_file, "super.img")
140
141
Tao Bao2aac9c92019-08-02 15:50:32 -0700142def ImgFromTargetFiles(input_file, output_file):
143 """Creates an image archive from the input target_files zip.
144
145 Args:
146 input_file: Path to the input target_files zip.
147 output_file: Output filename.
148
149 Raises:
150 ValueError: On invalid input.
151 """
152 if not zipfile.is_zipfile(input_file):
153 raise ValueError("%s is not a valid zipfile" % input_file)
154
155 logger.info("Building image zip from target files zip.")
156
157 # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py.
158 # However, common.LoadInfoDict() may read additional files under BOOT/,
159 # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip.
160 input_tmp = common.UnzipTemp(input_file)
161
162 LoadOptions(input_tmp)
163 output_zip = zipfile.ZipFile(
164 output_file, "w", compression=zipfile.ZIP_DEFLATED,
165 allowZip64=not OPTIONS.sparse_userimages)
166
167 try:
168 CopyInfo(input_tmp, output_zip)
169 CopyUserImages(input_tmp, output_zip)
170 WriteSuperImages(input_tmp, output_zip)
171 finally:
172 logger.info("cleaning up...")
173 common.ZipClose(output_zip)
174
175
Doug Zongkereef39442009-04-02 12:14:19 -0700176def main(argv):
Tao Bao76def242017-11-21 09:25:31 -0800177 # This allows modifying the value from inner function.
178 bootable_only_array = [False]
Doug Zongkereef39442009-04-02 12:14:19 -0700179
Dan Albert8b72aef2015-03-23 19:13:21 -0700180 def option_handler(o, _):
Doug Zongker55d93282011-01-25 17:03:34 -0800181 if o in ("-z", "--bootable_zip"):
Tao Bao76def242017-11-21 09:25:31 -0800182 bootable_only_array[0] = True
Doug Zongkereef39442009-04-02 12:14:19 -0700183 else:
184 return False
Doug Zongkerfdd8e692009-08-03 17:27:48 -0700185 return True
Doug Zongkereef39442009-04-02 12:14:19 -0700186
187 args = common.ParseOptions(argv, __doc__,
Doug Zongker3c84f562014-07-31 11:06:30 -0700188 extra_opts="z",
189 extra_long_opts=["bootable_zip"],
Doug Zongkereef39442009-04-02 12:14:19 -0700190 extra_option_handler=option_handler)
191
Yifan Hong0e97dbb2019-04-17 14:28:52 -0700192 OPTIONS.bootable_only = bootable_only_array[0]
Doug Zongker55d93282011-01-25 17:03:34 -0800193
Doug Zongkereef39442009-04-02 12:14:19 -0700194 if len(args) != 2:
195 common.Usage(__doc__)
196 sys.exit(1)
197
Tao Bao32fcdab2018-10-12 10:30:39 -0700198 common.InitLogging()
199
Tao Bao2aac9c92019-08-02 15:50:32 -0700200 ImgFromTargetFiles(args[0], args[1])
Doug Zongkereef39442009-04-02 12:14:19 -0700201
Tao Bao32fcdab2018-10-12 10:30:39 -0700202 logger.info("done.")
Doug Zongkereef39442009-04-02 12:14:19 -0700203
204
205if __name__ == '__main__':
206 try:
Ying Wang7e6d4e42010-12-13 16:25:36 -0800207 common.CloseInheritedPipes()
Doug Zongkereef39442009-04-02 12:14:19 -0700208 main(sys.argv[1:])
Dan Albert8b72aef2015-03-23 19:13:21 -0700209 except common.ExternalError as e:
Tao Bao32fcdab2018-10-12 10:30:39 -0700210 logger.exception("\n ERROR:\n")
Doug Zongkereef39442009-04-02 12:14:19 -0700211 sys.exit(1)
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700212 finally:
213 common.Cleanup()