build/core/Makefile
define build-userdataimage-target $(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)") @mkdir -p $(TARGET_OUT_DATA) @mkdir -p $(userdataimage_intermediates) && rm -rf $(userdataimage_intermediates)/userdata_image_info.txt $(call generate-image-prop-dictionary, $(userdataimage_intermediates)/userdata_image_info.txt,userdata,skip_fsck=true) $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH build/make/tools/releasetools/build_image.py $(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt $(INSTALLED_USERDATAIMAGE_TARGET) $(TARGET_OUT)
TARGET_OUT_DATA is out/target/product/[device]/data
INSTALLED_USERDATAIMAGE_TARGET is out/target/product/$device/userdata.img
TARGET_OUT is out/target/product/$device/system
$(userdataimage_intermediates)/userdata_image_info.txt is:
out/target/product/[device]/obj/PACKAGING/userdata_intermediates/userdata_image_info.txt:
userdata_size=4625268736 ext_mkuserimg=mkuserimg_mke2fs fs_type=ext4 extfs_sparse_flag=-s squashfs_sparse_flag=-s selinux_fc=out/target/product/$(device)/obj/ETC/file_contexts.bin_intermediates/file_contexts.bin root_dir=out/target/product/$(device)/root use_dynamic_partition_size=true skip_fsck=true
build/tools/releasetools/build_image.py
def main(argv): in_dir = argv[0] glob_dict_file = argv[1] out_file = argv[2] target_out = argv[3] glob_dict = LoadGlobalDict(glob_dict_file) if "mount_point" in glob_dict: # The caller knows the mount point and provides a dictionary needed by # BuildImage(). image_properties = glob_dict else: image_filename = os.path.basename(out_file) mount_point = "" if image_filename == "system.img": mount_point = "system" elif image_filename == "system_other.img": mount_point = "system_other" elif image_filename == "userdata.img": mount_point = "data" elif image_filename == "cache.img": mount_point = "cache" elif image_filename == "vendor.img": mount_point = "vendor" elif image_filename == "odm.img": mount_point = "odm" elif image_filename == "oem.img": mount_point = "oem" elif image_filename == "product.img": mount_point = "product" elif image_filename == "product_services.img": mount_point = "product_services" else: logger.error("Unknown image file name %s", image_filename) sys.exit(1) image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) try: BuildImage(in_dir, image_properties, out_file, target_out)
def ImagePropFromGlobalDict(glob_dict, mount_point): elif mount_point == "data": # Copy the generic fs type first, override with specific one if available. copy_prop("fs_type", "fs_type") copy_prop("userdata_fs_type", "fs_type") copy_prop("userdata_size", "partition_size") copy_prop("flash_logical_block_size", "flash_logical_block_size") copy_prop("flash_erase_block_size", "flash_erase_block_size")
在prop_dict里有了partition_size prop,即device/$vendor/$product/BoardConfig.mk里define的userdata partition size
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
if (prop_dict.get("use_dynamic_partition_size") == "true" and
"partition_size" not in prop_dict):
//not the case
...
//the case
prop_dict["image_size"] = prop_dict["partition_size"] //image_size即为userdata partition size definition
mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
def BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config):
if fs_type.startswith("ext"):
build_command = [prop_dict["ext_mkuserimg"]] //ext_mkuserimg值为mkuserimg_mke2fs
build_command.append(prop_dict["image_size"])
if "extfs_inode_count" in prop_dict: //以userdata.img为例,它在userdata_image_info.txt里是没有define inode count的
build_command.extend(["-i", prop_dict["extfs_inode_count"]])
build_command.extend(["--inode_size", "256"])
if "selinux_fc" in prop_dict:
build_command.append(prop_dict["selinux_fc"])
//将执行ext_mkuserimg,即执行mkuserimg_mke2fs.py
mkfs_output = common.RunAndCheckOutput(build_command)
system\extras\ext4_utils\Mkuserimg_mke2fs.py
def main(argv): args = ParseArguments(argv) if args.mount_point[0] != ‘/‘: args.mount_point = ‘/‘ + args.mount_point if not args.fs_size: logging.error("Size of the filesystem is required") sys.exit(2) mke2fs_cmd, e2fsdroid_cmd = ConstructE2fsCommands(args)
def ParseArguments(argv): parser.add_argument("src_dir", help="The source directory for user image.") parser.add_argument("output_file", help="The path of the output image file.") parser.add_argument("ext_variant", choices=["ext2", "ext4"], help="Variant of the extended filesystem.") parser.add_argument("mount_point", help="The mount point for user image.") parser.add_argument("fs_size", help="Size of the file system.") //即userdata partition size definition parser.add_argument("--inodes", "-i", help="The extfs inodes count (mke2fs).") parser.add_argument("--inode_size", "-I", help="The extfs inode size (mke2fs).")
def ConstructE2fsCommands(args): BLOCKSIZE = 4096 if args.inodes: mke2fs_opts += ["-N", args.inodes] if args.inode_size: mke2fs_opts += ["-I", args.inode_size] if args.mount_point: mke2fs_opts += ["-M", args.mount_point] # Round down the filesystem length to be a multiple of the block size blocks = int(args.fs_size) / BLOCKSIZE mke2fs_cmd = (["mke2fs"] + mke2fs_opts + ["-t", args.ext_variant, "-b", str(BLOCKSIZE), args.output_file, str(blocks)]) e2fsdroid_cmd = (["e2fsdroid"] + e2fsdroid_opts + ["-f", args.src_dir, "-a", args.mount_point, args.output_file]) return mke2fs_cmd, e2fsdroid_cmd
上述mke2fs_cmd中的blocks是userdata partition size definition/block_size(所以会将其block size对齐,block size是4K),所以生成的userdata.img里是包含userdata partition size信息的,即block count
mke2fs、e2fsdroid是可执行程序,路径在out/host/linux-x86/bin
用dumpe2fs tool解析build出来的userdata.ext4查看block count为1129216,1129216 * 4096 = 4,625,268,736,和userdata partition size definition一致:
dumpe2fs -f userdata.ext4
Block count: 1129216
BOARD_USERDATAIMAGE_PARTITION_SIZE := 4625268736
userdata.img里的block count等于userdata partition size/block_size
原文:https://www.cnblogs.com/aspirs/p/14800046.html