1bd93d425aedef907d8fef643b748897e9c7dceebYing Wang#!/usr/bin/env python 2bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# 3bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# Copyright (C) 2011 The Android Open Source Project 4bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# 5bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# Licensed under the Apache License, Version 2.0 (the "License"); 6bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# you may not use this file except in compliance with the License. 7bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# You may obtain a copy of the License at 8bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# 9bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# http://www.apache.org/licenses/LICENSE-2.0 10bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# 11bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# Unless required by applicable law or agreed to in writing, software 12bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# distributed under the License is distributed on an "AS IS" BASIS, 13bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# See the License for the specific language governing permissions and 15bd93d425aedef907d8fef643b748897e9c7dceebYing Wang# limitations under the License. 16bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 17bd93d425aedef907d8fef643b748897e9c7dceebYing Wang""" 18bd93d425aedef907d8fef643b748897e9c7dceebYing WangBuild image output_image_file from input_directory and properties_file. 19bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 20bd93d425aedef907d8fef643b748897e9c7dceebYing WangUsage: build_image input_directory properties_file output_image_file 21bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 22bd93d425aedef907d8fef643b748897e9c7dceebYing Wang""" 23bd93d425aedef907d8fef643b748897e9c7dceebYing Wangimport os 2469e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wangimport os.path 25bd93d425aedef907d8fef643b748897e9c7dceebYing Wangimport subprocess 26bd93d425aedef907d8fef643b748897e9c7dceebYing Wangimport sys 27bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 2869e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wangdef RunCommand(cmd): 2969e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang """ Echo and run the given command 3069e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang 3169e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang Args: 3269e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang cmd: the command represented as a list of strings. 3369e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang Returns: 3469e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang The exit code. 3569e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang """ 3669e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang print "Running: ", " ".join(cmd) 3769e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang p = subprocess.Popen(cmd) 3869e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang p.communicate() 3969e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang return p.returncode 40bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 41bd93d425aedef907d8fef643b748897e9c7dceebYing Wangdef BuildImage(in_dir, prop_dict, out_file): 42bd93d425aedef907d8fef643b748897e9c7dceebYing Wang """Build an image to out_file from in_dir with property prop_dict. 43bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 44bd93d425aedef907d8fef643b748897e9c7dceebYing Wang Args: 45bd93d425aedef907d8fef643b748897e9c7dceebYing Wang in_dir: path of input directory. 46bd93d425aedef907d8fef643b748897e9c7dceebYing Wang prop_dict: property dictionary. 47bd93d425aedef907d8fef643b748897e9c7dceebYing Wang out_file: path of the output image file. 48bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 49bd93d425aedef907d8fef643b748897e9c7dceebYing Wang Returns: 50bd93d425aedef907d8fef643b748897e9c7dceebYing Wang True iff the image is built successfully. 51bd93d425aedef907d8fef643b748897e9c7dceebYing Wang """ 52bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command = [] 53bd93d425aedef907d8fef643b748897e9c7dceebYing Wang fs_type = prop_dict.get("fs_type", "") 5469e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang run_fsck = False 55bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if fs_type.startswith("ext"): 56bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command = ["mkuserimg.sh"] 57bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if "extfs_sparse_flag" in prop_dict: 58bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.append(prop_dict["extfs_sparse_flag"]) 5969e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang run_fsck = True 60bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.extend([in_dir, out_file, fs_type, 61bd93d425aedef907d8fef643b748897e9c7dceebYing Wang prop_dict["mount_point"]]) 62bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if "partition_size" in prop_dict: 63bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.append(prop_dict["partition_size"]) 64f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root if "selinux_fc" in prop_dict: 65f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root build_command.append(prop_dict["selinux_fc"]) 66bd93d425aedef907d8fef643b748897e9c7dceebYing Wang else: 67bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command = ["mkyaffs2image", "-f"] 68bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if prop_dict.get("mkyaffs2_extra_flags", None): 69bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.extend(prop_dict["mkyaffs2_extra_flags"].split()) 70bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.append(in_dir) 71bd93d425aedef907d8fef643b748897e9c7dceebYing Wang build_command.append(out_file) 72f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root if "selinux_fc" in prop_dict: 73f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root build_command.append(prop_dict["selinux_fc"]) 74f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root build_command.append(prop_dict["mount_point"]) 75bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 7669e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang exit_code = RunCommand(build_command) 7769e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang if exit_code != 0: 7869e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang return False 7969e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang 806a42a25429a3313f87c8ca5154c99c7acd0eccdfYing Wang if run_fsck and prop_dict.get("skip_fsck") != "true": 8169e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang # Inflate the sparse image 8269e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang unsparse_image = os.path.join( 8369e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang os.path.dirname(out_file), "unsparse_" + os.path.basename(out_file)) 8469e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang inflate_command = ["simg2img", out_file, unsparse_image] 8569e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang exit_code = RunCommand(inflate_command) 8669e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang if exit_code != 0: 8769e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang os.remove(unsparse_image) 8869e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang return False 8969e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang 9069e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang # Run e2fsck on the inflated image file 9169e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image] 9269e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang exit_code = RunCommand(e2fsck_command) 9369e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang 9469e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang os.remove(unsparse_image) 9569e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang 9669e9b4d6d1e9647c3f9c011bad0f22138911a413Ying Wang return exit_code == 0 97bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 98bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 99bd93d425aedef907d8fef643b748897e9c7dceebYing Wangdef ImagePropFromGlobalDict(glob_dict, mount_point): 100bd93d425aedef907d8fef643b748897e9c7dceebYing Wang """Build an image property dictionary from the global dictionary. 101bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 102bd93d425aedef907d8fef643b748897e9c7dceebYing Wang Args: 103bd93d425aedef907d8fef643b748897e9c7dceebYing Wang glob_dict: the global dictionary from the build system. 104bd93d425aedef907d8fef643b748897e9c7dceebYing Wang mount_point: such as "system", "data" etc. 105bd93d425aedef907d8fef643b748897e9c7dceebYing Wang """ 106bd93d425aedef907d8fef643b748897e9c7dceebYing Wang d = {} 1079f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang 1089f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang def copy_prop(src_p, dest_p): 1099f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang if src_p in glob_dict: 1109f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang d[dest_p] = str(glob_dict[src_p]) 1119f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang 112bd93d425aedef907d8fef643b748897e9c7dceebYing Wang common_props = ( 113bd93d425aedef907d8fef643b748897e9c7dceebYing Wang "extfs_sparse_flag", 114bd93d425aedef907d8fef643b748897e9c7dceebYing Wang "mkyaffs2_extra_flags", 115f32dc71e49656e16fc8e178f7436706a47e8af52Kenny Root "selinux_fc", 1166a42a25429a3313f87c8ca5154c99c7acd0eccdfYing Wang "skip_fsck", 117bd93d425aedef907d8fef643b748897e9c7dceebYing Wang ) 118bd93d425aedef907d8fef643b748897e9c7dceebYing Wang for p in common_props: 1199f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop(p, p) 120bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 121bd93d425aedef907d8fef643b748897e9c7dceebYing Wang d["mount_point"] = mount_point 122bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if mount_point == "system": 1239f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("fs_type", "fs_type") 1249f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("system_size", "partition_size") 125bd93d425aedef907d8fef643b748897e9c7dceebYing Wang elif mount_point == "data": 1269f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("fs_type", "fs_type") 1279f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("userdata_size", "partition_size") 1289f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang elif mount_point == "cache": 1299f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("cache_fs_type", "fs_type") 1309f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang copy_prop("cache_size", "partition_size") 131a0febe5e6de24ffee5cd32944d5a1814cf312efbYing Wang elif mount_point == "vendor": 132a0febe5e6de24ffee5cd32944d5a1814cf312efbYing Wang copy_prop("vendor_fs_type", "fs_type") 133a0febe5e6de24ffee5cd32944d5a1814cf312efbYing Wang copy_prop("vendor_size", "partition_size") 134bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 135bd93d425aedef907d8fef643b748897e9c7dceebYing Wang return d 136bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 137bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 138bd93d425aedef907d8fef643b748897e9c7dceebYing Wangdef LoadGlobalDict(filename): 139bd93d425aedef907d8fef643b748897e9c7dceebYing Wang """Load "name=value" pairs from filename""" 140bd93d425aedef907d8fef643b748897e9c7dceebYing Wang d = {} 141bd93d425aedef907d8fef643b748897e9c7dceebYing Wang f = open(filename) 142bd93d425aedef907d8fef643b748897e9c7dceebYing Wang for line in f: 143bd93d425aedef907d8fef643b748897e9c7dceebYing Wang line = line.strip() 144bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if not line or line.startswith("#"): 145bd93d425aedef907d8fef643b748897e9c7dceebYing Wang continue 146bd93d425aedef907d8fef643b748897e9c7dceebYing Wang k, v = line.split("=", 1) 147bd93d425aedef907d8fef643b748897e9c7dceebYing Wang d[k] = v 148bd93d425aedef907d8fef643b748897e9c7dceebYing Wang f.close() 149bd93d425aedef907d8fef643b748897e9c7dceebYing Wang return d 150bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 151bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 152bd93d425aedef907d8fef643b748897e9c7dceebYing Wangdef main(argv): 153bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if len(argv) != 3: 154bd93d425aedef907d8fef643b748897e9c7dceebYing Wang print __doc__ 155bd93d425aedef907d8fef643b748897e9c7dceebYing Wang sys.exit(1) 156bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 157bd93d425aedef907d8fef643b748897e9c7dceebYing Wang in_dir = argv[0] 158bd93d425aedef907d8fef643b748897e9c7dceebYing Wang glob_dict_file = argv[1] 159bd93d425aedef907d8fef643b748897e9c7dceebYing Wang out_file = argv[2] 160bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 161bd93d425aedef907d8fef643b748897e9c7dceebYing Wang glob_dict = LoadGlobalDict(glob_dict_file) 162bd93d425aedef907d8fef643b748897e9c7dceebYing Wang image_filename = os.path.basename(out_file) 163bd93d425aedef907d8fef643b748897e9c7dceebYing Wang mount_point = "" 164bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if image_filename == "system.img": 165bd93d425aedef907d8fef643b748897e9c7dceebYing Wang mount_point = "system" 166bd93d425aedef907d8fef643b748897e9c7dceebYing Wang elif image_filename == "userdata.img": 167bd93d425aedef907d8fef643b748897e9c7dceebYing Wang mount_point = "data" 1689f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang elif image_filename == "cache.img": 1699f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang mount_point = "cache" 170a0febe5e6de24ffee5cd32944d5a1814cf312efbYing Wang elif image_filename == "vendor.img": 171a0febe5e6de24ffee5cd32944d5a1814cf312efbYing Wang mount_point = "vendor" 1729f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang else: 1739f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang print >> sys.stderr, "error: unknown image file name ", image_filename 1749f8e8db188371cb3787a91a03d193f87ad244ea3Ying Wang exit(1) 175bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 176bd93d425aedef907d8fef643b748897e9c7dceebYing Wang image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) 177bd93d425aedef907d8fef643b748897e9c7dceebYing Wang if not BuildImage(in_dir, image_properties, out_file): 178bd93d425aedef907d8fef643b748897e9c7dceebYing Wang print >> sys.stderr, "error: failed to build %s from %s" % (out_file, in_dir) 179bd93d425aedef907d8fef643b748897e9c7dceebYing Wang exit(1) 180bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 181bd93d425aedef907d8fef643b748897e9c7dceebYing Wang 182bd93d425aedef907d8fef643b748897e9c7dceebYing Wangif __name__ == '__main__': 183bd93d425aedef907d8fef643b748897e9c7dceebYing Wang main(sys.argv[1:]) 184