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