| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 1 | #!/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 | """ | 
|  | 18 | Given a target-files zipfile, produces an image zipfile suitable for | 
|  | 19 | use with 'fastboot update'. | 
|  | 20 |  | 
|  | 21 | Usage:  img_from_target_files [flags] input_target_files output_image_zip | 
|  | 22 |  | 
|  | 23 | -b  (--board_config)  <file> | 
| Doug Zongker | fdd8e69 | 2009-08-03 17:27:48 -0700 | [diff] [blame] | 24 | Deprecated. | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 25 |  | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 26 | -z  (--bootable_zip) | 
|  | 27 | Include only the bootable images (eg 'boot' and 'recovery') in | 
|  | 28 | the output. | 
|  | 29 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 30 | """ | 
|  | 31 |  | 
|  | 32 | import sys | 
|  | 33 |  | 
|  | 34 | if sys.hexversion < 0x02040000: | 
|  | 35 | print >> sys.stderr, "Python 2.4 or newer is required." | 
|  | 36 | sys.exit(1) | 
|  | 37 |  | 
| Mike Ritter | e44fade | 2009-09-15 11:18:31 -0700 | [diff] [blame] | 38 | import errno | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 39 | import os | 
|  | 40 | import re | 
|  | 41 | import shutil | 
|  | 42 | import subprocess | 
|  | 43 | import tempfile | 
|  | 44 | import zipfile | 
|  | 45 |  | 
|  | 46 | # missing in Python 2.4 and before | 
|  | 47 | if not hasattr(os, "SEEK_SET"): | 
|  | 48 | os.SEEK_SET = 0 | 
|  | 49 |  | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 50 | import build_image | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 51 | import common | 
|  | 52 |  | 
|  | 53 | OPTIONS = common.OPTIONS | 
|  | 54 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 55 | def AddUserdata(output_zip): | 
|  | 56 | """Create an empty userdata image and store it in output_zip.""" | 
|  | 57 |  | 
| Ying Wang | 4e3f44f | 2012-11-19 10:26:00 -0800 | [diff] [blame] | 58 | image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, | 
|  | 59 | "data") | 
| Ying Wang | d7321d3 | 2013-03-15 10:32:29 -0700 | [diff] [blame^] | 60 | # If no userdata_size is provided for extfs, skip userdata.img. | 
|  | 61 | if (image_props.get("fs_type", "").startswith("ext") and | 
|  | 62 | not image_props.get("partition_size")): | 
| Ying Wang | 4e3f44f | 2012-11-19 10:26:00 -0800 | [diff] [blame] | 63 | return | 
|  | 64 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 65 | print "creating userdata.img..." | 
|  | 66 |  | 
|  | 67 | # The name of the directory it is making an image out of matters to | 
|  | 68 | # mkyaffs2image.  So we create a temp dir, and within it we create an | 
|  | 69 | # empty dir named "data", and build the image from that. | 
|  | 70 | temp_dir = tempfile.mkdtemp() | 
|  | 71 | user_dir = os.path.join(temp_dir, "data") | 
|  | 72 | os.mkdir(user_dir) | 
|  | 73 | img = tempfile.NamedTemporaryFile() | 
|  | 74 |  | 
| Doug Zongker | 33a4b08 | 2010-09-21 16:12:55 -0700 | [diff] [blame] | 75 | fstab = OPTIONS.info_dict["fstab"] | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 76 | if fstab: | 
|  | 77 | image_props["fs_type" ] = fstab["/data"].fs_type | 
|  | 78 | succ = build_image.BuildImage(user_dir, image_props, img.name) | 
|  | 79 | assert succ, "build userdata.img image failed" | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 80 |  | 
| Doug Zongker | 3797473 | 2010-09-16 17:44:38 -0700 | [diff] [blame] | 81 | common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 82 | output_zip.write(img.name, "userdata.img") | 
|  | 83 | img.close() | 
|  | 84 | os.rmdir(user_dir) | 
|  | 85 | os.rmdir(temp_dir) | 
|  | 86 |  | 
|  | 87 |  | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 88 | def AddCache(output_zip): | 
|  | 89 | """Create an empty cache image and store it in output_zip.""" | 
|  | 90 |  | 
|  | 91 | image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, | 
|  | 92 | "cache") | 
|  | 93 | # The build system has to explicitly request for cache.img. | 
|  | 94 | if "fs_type" not in image_props: | 
|  | 95 | return | 
|  | 96 |  | 
|  | 97 | print "creating cache.img..." | 
|  | 98 |  | 
|  | 99 | # The name of the directory it is making an image out of matters to | 
|  | 100 | # mkyaffs2image.  So we create a temp dir, and within it we create an | 
|  | 101 | # empty dir named "cache", and build the image from that. | 
|  | 102 | temp_dir = tempfile.mkdtemp() | 
|  | 103 | user_dir = os.path.join(temp_dir, "cache") | 
|  | 104 | os.mkdir(user_dir) | 
|  | 105 | img = tempfile.NamedTemporaryFile() | 
|  | 106 |  | 
|  | 107 | fstab = OPTIONS.info_dict["fstab"] | 
|  | 108 | if fstab: | 
|  | 109 | image_props["fs_type" ] = fstab["/cache"].fs_type | 
|  | 110 | succ = build_image.BuildImage(user_dir, image_props, img.name) | 
|  | 111 | assert succ, "build cache.img image failed" | 
|  | 112 |  | 
|  | 113 | common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) | 
|  | 114 | output_zip.write(img.name, "cache.img") | 
|  | 115 | img.close() | 
|  | 116 | os.rmdir(user_dir) | 
|  | 117 | os.rmdir(temp_dir) | 
|  | 118 |  | 
|  | 119 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 120 | def AddSystem(output_zip): | 
|  | 121 | """Turn the contents of SYSTEM into a system image and store it in | 
|  | 122 | output_zip.""" | 
|  | 123 |  | 
|  | 124 | print "creating system.img..." | 
|  | 125 |  | 
|  | 126 | img = tempfile.NamedTemporaryFile() | 
|  | 127 |  | 
|  | 128 | # The name of the directory it is making an image out of matters to | 
|  | 129 | # mkyaffs2image.  It wants "system" but we have a directory named | 
|  | 130 | # "SYSTEM", so create a symlink. | 
| Mike Ritter | e44fade | 2009-09-15 11:18:31 -0700 | [diff] [blame] | 131 | try: | 
|  | 132 | os.symlink(os.path.join(OPTIONS.input_tmp, "SYSTEM"), | 
|  | 133 | os.path.join(OPTIONS.input_tmp, "system")) | 
|  | 134 | except OSError, e: | 
|  | 135 | # bogus error on my mac version? | 
|  | 136 | #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem | 
|  | 137 | #     os.path.join(OPTIONS.input_tmp, "system")) | 
|  | 138 | # OSError: [Errno 17] File exists | 
|  | 139 | if (e.errno == errno.EEXIST): | 
|  | 140 | pass | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 141 |  | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 142 | image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, | 
|  | 143 | "system") | 
| Doug Zongker | 33a4b08 | 2010-09-21 16:12:55 -0700 | [diff] [blame] | 144 | fstab = OPTIONS.info_dict["fstab"] | 
| Ying Wang | bd93d42 | 2011-10-28 17:02:30 -0700 | [diff] [blame] | 145 | if fstab: | 
|  | 146 | image_props["fs_type" ] = fstab["/system"].fs_type | 
|  | 147 | succ = build_image.BuildImage(os.path.join(OPTIONS.input_tmp, "system"), | 
|  | 148 | image_props, img.name) | 
|  | 149 | assert succ, "build system.img image failed" | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 150 |  | 
|  | 151 | img.seek(os.SEEK_SET, 0) | 
|  | 152 | data = img.read() | 
|  | 153 | img.close() | 
|  | 154 |  | 
| Doug Zongker | 3797473 | 2010-09-16 17:44:38 -0700 | [diff] [blame] | 155 | common.CheckSize(data, "system.img", OPTIONS.info_dict) | 
| Doug Zongker | 048e7ca | 2009-06-15 14:31:53 -0700 | [diff] [blame] | 156 | common.ZipWriteStr(output_zip, "system.img", data) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 157 |  | 
|  | 158 |  | 
|  | 159 | def CopyInfo(output_zip): | 
|  | 160 | """Copy the android-info.txt file from the input to the output.""" | 
|  | 161 | output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"), | 
|  | 162 | "android-info.txt") | 
|  | 163 |  | 
|  | 164 |  | 
|  | 165 | def main(argv): | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 166 | bootable_only = [False] | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 167 |  | 
|  | 168 | def option_handler(o, a): | 
|  | 169 | if o in ("-b", "--board_config"): | 
| Doug Zongker | fdd8e69 | 2009-08-03 17:27:48 -0700 | [diff] [blame] | 170 | pass       # deprecated | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 171 | if o in ("-z", "--bootable_zip"): | 
|  | 172 | bootable_only[0] = True | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 173 | else: | 
|  | 174 | return False | 
| Doug Zongker | fdd8e69 | 2009-08-03 17:27:48 -0700 | [diff] [blame] | 175 | return True | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 176 |  | 
|  | 177 | args = common.ParseOptions(argv, __doc__, | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 178 | extra_opts="b:z", | 
|  | 179 | extra_long_opts=["board_config=", | 
|  | 180 | "bootable_zip"], | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 181 | extra_option_handler=option_handler) | 
|  | 182 |  | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 183 | bootable_only = bootable_only[0] | 
|  | 184 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 185 | if len(args) != 2: | 
|  | 186 | common.Usage(__doc__) | 
|  | 187 | sys.exit(1) | 
|  | 188 |  | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 189 | OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) | 
| Doug Zongker | 3797473 | 2010-09-16 17:44:38 -0700 | [diff] [blame] | 190 | OPTIONS.info_dict = common.LoadInfoDict(input_zip) | 
| Ying Wang | d421f57 | 2010-08-25 20:39:41 -0700 | [diff] [blame] | 191 |  | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 192 | output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) | 
|  | 193 |  | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 194 | common.GetBootableImage( | 
|  | 195 | "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT").AddToZip(output_zip) | 
|  | 196 | common.GetBootableImage( | 
|  | 197 | "recovery.img", "recovery.img", OPTIONS.input_tmp, | 
|  | 198 | "RECOVERY").AddToZip(output_zip) | 
|  | 199 |  | 
|  | 200 | if not bootable_only: | 
|  | 201 | AddSystem(output_zip) | 
|  | 202 | AddUserdata(output_zip) | 
| Ying Wang | 9f8e8db | 2011-11-04 11:37:01 -0700 | [diff] [blame] | 203 | AddCache(output_zip) | 
| Doug Zongker | 55d9328 | 2011-01-25 17:03:34 -0800 | [diff] [blame] | 204 | CopyInfo(output_zip) | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 205 |  | 
|  | 206 | print "cleaning up..." | 
|  | 207 | output_zip.close() | 
|  | 208 | shutil.rmtree(OPTIONS.input_tmp) | 
|  | 209 |  | 
|  | 210 | print "done." | 
|  | 211 |  | 
|  | 212 |  | 
|  | 213 | if __name__ == '__main__': | 
|  | 214 | try: | 
| Ying Wang | 7e6d4e4 | 2010-12-13 16:25:36 -0800 | [diff] [blame] | 215 | common.CloseInheritedPipes() | 
| Doug Zongker | eef3944 | 2009-04-02 12:14:19 -0700 | [diff] [blame] | 216 | main(sys.argv[1:]) | 
|  | 217 | except common.ExternalError, e: | 
|  | 218 | print | 
|  | 219 | print "   ERROR: %s" % (e,) | 
|  | 220 | print | 
|  | 221 | sys.exit(1) |