最近在學習python,基礎知識學習了一遍。我的學習習慣是:了解了基礎語法后,去閱讀開源代碼(掌握優秀程序員的一些寫代碼習慣和手法),最后結合項目實踐,實踐的過程對某些細節進行深化。 想起android編譯系統中有一些python腳本,下面對build_image.py進行簡單分析。
生成系統鏡像的target在build/core/Makefile中,
#----------build/core/Makefile-------------# $(1): output filedefine build-systemimage-target @echo "Target system fs image: $(1)" @mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt $(call generate-userimage-PRop-dictionary, $(systemimage_intermediates)/system_image_info.txt, skip_fsck=true) $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH / ./build/tools/releasetools/build_image.py / $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1)endef其中,可以看出來主要是借助了build_image.py去生成鏡像,/build/tools/releasetools/build_image.py $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1)
, 有三個參數,一個是作為輸入的文件目錄,system_image_info.txt,和最終生成的鏡像名,例如system.img。
由于上面makefile中是在shell中直接調用build_image.py(不是import 模塊),所以__name__
為__main__
,會直接調用main
函數,
其中,system_image_info.txt一個例子如下所示,一些參數及其值,
fs_type=ext4system_size=1288491008userdata_size=5835325440cache_fs_type=ext4cache_size=268435456extfs_sparse_flag=-sselinux_fc=out/target/product/msm8916_64/root/file_contextsverity=trueverity_key=build/target/product/security/verityverity_signer_cmd=out/host/linux-x86/bin/verity_signersystem_verity_block_device=/dev/block/bootdevice/by-name/systemskip_fsck=trueLoadGlobalDict函數如下,將system_image_info.txt中的內容保存到字典中,例如{‘fs_type’:’ext4’,…..}
def LoadGlobalDict(filename): """Load "name=value" pairs from filename""" d = {} f = open(filename) #對文件對象的迭代 #文件中#不處理,是注釋 #strip去除字符串兩頭,不包括內部的空格 #split將字符串分割成序列 str.split(sep=None, maxsplit=-1) #If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). #>>>'1,2,3'.split(',', maxsplit=1) #['1', '2,3'] #所以用=分割,只有=前面和后面2個元素 for line in f: line = line.strip() if not line or line.startswith("#"): continue k, v = line.split("=", 1) d[k] = v f.close() return dImagePropFromGlobalDict函數,從全局字典(system_image_info.txt中有些東西不是都有用)取出需要的東西,返回一個新字典。
def ImagePropFromGlobalDict(glob_dict, mount_point): """Build an image property dictionary from the global dictionary. Args: glob_dict: the global dictionary from the build system. mount_point: such as "system", "data" etc. """ d = {} def copy_prop(src_p, dest_p): if src_p in glob_dict: d[dest_p] = str(glob_dict[src_p]) #extfs_sparse_flag=-s #skip_fsck=true #selinux_fc=out/target/product/msm8916_64/root/file_contexts #將common_props屬性中的值保存到新建的字典d中, common_props = ( "extfs_sparse_flag", "mkyaffs2_extra_flags", "selinux_fc", "skip_fsck", ) for p in common_props: copy_prop(p, p) #添加'mount_point':'system' d["mount_point"] = mount_point if mount_point == "system": #'fs_type':'ext4' #'partition_size':'1288491008' copy_prop("fs_type", "fs_type") copy_prop("system_size", "partition_size") elif mount_point == "data": copy_prop("fs_type", "fs_type") copy_prop("userdata_size", "partition_size") elif mount_point == "cache": copy_prop("cache_fs_type", "fs_type") copy_prop("cache_size", "partition_size") elif mount_point == "vendor": copy_prop("vendor_fs_type", "fs_type") copy_prop("vendor_size", "partition_size") return d最后調用BuildImage函數,其實就是組了一個命令,然后執行該命令(mkuserimg.sh -s in_dir out_file ext4 system 1288491008 out/target/product/msm8916_64/root/file_contexts)。
def BuildImage(in_dir, prop_dict, out_file): """Build an image to out_file from in_dir with property prop_dict. Args: in_dir: path of input directory. prop_dict: property dictionary. out_file: path of the output image file. Returns: True iff the image is built successfully. """ build_command = [] #字典的get方法,如果鍵不存在,沒有任何異常,而得到None fs_type = prop_dict.get("fs_type", "") run_fsck = False #文件系統以ext開頭 #這里是ext4,走這里,其實就是組一個要執行的命令 mkuserimg.sh -s in_dir out_file ext4 system 1288491008 out/target/product/msm8916_64/root/file_contexts if fs_type.startswith("ext"): build_command = ["mkuserimg.sh"] if "extfs_sparse_flag" in prop_dict: build_command.append(prop_dict["extfs_sparse_flag"]) run_fsck = True build_command.extend([in_dir, out_file, fs_type, prop_dict["mount_point"]]) if "partition_size" in prop_dict: build_command.append(prop_dict["partition_size"]) if "selinux_fc" in prop_dict: build_command.append(prop_dict["selinux_fc"]) else: build_command = ["mkyaffs2image", "-f"] #split用于將字符串分割成list,沒有參數表示用空格分割 if prop_dict.get("mkyaffs2_extra_flags", None): build_command.extend(prop_dict["mkyaffs2_extra_flags"].split()) build_command.append(in_dir) build_command.append(out_file) if "selinux_fc" in prop_dict: build_command.append(prop_dict["selinux_fc"]) build_command.append(prop_dict["mount_point"]) #執行該命令mkuserimg.sh -s in_dir out_file ext4 system exit_code = RunCommand(build_command) if exit_code != 0: return False# >>> os.path.dirname('c://Python//a.txt') 返回目錄# 'c://Python'# >>> os.path.basename('c://Python//a.txt') 返回文件名# 'a.txt'# os.path.join連接目錄與文件名或目錄 #skip_fsck=true,不走這里 if run_fsck and prop_dict.get("skip_fsck") != "true": # Inflate the sparse image unsparse_image = os.path.join( os.path.dirname(out_file), "unsparse_" + os.path.basename(out_file)) inflate_command = ["simg2img", out_file, unsparse_image] exit_code = RunCommand(inflate_command) #This function is semantically identical to unlink(). #remove和unlink一樣 if exit_code != 0: os.remove(unsparse_image) return False # Run e2fsck on the inflated image file e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image] exit_code = RunCommand(e2fsck_command) os.remove(unsparse_image) return exit_code == 0其中,RunCommand其實就類似于c語言中的system(),執行一段命令,獲取返回值,用popen實現的。
def RunCommand(cmd): """ Echo and run the given command Args: cmd: the command represented as a list of strings. Returns: The exit code. """ print "Running: ", " ".join(cmd) #創建子進程 p = subprocess.Popen(cmd) #等待子進程執行完 p.communicate() return p.returncode最終其實是調用了mkuserimg.sh腳本,腳本核心是調用make_ext4fs 應用程序
#system/extras/ext4_utils/mkuserimg.shfunction usage() {cat<<EOTUsage:mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [FILE_CONTEXTS]EOT}echo "in mkuserimg.sh PATH=$PATH"ENABLE_SPARSE_IMAGE=if [ "$1" = "-s" ]; then ENABLE_SPARSE_IMAGE="-s" shiftfiif [ $# -ne 5 -a $# -ne 6 ]; then usage exit 1fiSRC_DIR=$1if [ ! -d $SRC_DIR ]; then echo "Can not find directory $SRC_DIR!" exit 2fiOUTPUT_FILE=$2EXT_VARIANT=$3MOUNT_POINT=$4SIZE=$5FC=$6case $EXT_VARIANT in ext4) ;; *) echo "Only ext4 is supported!"; exit 3 ;;esacif [ -z $MOUNT_POINT ]; then echo "Mount point is required" exit 2fiif [ -z $SIZE ]; then echo "Need size of filesystem" exit 2fiif [ -n "$FC" ]; then FCOPT="-S $FC"fi#核心是make_ext4fs 應用程序MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"echo $MAKE_EXT4FS_CMD$MAKE_EXT4FS_CMDif [ $? -ne 0 ]; then exit 4fi而make_ext4fs 應用程序具體在system/extras/ext4_utils
中生成,makefile如下,其中makefile中有兩個make_ext4fs
的module,一個是host(BUILD_HOST_EXECUTABLE),一個是target的(BUILD_EXECUTABLE),這個命令是在編譯機調用,也就是host上而不是target上。
新聞熱點
疑難解答