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