add_img_to_target_files.py revision d42e97ebb45fdc5a30799a3f37e482948d318010
1709a0978ae141198018ca9769f8d96292a8928e6Jason Sams#!/usr/bin/env python 2709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# 3709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# Copyright (C) 2014 The Android Open Source Project 4709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# 5709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# Licensed under the Apache License, Version 2.0 (the "License"); 6709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# you may not use this file except in compliance with the License. 7709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# You may obtain a copy of the License at 8709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# 9709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# http://www.apache.org/licenses/LICENSE-2.0 10709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# 11709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# Unless required by applicable law or agreed to in writing, software 12709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# distributed under the License is distributed on an "AS IS" BASIS, 13709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# See the License for the specific language governing permissions and 15709a0978ae141198018ca9769f8d96292a8928e6Jason Sams# limitations under the License. 16709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 176a236ad3a3760e8124b68a1b6220ed6e4fbfb152Stephen Hines""" 186a236ad3a3760e8124b68a1b6220ed6e4fbfb152Stephen HinesGiven a target-files zipfile that does not contain images (ie, does 19709a0978ae141198018ca9769f8d96292a8928e6Jason Samsnot have an IMAGES/ top-level subdirectory), produce the images and 20709a0978ae141198018ca9769f8d96292a8928e6Jason Samsadd them to the zipfile. 21709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 22709a0978ae141198018ca9769f8d96292a8928e6Jason SamsUsage: add_img_to_target_files [flag] target_files 2325e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines 2429809d1f95d4cd4cbc6b2f9384b3321759691e13Tim Murray -a (--add_missing) 2525e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines Build and add missing images to "IMAGES/". If this option is 2625e3af55a43faddced1a9931574dfdc3cc8ad8fdStephen Hines not specified, this script will simply exit when "IMAGES/" 27709a0978ae141198018ca9769f8d96292a8928e6Jason Sams directory exists in the target file. 28709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 2982e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang -r (--rebuild_recovery) 3082e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang Rebuild the recovery patch and write it to the system image. Only 319ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet meaningful when system image needs to be rebuilt. 329ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet 337974fc03e11f3a8dd40f794f3b33b4889483090cRahul Chaudhry --replace_verity_private_key 349ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet Replace the private key used for verity signing. (same as the option 35709a0978ae141198018ca9769f8d96292a8928e6Jason Sams in sign_target_files_apks) 36709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 37709a0978ae141198018ca9769f8d96292a8928e6Jason Sams --replace_verity_public_key 382abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni Replace the certificate (public key) used for verity verification. (same 39709a0978ae141198018ca9769f8d96292a8928e6Jason Sams as the option in sign_target_files_apks) 40709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 41709a0978ae141198018ca9769f8d96292a8928e6Jason Sams --is_signing 42709a0978ae141198018ca9769f8d96292a8928e6Jason Sams Skip building & adding the images for "userdata" and "cache" if we 43005113297b19ed256b6db9d6bc293ed9266899fcStephen Hines are signing the target files. 4444bef6fba6244292b751387f3d6c31cca96c28adChris Wailes""" 45c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 46709a0978ae141198018ca9769f8d96292a8928e6Jason Samsimport sys 47c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 48c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesif sys.hexversion < 0x02070000: 49f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes print >> sys.stderr, "Python 2.7 or newer is required." 50f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailes sys.exit(1) 5117e3cdc24776d8fdbf1ce16287b9b4dcd516708fJason Sams 52f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailesimport datetime 53f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailesimport errno 54f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailesimport os 55f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailesimport shlex 56f37121300217d3b39ab66dd9c8881bcbcad932dfChris Wailesimport shutil 57c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesimport subprocess 58c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesimport tempfile 59c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesimport zipfile 60c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 61c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesimport build_image 62c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesimport common 63c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 64c060f1435e7b9405f3be8974417fa6f410f03753Stephen HinesOPTIONS = common.OPTIONS 6514ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala 66ae2ec3febedfc29376b9104413fb4042028f1265David GrossOPTIONS.add_missing = False 6714ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt WalaOPTIONS.rebuild_recovery = False 6814ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt WalaOPTIONS.replace_verity_public_key = False 6914ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt WalaOPTIONS.replace_verity_private_key = False 70c060f1435e7b9405f3be8974417fa6f410f03753Stephen HinesOPTIONS.is_signing = False 71c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 72c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hinesdef AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None): 73c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines """Turn the contents of SYSTEM into a system image and store it in 74c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines output_zip. Returns the name of the system image file.""" 75c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines 76c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "system.img") 77c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines if os.path.exists(prebuilt_path): 78c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines print "system.img already exists in %s, no need to rebuild..." % (prefix,) 79c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines return prebuilt_path 80709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 81062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni def output_sink(fn, data): 82709a0978ae141198018ca9769f8d96292a8928e6Jason Sams ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w") 83c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines ofile.write(data) 84709a0978ae141198018ca9769f8d96292a8928e6Jason Sams ofile.close() 85709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 86709a0978ae141198018ca9769f8d96292a8928e6Jason Sams if OPTIONS.rebuild_recovery: 87709a0978ae141198018ca9769f8d96292a8928e6Jason Sams print "Building new recovery patch" 88bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, 894b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes boot_img, info_dict=OPTIONS.info_dict) 9014ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala 914b3c34e6833e39bc89c2128002806b654b8e623dChris Wailes block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map") 9214ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, 93709a0978ae141198018ca9769f8d96292a8928e6Jason Sams block_list=block_list) 946c1876bbef1b2c89975dce91230a168bd2d2ce4cDavid Gross 95ae2ec3febedfc29376b9104413fb4042028f1265David Gross common.ZipWrite(output_zip, imgname, prefix + "system.img") 96ae2ec3febedfc29376b9104413fb4042028f1265David Gross common.ZipWrite(output_zip, block_list, prefix + "system.map") 976c1876bbef1b2c89975dce91230a168bd2d2ce4cDavid Gross return imgname 98ae2ec3febedfc29376b9104413fb4042028f1265David Gross 996c1876bbef1b2c89975dce91230a168bd2d2ce4cDavid Gross 100709a0978ae141198018ca9769f8d96292a8928e6Jason Samsdef BuildSystem(input_dir, info_dict, block_list=None): 101709a0978ae141198018ca9769f8d96292a8928e6Jason Sams """Build the (sparse) system image and return the name of a temp 102709a0978ae141198018ca9769f8d96292a8928e6Jason Sams file containing it.""" 103c060f1435e7b9405f3be8974417fa6f410f03753Stephen Hines return CreateImage(input_dir, info_dict, "system", block_list=block_list) 104dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar 105709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 1068409d6414dd4a42aa59779fcfe9fce18648cb135Stephen Hinesdef AddVendor(output_zip, prefix="IMAGES/"): 1078409d6414dd4a42aa59779fcfe9fce18648cb135Stephen Hines """Turn the contents of VENDOR into a vendor image and store in it 1088409d6414dd4a42aa59779fcfe9fce18648cb135Stephen Hines output_zip.""" 1098409d6414dd4a42aa59779fcfe9fce18648cb135Stephen Hines 1105aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "vendor.img") 1118409d6414dd4a42aa59779fcfe9fce18648cb135Stephen Hines if os.path.exists(prebuilt_path): 112709a0978ae141198018ca9769f8d96292a8928e6Jason Sams print "vendor.img already exists in %s, no need to rebuild..." % (prefix,) 113709a0978ae141198018ca9769f8d96292a8928e6Jason Sams return 114709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 115dc0d8f7c0f1f43f25c34fbc04656ad578f6e953bPirama Arumuga Nainar block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map") 116709a0978ae141198018ca9769f8d96292a8928e6Jason Sams imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict, 117110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams block_list=block_list) 11840e35cdbe217ec8bf9fc3c69873c7d62fc14158fJean-Luc Brouillet common.ZipWrite(output_zip, imgname, prefix + "vendor.img") 11940e35cdbe217ec8bf9fc3c69873c7d62fc14158fJean-Luc Brouillet common.ZipWrite(output_zip, block_list, prefix + "vendor.map") 1209ab5094dd32352b33e251e540934f6e814c5fa5bJean-Luc Brouillet 12145e753a46e587c69b3b0d0c5138e88715a24a29aStephen Hines 12245e753a46e587c69b3b0d0c5138e88715a24a29aStephen Hinesdef BuildVendor(input_dir, info_dict, block_list=None): 123110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams """Build the (sparse) vendor image and return the name of a temp 124110f181b7966212a36ef18016f9b81c7322d0a2fJason Sams file containing it.""" 12514ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala return CreateImage(input_dir, info_dict, "vendor", block_list=block_list) 12614ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala 127d9bae689c1b8c3f2ed1a5f2b374dc9393584b8ddYang Ni 128709a0978ae141198018ca9769f8d96292a8928e6Jason Samsdef CreateImage(input_dir, info_dict, what, block_list=None): 129709a0978ae141198018ca9769f8d96292a8928e6Jason Sams print "creating " + what + ".img..." 130709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 131709a0978ae141198018ca9769f8d96292a8928e6Jason Sams img = common.MakeTempFile(prefix=what + "-", suffix=".img") 132da0f069871343119251d6b0586be356dc2146a62Yang Ni 1332abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni # The name of the directory it is making an image out of matters to 1342abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni # mkyaffs2image. It wants "system" but we have a directory named 13582e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang # "SYSTEM", so create a symlink. 136da0f069871343119251d6b0586be356dc2146a62Yang Ni try: 1372abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni os.symlink(os.path.join(input_dir, what.upper()), 13814ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala os.path.join(input_dir, what)) 13914ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala except OSError as e: 14014ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala # bogus error on my mac version? 14114ce007a633b10e3b9a3fae29d8f53a7e8c9b59fMatt Wala # File "./build/tools/releasetools/img_from_target_files" 14282e135c4bbe18855d8ed02632bb074f8da0b96e0Miao Wang # os.path.join(OPTIONS.input_tmp, "system")) 143cb17015fed6b11a5028f31cc804a3847e379945dYang Ni # OSError: [Errno 17] File exists 144aa6757ffc1b23d771566439c3179fdbc1e5ba569Pirama Arumuga Nainar if e.errno == errno.EEXIST: 145709a0978ae141198018ca9769f8d96292a8928e6Jason Sams pass 146709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 147709a0978ae141198018ca9769f8d96292a8928e6Jason Sams image_props = build_image.ImagePropFromGlobalDict(info_dict, what) 148709a0978ae141198018ca9769f8d96292a8928e6Jason Sams fstab = info_dict["fstab"] 149709a0978ae141198018ca9769f8d96292a8928e6Jason Sams if fstab: 150709a0978ae141198018ca9769f8d96292a8928e6Jason Sams image_props["fs_type"] = fstab["/" + what].fs_type 151709a0978ae141198018ca9769f8d96292a8928e6Jason Sams 152cb17015fed6b11a5028f31cc804a3847e379945dYang Ni # Use a fixed timestamp (01/01/2009) when packaging the image. 153cb17015fed6b11a5028f31cc804a3847e379945dYang Ni # Bug: 24377993 154cb17015fed6b11a5028f31cc804a3847e379945dYang Ni epoch = datetime.datetime.fromtimestamp(0) 155f02a2b0a2749d4a4f07edbc23eddff2e51d11b72Yang Ni timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 1567974fc03e11f3a8dd40f794f3b33b4889483090cRahul Chaudhry image_props["timestamp"] = int(timestamp) 157d9bae689c1b8c3f2ed1a5f2b374dc9393584b8ddYang Ni 158da0f069871343119251d6b0586be356dc2146a62Yang Ni if what == "system": 159da0f069871343119251d6b0586be356dc2146a62Yang Ni fs_config_prefix = "" 160da43d5866f6224e17e756fdfea405ca4b00a38fcJiyong Park else: 161cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko fs_config_prefix = what + "_" 162682672e36b05349bc4d9dee74e9fab73ce804183Pirama Arumuga Nainar 163cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko fs_config = os.path.join( 164cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko input_dir, "META/" + fs_config_prefix + "filesystem_config.txt") 165da43d5866f6224e17e756fdfea405ca4b00a38fcJiyong Park if not os.path.exists(fs_config): 166cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko fs_config = None 167cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko 168da0f069871343119251d6b0586be356dc2146a62Yang Ni # Override values loaded from info_dict. 169da0f069871343119251d6b0586be356dc2146a62Yang Ni if fs_config: 170da43d5866f6224e17e756fdfea405ca4b00a38fcJiyong Park image_props["fs_config"] = fs_config 171cfb1d0b3ed5a775689c20ce053bfc023ea9d8e5fVictor Khimenko if block_list: 172682672e36b05349bc4d9dee74e9fab73ce804183Pirama Arumuga Nainar image_props["block_list"] = block_list 173da0f069871343119251d6b0586be356dc2146a62Yang Ni 174da0f069871343119251d6b0586be356dc2146a62Yang Ni succ = build_image.BuildImage(os.path.join(input_dir, what), 1757974fc03e11f3a8dd40f794f3b33b4889483090cRahul Chaudhry image_props, img) 176709a0978ae141198018ca9769f8d96292a8928e6Jason Sams assert succ, "build " + what + ".img image failed" 177a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 178a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni return img 179a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 180a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 181a845c35880f8434619ac299e8af47aa6a5049e8dYang Nidef AddUserdata(output_zip, prefix="IMAGES/"): 182a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni """Create a userdata image and store it in output_zip. 183a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 184a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni In most case we just create and store an empty userdata.img; 185a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni But the invoker can also request to create userdata.img with real 186a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni data from the target files, by setting "userdata_img_with_data=true" 187a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni in OPTIONS.info_dict. 188a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni """ 189a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 190a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "userdata.img") 191a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni if os.path.exists(prebuilt_path): 192a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni print "userdata.img already exists in %s, no need to rebuild..." % (prefix,) 193a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni return 194a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 195a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni # Skip userdata.img if no size. 196a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "data") 197e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun if not image_props.get("partition_size"): 198e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun return 199e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun 200e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun print "creating userdata.img..." 201e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun 202e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun # Use a fixed timestamp (01/01/2009) when packaging the image. 203e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun # Bug: 24377993 204e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun epoch = datetime.datetime.fromtimestamp(0) 205e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 206e0f1e2ef6df041d4d88a4d4135c46ddcb0c50029Justin Yun image_props["timestamp"] = int(timestamp) 207a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni 208a845c35880f8434619ac299e8af47aa6a5049e8dYang Ni # The name of the directory it is making an image out of matters to 2096a236ad3a3760e8124b68a1b6220ed6e4fbfb152Stephen Hines # mkyaffs2image. So we create a temp dir, and within it we create an 210 # empty dir named "data", or a symlink to the DATA dir, 211 # and build the image from that. 212 temp_dir = tempfile.mkdtemp() 213 user_dir = os.path.join(temp_dir, "data") 214 empty = (OPTIONS.info_dict.get("userdata_img_with_data") != "true") 215 if empty: 216 # Create an empty dir. 217 os.mkdir(user_dir) 218 else: 219 # Symlink to the DATA dir. 220 os.symlink(os.path.join(OPTIONS.input_tmp, "DATA"), 221 user_dir) 222 223 img = tempfile.NamedTemporaryFile() 224 225 fstab = OPTIONS.info_dict["fstab"] 226 if fstab: 227 image_props["fs_type"] = fstab["/data"].fs_type 228 succ = build_image.BuildImage(user_dir, image_props, img.name) 229 assert succ, "build userdata.img image failed" 230 231 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) 232 common.ZipWrite(output_zip, img.name, prefix + "userdata.img") 233 img.close() 234 shutil.rmtree(temp_dir) 235 236 237def AddVBMeta(output_zip, boot_img_path, system_img_path, prefix="IMAGES/"): 238 """Create a VBMeta image and store it in output_zip.""" 239 _, img_file_name = tempfile.mkstemp() 240 avbtool = os.getenv('AVBTOOL') or "avbtool" 241 cmd = [avbtool, "make_vbmeta_image", 242 "--output", img_file_name, 243 "--include_descriptors_from_image", boot_img_path, 244 "--include_descriptors_from_image", system_img_path, 245 "--generate_dm_verity_cmdline_from_hashtree", system_img_path] 246 common.AppendAVBSigningArgs(cmd) 247 args = OPTIONS.info_dict.get("board_avb_make_vbmeta_image_args", None) 248 if args and args.strip(): 249 cmd.extend(shlex.split(args)) 250 p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 251 p.communicate() 252 assert p.returncode == 0, "avbtool make_vbmeta_image failed" 253 common.ZipWrite(output_zip, img_file_name, prefix + "vbmeta.img") 254 255 256def AddPartitionTable(output_zip, prefix="IMAGES/"): 257 """Create a partition table image and store it in output_zip.""" 258 259 _, img_file_name = tempfile.mkstemp() 260 _, bpt_file_name = tempfile.mkstemp() 261 262 # use BPTTOOL from environ, or "bpttool" if empty or not set. 263 bpttool = os.getenv("BPTTOOL") or "bpttool" 264 cmd = [bpttool, "make_table", "--output_json", bpt_file_name, 265 "--output_gpt", img_file_name] 266 input_files_str = OPTIONS.info_dict["board_bpt_input_files"] 267 input_files = input_files_str.split(" ") 268 for i in input_files: 269 cmd.extend(["--input", i]) 270 disk_size = OPTIONS.info_dict.get("board_bpt_disk_size") 271 if disk_size: 272 cmd.extend(["--disk_size", disk_size]) 273 args = OPTIONS.info_dict.get("board_bpt_make_table_args") 274 if args: 275 cmd.extend(shlex.split(args)) 276 277 p = common.Run(cmd, stdout=subprocess.PIPE) 278 p.communicate() 279 assert p.returncode == 0, "bpttool make_table failed" 280 281 common.ZipWrite(output_zip, img_file_name, prefix + "partition-table.img") 282 common.ZipWrite(output_zip, bpt_file_name, prefix + "partition-table.bpt") 283 284 285def AddCache(output_zip, prefix="IMAGES/"): 286 """Create an empty cache image and store it in output_zip.""" 287 288 prebuilt_path = os.path.join(OPTIONS.input_tmp, prefix, "cache.img") 289 if os.path.exists(prebuilt_path): 290 print "cache.img already exists in %s, no need to rebuild..." % (prefix,) 291 return 292 293 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, "cache") 294 # The build system has to explicitly request for cache.img. 295 if "fs_type" not in image_props: 296 return 297 298 print "creating cache.img..." 299 300 # Use a fixed timestamp (01/01/2009) when packaging the image. 301 # Bug: 24377993 302 epoch = datetime.datetime.fromtimestamp(0) 303 timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() 304 image_props["timestamp"] = int(timestamp) 305 306 # The name of the directory it is making an image out of matters to 307 # mkyaffs2image. So we create a temp dir, and within it we create an 308 # empty dir named "cache", and build the image from that. 309 temp_dir = tempfile.mkdtemp() 310 user_dir = os.path.join(temp_dir, "cache") 311 os.mkdir(user_dir) 312 img = tempfile.NamedTemporaryFile() 313 314 fstab = OPTIONS.info_dict["fstab"] 315 if fstab: 316 image_props["fs_type"] = fstab["/cache"].fs_type 317 succ = build_image.BuildImage(user_dir, image_props, img.name) 318 assert succ, "build cache.img image failed" 319 320 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) 321 common.ZipWrite(output_zip, img.name, prefix + "cache.img") 322 img.close() 323 os.rmdir(user_dir) 324 os.rmdir(temp_dir) 325 326 327def AddImagesToTargetFiles(filename): 328 OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename) 329 330 if not OPTIONS.add_missing: 331 for n in input_zip.namelist(): 332 if n.startswith("IMAGES/"): 333 print "target_files appears to already contain images." 334 sys.exit(1) 335 336 try: 337 input_zip.getinfo("VENDOR/") 338 has_vendor = True 339 except KeyError: 340 has_vendor = False 341 342 OPTIONS.info_dict = common.LoadInfoDict(input_zip, OPTIONS.input_tmp) 343 344 common.ZipClose(input_zip) 345 output_zip = zipfile.ZipFile(filename, "a", 346 compression=zipfile.ZIP_DEFLATED, 347 allowZip64=True) 348 349 has_recovery = (OPTIONS.info_dict.get("no_recovery") != "true") 350 system_root_image = (OPTIONS.info_dict.get("system_root_image", None) == "true") 351 352 def banner(s): 353 print "\n\n++++ " + s + " ++++\n\n" 354 355 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "boot.img") 356 boot_image = None 357 if os.path.exists(prebuilt_path): 358 banner("boot") 359 print "boot.img already exists in IMAGES/, no need to rebuild..." 360 if OPTIONS.rebuild_recovery: 361 boot_image = common.GetBootableImage( 362 "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 363 else: 364 banner("boot") 365 boot_image = common.GetBootableImage( 366 "IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 367 if boot_image: 368 boot_image.AddToZip(output_zip) 369 370 recovery_image = None 371 if has_recovery: 372 banner("recovery") 373 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img") 374 if os.path.exists(prebuilt_path): 375 print "recovery.img already exists in IMAGES/, no need to rebuild..." 376 if OPTIONS.rebuild_recovery: 377 recovery_image = common.GetBootableImage( 378 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, 379 "RECOVERY") 380 else: 381 recovery_image = common.GetBootableImage( 382 "IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") 383 if recovery_image: 384 recovery_image.AddToZip(output_zip) 385 386 banner("recovery (two-step image)") 387 # The special recovery.img for two-step package use. 388 recovery_two_step_image = common.GetBootableImage( 389 "IMAGES/recovery-two-step.img", "recovery-two-step.img", 390 OPTIONS.input_tmp, "RECOVERY", two_step_image=True) 391 if recovery_two_step_image: 392 recovery_two_step_image.AddToZip(output_zip) 393 394 banner("system") 395 system_img_path = AddSystem( 396 output_zip, recovery_img=recovery_image, boot_img=boot_image) 397 if has_vendor: 398 banner("vendor") 399 AddVendor(output_zip) 400 if not OPTIONS.is_signing: 401 banner("userdata") 402 AddUserdata(output_zip) 403 banner("cache") 404 AddCache(output_zip) 405 if OPTIONS.info_dict.get("board_bpt_enable", None) == "true": 406 banner("partition-table") 407 AddPartitionTable(output_zip) 408 if OPTIONS.info_dict.get("board_avb_enable", None) == "true": 409 banner("vbmeta") 410 boot_contents = boot_image.WriteToTemp() 411 AddVBMeta(output_zip, boot_contents.name, system_img_path) 412 413 # For devices using A/B update, copy over images from RADIO/ and/or 414 # VENDOR_IMAGES/ to IMAGES/ and make sure we have all the needed 415 # images ready under IMAGES/. All images should have '.img' as extension. 416 banner("radio") 417 ab_partitions = os.path.join(OPTIONS.input_tmp, "META", "ab_partitions.txt") 418 if os.path.exists(ab_partitions): 419 with open(ab_partitions, 'r') as f: 420 lines = f.readlines() 421 for line in lines: 422 img_name = line.strip() + ".img" 423 prebuilt_path = os.path.join(OPTIONS.input_tmp, "IMAGES", img_name) 424 if os.path.exists(prebuilt_path): 425 print "%s already exists, no need to overwrite..." % (img_name,) 426 continue 427 428 img_radio_path = os.path.join(OPTIONS.input_tmp, "RADIO", img_name) 429 img_vendor_dir = os.path.join( 430 OPTIONS.input_tmp, "VENDOR_IMAGES") 431 if os.path.exists(img_radio_path): 432 common.ZipWrite(output_zip, img_radio_path, 433 os.path.join("IMAGES", img_name)) 434 else: 435 for root, _, files in os.walk(img_vendor_dir): 436 if img_name in files: 437 common.ZipWrite(output_zip, os.path.join(root, img_name), 438 os.path.join("IMAGES", img_name)) 439 break 440 441 # Zip spec says: All slashes MUST be forward slashes. 442 img_path = 'IMAGES/' + img_name 443 assert img_path in output_zip.namelist(), "cannot find " + img_name 444 445 common.ZipClose(output_zip) 446 447def main(argv): 448 def option_handler(o, a): 449 if o in ("-a", "--add_missing"): 450 OPTIONS.add_missing = True 451 elif o in ("-r", "--rebuild_recovery",): 452 OPTIONS.rebuild_recovery = True 453 elif o == "--replace_verity_private_key": 454 OPTIONS.replace_verity_private_key = (True, a) 455 elif o == "--replace_verity_public_key": 456 OPTIONS.replace_verity_public_key = (True, a) 457 elif o == "--is_signing": 458 OPTIONS.is_signing = True 459 else: 460 return False 461 return True 462 463 args = common.ParseOptions( 464 argv, __doc__, extra_opts="ar", 465 extra_long_opts=["add_missing", "rebuild_recovery", 466 "replace_verity_public_key=", 467 "replace_verity_private_key=", 468 "is_signing"], 469 extra_option_handler=option_handler) 470 471 472 if len(args) != 1: 473 common.Usage(__doc__) 474 sys.exit(1) 475 476 AddImagesToTargetFiles(args[0]) 477 print "done." 478 479if __name__ == '__main__': 480 try: 481 common.CloseInheritedPipes() 482 main(sys.argv[1:]) 483 except common.ExternalError as e: 484 print 485 print " ERROR: %s" % (e,) 486 print 487 sys.exit(1) 488 finally: 489 common.Cleanup() 490