1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2014 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 that does not contain images (ie, does 19 not have an IMAGES/ top-level subdirectory), produce the images and 20 add them to the zipfile. 21 22 Usage: add_img_to_target_files target_files 23 """ 24 25 import sys 26 27 if sys.hexversion < 0x02070000: 28 print >> sys.stderr, "Python 2.7 or newer is required." 29 sys.exit(1) 30 31 import errno 32 import os 33 import re 34 import shutil 35 import subprocess 36 import tempfile 37 import zipfile 38 39 # missing in Python 2.4 and before 40 if not hasattr(os, "SEEK_SET"): 41 os.SEEK_SET = 0 42 43 import build_image 44 import common 45 46 OPTIONS = common.OPTIONS 47 48 49 def AddSystem(output_zip, prefix="IMAGES/"): 50 """Turn the contents of SYSTEM into a system image and store it in 51 output_zip.""" 52 block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map") 53 imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, 54 block_list=block_list) 55 with open(imgname, "rb") as f: 56 common.ZipWriteStr(output_zip, prefix + "system.img", f.read()) 57 with open(block_list, "rb") as f: 58 common.ZipWriteStr(output_zip, prefix + "system.map", f.read()) 59 60 61 def BuildSystem(input_dir, info_dict, block_list=None): 62 """Build the (sparse) system image and return the name of a temp 63 file containing it.""" 64 return CreateImage(input_dir, info_dict, "system", block_list=block_list) 65 66 67 def AddVendor(output_zip, prefix="IMAGES/"): 68 """Turn the contents of VENDOR into a vendor image and store in it 69 output_zip.""" 70 block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map") 71 imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict, 72 block_list=block_list) 73 with open(imgname, "rb") as f: 74 common.ZipWriteStr(output_zip, prefix + "vendor.img", f.read()) 75 with open(block_list, "rb") as f: 76 common.ZipWriteStr(output_zip, prefix + "vendor.map", f.read()) 77 78 79 def BuildVendor(input_dir, info_dict, block_list=None): 80 """Build the (sparse) vendor image and return the name of a temp 81 file containing it.""" 82 return CreateImage(input_dir, info_dict, "vendor", block_list=block_list) 83 84 85 def CreateImage(input_dir, info_dict, what, block_list=None): 86 print "creating " + what + ".img..." 87 88 img = common.MakeTempFile(prefix=what + "-", suffix=".img") 89 90 # The name of the directory it is making an image out of matters to 91 # mkyaffs2image. It wants "system" but we have a directory named 92 # "SYSTEM", so create a symlink. 93 try: 94 os.symlink(os.path.join(input_dir, what.upper()), 95 os.path.join(input_dir, what)) 96 except OSError, e: 97 # bogus error on my mac version? 98 # File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem 99 # os.path.join(OPTIONS.input_tmp, "system")) 100 # OSError: [Errno 17] File exists 101 if (e.errno == errno.EEXIST): 102 pass 103 104 image_props = build_image.ImagePropFromGlobalDict(info_dict, what) 105 fstab = info_dict["fstab"] 106 if fstab: 107 image_props["fs_type" ] = fstab["/" + what].fs_type 108 109 if what == "system": 110 fs_config_prefix = "" 111 else: 112 fs_config_prefix = what + "_" 113 114 fs_config = os.path.join( 115 input_dir, "META/" + fs_config_prefix + "filesystem_config.txt") 116 if not os.path.exists(fs_config): fs_config = None 117 118 fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts") 119 if not os.path.exists(fc_config): fc_config = None 120 121 succ = build_image.BuildImage(os.path.join(input_dir, what), 122 image_props, img, 123 fs_config=fs_config, 124 fc_config=fc_config, 125 block_list=block_list) 126 assert succ, "build " + what + ".img image failed" 127 128 return img 129 130 131 def AddUserdata(output_zip, prefix="IMAGES/"): 132 """Create an empty userdata image and store it in output_zip.""" 133 134 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 135 "data") 136 # We only allow yaffs to have a 0/missing partition_size. 137 # Extfs, f2fs must have a size. Skip userdata.img if no size. 138 if (not image_props.get("fs_type", "").startswith("yaffs") and 139 not image_props.get("partition_size")): 140 return 141 142 print "creating userdata.img..." 143 144 # The name of the directory it is making an image out of matters to 145 # mkyaffs2image. So we create a temp dir, and within it we create an 146 # empty dir named "data", and build the image from that. 147 temp_dir = tempfile.mkdtemp() 148 user_dir = os.path.join(temp_dir, "data") 149 os.mkdir(user_dir) 150 img = tempfile.NamedTemporaryFile() 151 152 fstab = OPTIONS.info_dict["fstab"] 153 if fstab: 154 image_props["fs_type" ] = fstab["/data"].fs_type 155 succ = build_image.BuildImage(user_dir, image_props, img.name) 156 assert succ, "build userdata.img image failed" 157 158 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) 159 output_zip.write(img.name, prefix + "userdata.img") 160 img.close() 161 os.rmdir(user_dir) 162 os.rmdir(temp_dir) 163 164 165 def AddCache(output_zip, prefix="IMAGES/"): 166 """Create an empty cache image and store it in output_zip.""" 167 168 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 169 "cache") 170 # The build system has to explicitly request for cache.img. 171 if "fs_type" not in image_props: 172 return 173 174 print "creating cache.img..." 175 176 # The name of the directory it is making an image out of matters to 177 # mkyaffs2image. So we create a temp dir, and within it we create an 178 # empty dir named "cache", and build the image from that. 179 temp_dir = tempfile.mkdtemp() 180 user_dir = os.path.join(temp_dir, "cache") 181 os.mkdir(user_dir) 182 img = tempfile.NamedTemporaryFile() 183 184 fstab = OPTIONS.info_dict["fstab"] 185 if fstab: 186 image_props["fs_type" ] = fstab["/cache"].fs_type 187 succ = build_image.BuildImage(user_dir, image_props, img.name) 188 assert succ, "build cache.img image failed" 189 190 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) 191 output_zip.write(img.name, prefix + "cache.img") 192 img.close() 193 os.rmdir(user_dir) 194 os.rmdir(temp_dir) 195 196 197 def AddImagesToTargetFiles(filename): 198 OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename) 199 200 for n in input_zip.namelist(): 201 if n.startswith("IMAGES/"): 202 print "target_files appears to already contain images." 203 sys.exit(1) 204 205 try: 206 input_zip.getinfo("VENDOR/") 207 has_vendor = True 208 except KeyError: 209 has_vendor = False 210 211 OPTIONS.info_dict = common.LoadInfoDict(input_zip) 212 if "selinux_fc" in OPTIONS.info_dict: 213 OPTIONS.info_dict["selinux_fc"] = os.path.join( 214 OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts") 215 216 input_zip.close() 217 output_zip = zipfile.ZipFile(filename, "a", 218 compression=zipfile.ZIP_DEFLATED) 219 220 def banner(s): 221 print "\n\n++++ " + s + " ++++\n\n" 222 223 banner("boot") 224 boot_image = common.GetBootableImage( 225 "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 226 if boot_image: 227 boot_image.AddToZip(output_zip) 228 229 banner("recovery") 230 recovery_image = common.GetBootableImage( 231 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") 232 if recovery_image: 233 recovery_image.AddToZip(output_zip) 234 235 banner("system") 236 AddSystem(output_zip) 237 if has_vendor: 238 banner("vendor") 239 AddVendor(output_zip) 240 banner("userdata") 241 AddUserdata(output_zip) 242 banner("cache") 243 AddCache(output_zip) 244 245 output_zip.close() 246 247 248 def main(argv): 249 args = common.ParseOptions(argv, __doc__) 250 251 if len(args) != 1: 252 common.Usage(__doc__) 253 sys.exit(1) 254 255 AddImagesToTargetFiles(args[0]) 256 print "done." 257 258 if __name__ == '__main__': 259 try: 260 common.CloseInheritedPipes() 261 main(sys.argv[1:]) 262 except common.ExternalError, e: 263 print 264 print " ERROR: %s" % (e,) 265 print 266 sys.exit(1) 267 finally: 268 common.Cleanup() 269