System.imgはどのようにパッケージ化されていますか?

18608 ワード

makeコマンドをタップすると、最初のターゲットdroid(build/core/main.mk)が見つかり、droidはdroidに依存します.targets,droid_targets依存droidcoreとdist_files,droidcoreの依存関係は以下の通りである.
.PHONY: droidcore
droidcore: files \
	systemimage \
	$(INSTALLED_BOOTIMAGE_TARGET) \
	$(INSTALLED_RECOVERYIMAGE_TARGET) \
	$(INSTALLED_VBMETAIMAGE_TARGET) \
	$(INSTALLED_USERDATAIMAGE_TARGET) \
	$(INSTALLED_CACHEIMAGE_TARGET) \
	$(INSTALLED_BPTIMAGE_TARGET) \
	$(INSTALLED_VENDORIMAGE_TARGET) \
	$(INSTALLED_PRODUCTIMAGE_TARGET) \
	$(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \
	$(INSTALLED_FILES_FILE) \
	$(INSTALLED_FILES_FILE_VENDOR) \
	$(INSTALLED_FILES_FILE_PRODUCT) \
	$(INSTALLED_FILES_FILE_SYSTEMOTHER) \
	soong_docs

build/core/Makefileにカットすると、システムイメージがINSTALLEDに依存していることがわかります.SYSTEMIMAGE、INSTALLED_SYSTEMIMAGEまたBUILTに頼ってSYSTEMIMAGE,BUILT_システメメメメジはシステムですimg
systemimage: $(INSTALLED_SYSTEMIMAGE)
$(INSTALLED_SYSTEMIMAGE): $(BUILT_SYSTEMIMAGE) $(RECOVERY_FROM_BOOT_PATCH)

BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img

BUILTを見てみましょうSYSTEMIMAGEの依存関係:
$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(BUILD_IMAGE_SRCS)
	$(call build-systemimage-target,$@)

BUILT_SYSTEMIMAGE依存のファイルが生成されると、makefileのbuild-systemimage-target関数が呼び出されます.次にbuild-systemimage-targetの関数のプロトタイプを見てみましょう.
define build-systemimage-target
  @echo "Target system fs image: $(1)"
  $(call create-system-vendor-symlink)
  @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) $(TARGET_OUT) \
      || ( echo "Out of space? the tree size of $(TARGET_OUT) is (MB): " 1>&2 ;\
           du -sm $(TARGET_OUT) 1>&2;\
           if [ "$(INTERNAL_USERIMAGES_EXT_VARIANT)" == "ext4" ]; then \
               maxsize=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE); \
               if [ "$(BOARD_HAS_EXT4_RESERVED_BLOCKS)" == "true" ]; then \
                   maxsize=$$((maxsize - 4096 * 4096)); \
               fi; \
               echo "The max is $$(( maxsize / 1048576 )) MB." 1>&2 ;\
           else \
               echo "The max is $$(( $(BOARD_SYSTEMIMAGE_PARTITION_SIZE) / 1048576 )) MB." 1>&2 ;\
           fi; \
           mkdir -p $(DIST_DIR); cp $(INSTALLED_FILES_FILE) $(DIST_DIR)/installed-files-rescued.txt; \
           exit 1 )
endef

複雑そうに見えますが、実はshell文ばかりで、よく見ると読めます.読めなくても大丈夫です.私たちはその中の肝心な文だけに関心を持っています./build/tools/releasetools/build_image.py、その後パラメータの山に従って、私たちはこれらのパラメータに関心を持つ必要はありません.理解すれば、ここでbuild_を呼び出しました.image.py build_を開くimage.py,main関数は以下のように複雑ではありません.ここでBuildImage()を呼び出します.
def main(argv):
  if len(argv) != 4:
    print __doc__
    sys.exit(1)

  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 dictionay 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 == "oem.img":
      mount_point = "oem"
    else:
      print >> sys.stderr, "error: unknown image file name ", image_filename
      exit(1)

    image_properties = ImagePropFromGlobalDict(glob_dict, mount_point)

  if not BuildImage(in_dir, image_properties, out_file, target_out):
    print >> sys.stderr, "error: failed to build %s from %s" % (out_file,
                                                                in_dir)
    exit(1)

BuildImage()の表示を続行します.プロトタイプは次のとおりです.
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
  """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.
    target_out: path of the product out directory to read device specific FS config files.

  Returns:
    True iff the image is built successfully.
  """
  # system_root_image=true: build a system.img that combines the contents of
  # /system and the ramdisk, and can be mounted at the root of the file system.
  origin_in = in_dir
  fs_config = prop_dict.get("fs_config")
  base_fs_file = None
  if (prop_dict.get("system_root_image") == "true"
      and prop_dict["mount_point"] == "system"):
    in_dir = tempfile.mkdtemp()
    # Change the mount point to "/"
    prop_dict["mount_point"] = "/"
    if fs_config:
      # We need to merge the fs_config files of system and ramdisk.
      fd, merged_fs_config = tempfile.mkstemp(prefix="root_fs_config",
                                              suffix=".txt")
      os.close(fd)
      with open(merged_fs_config, "w") as fw:
        if "ramdisk_fs_config" in prop_dict:
          with open(prop_dict["ramdisk_fs_config"]) as fr:
            fw.writelines(fr.readlines())
        with open(fs_config) as fr:
          fw.writelines(fr.readlines())
      fs_config = merged_fs_config

  build_command = []
  fs_type = prop_dict.get("fs_type", "")
  run_fsck = False

  fs_spans_partition = True
  if fs_type.startswith("squash"):
    fs_spans_partition = False

  is_verity_partition = "verity_block_device" in prop_dict
  verity_supported = prop_dict.get("verity") == "true"
  verity_fec_supported = prop_dict.get("verity_fec") == "true"

  # Adjust the partition size to make room for the hashes if this is to be
  # verified.
  if verity_supported and is_verity_partition:
    partition_size = int(prop_dict.get("partition_size"))
    (adjusted_size, verity_size) = AdjustPartitionSizeForVerity(partition_size,
                                                                verity_fec_supported)
    if not adjusted_size:
      return False
    prop_dict["partition_size"] = str(adjusted_size)
    prop_dict["original_partition_size"] = str(partition_size)
    prop_dict["verity_size"] = str(verity_size)

  # Adjust partition size for AVB hash footer or AVB hashtree footer.
  avb_footer_type = ''
  if prop_dict.get("avb_hash_enable") == "true":
    avb_footer_type = 'hash'
  elif prop_dict.get("avb_hashtree_enable") == "true":
    avb_footer_type = 'hashtree'

  if avb_footer_type:
    avbtool = prop_dict["avb_avbtool"]
    partition_size = prop_dict["partition_size"]
    # avb_add_hash_footer_args or avb_add_hashtree_footer_args.
    additional_args = prop_dict["avb_add_" + avb_footer_type + "_footer_args"]
    max_image_size = AVBCalcMaxImageSize(avbtool, avb_footer_type, partition_size,
                                         additional_args)
    if max_image_size == 0:
      return False
    prop_dict["partition_size"] = str(max_image_size)
    prop_dict["original_partition_size"] = partition_size

  if fs_type.startswith("ext"):
    build_command = [prop_dict["ext_mkuserimg"]]
    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"]])
    build_command.append(prop_dict["partition_size"])
    if "journal_size" in prop_dict:
      build_command.extend(["-j", prop_dict["journal_size"]])
    if "timestamp" in prop_dict:
      build_command.extend(["-T", str(prop_dict["timestamp"])])
    if fs_config:
      build_command.extend(["-C", fs_config])
    if target_out:
      build_command.extend(["-D", target_out])
    if "block_list" in prop_dict:
      build_command.extend(["-B", prop_dict["block_list"]])
    if "base_fs_file" in prop_dict:
      base_fs_file = ConvertBlockMapToBaseFs(prop_dict["base_fs_file"])
      if base_fs_file is None:
        return False
      build_command.extend(["-d", base_fs_file])
    build_command.extend(["-L", prop_dict["mount_point"]])
    if "extfs_inode_count" in prop_dict:
      build_command.extend(["-i", prop_dict["extfs_inode_count"]])
    if "flash_erase_block_size" in prop_dict:
      build_command.extend(["-e", prop_dict["flash_erase_block_size"]])
    if "flash_logical_block_size" in prop_dict:
      build_command.extend(["-o", prop_dict["flash_logical_block_size"]])
    # Specify UUID and hash_seed if using mke2fs.
    if prop_dict["ext_mkuserimg"] == "mkuserimg_mke2fs.sh":
      if "uuid" in prop_dict:
        build_command.extend(["-U", prop_dict["uuid"]])
      if "hash_seed" in prop_dict:
        build_command.extend(["-S", prop_dict["hash_seed"]])
    if "selinux_fc" in prop_dict:
      build_command.append(prop_dict["selinux_fc"])
  elif fs_type.startswith("squash"):
    build_command = ["mksquashfsimage.sh"]
    build_command.extend([in_dir, out_file])
    if "squashfs_sparse_flag" in prop_dict:
      build_command.extend([prop_dict["squashfs_sparse_flag"]])
    build_command.extend(["-m", prop_dict["mount_point"]])
    if target_out:
      build_command.extend(["-d", target_out])
    if fs_config:
      build_command.extend(["-C", fs_config])
    if "selinux_fc" in prop_dict:
      build_command.extend(["-c", prop_dict["selinux_fc"]])
    if "block_list" in prop_dict:
      build_command.extend(["-B", prop_dict["block_list"]])
    if "squashfs_compressor" in prop_dict:
      build_command.extend(["-z", prop_dict["squashfs_compressor"]])
    if "squashfs_compressor_opt" in prop_dict:
      build_command.extend(["-zo", prop_dict["squashfs_compressor_opt"]])
    if "squashfs_block_size" in prop_dict:
      build_command.extend(["-b", prop_dict["squashfs_block_size"]])
    if "squashfs_disable_4k_align" in prop_dict and prop_dict.get("squashfs_disable_4k_align") == "true":
      build_command.extend(["-a"])
  elif fs_type.startswith("f2fs"):
    build_command = ["mkf2fsuserimg.sh"]
    build_command.extend([out_file, prop_dict["partition_size"]])
  else:
    print("Error: unknown filesystem type '%s'" % (fs_type))
    return False

  if in_dir != origin_in:
    # Construct a staging directory of the root file system.
    ramdisk_dir = prop_dict.get("ramdisk_dir")
    if ramdisk_dir:
      shutil.rmtree(in_dir)
      shutil.copytree(ramdisk_dir, in_dir, symlinks=True)
    staging_system = os.path.join(in_dir, "system")
    shutil.rmtree(staging_system, ignore_errors=True)
    shutil.copytree(origin_in, staging_system, symlinks=True)

  has_reserved_blocks = prop_dict.get("has_ext4_reserved_blocks") == "true"
  ext4fs_output = None

  try:
    if fs_type.startswith("ext4"):
      (ext4fs_output, exit_code) = RunCommand(build_command)
    else:
      (_, exit_code) = RunCommand(build_command)
  finally:
    if in_dir != origin_in:
      # Clean up temporary directories and files.
      shutil.rmtree(in_dir, ignore_errors=True)
      if fs_config:
        os.remove(fs_config)
    if base_fs_file is not None:
      os.remove(base_fs_file)
  if exit_code != 0:
    return False

  # Bug: 21522719, 22023465
  # There are some reserved blocks on ext4 FS (lesser of 4096 blocks and 2%).
  # We need to deduct those blocks from the available space, since they are
  # not writable even with root privilege. It only affects devices using
  # file-based OTA and a kernel version of 3.10 or greater (currently just
  # sprout).
  # Separately, check if there's enough headroom space available. This is useful for
  # devices with low disk space that have system image variation between builds.
  if (has_reserved_blocks or "partition_headroom" in prop_dict) and fs_type.startswith("ext4"):
    assert ext4fs_output is not None
    ext4fs_stats = re.compile(
        r'Created filesystem with .* (?P[0-9]+)/'
        r'(?P[0-9]+) blocks')
    m = ext4fs_stats.match(ext4fs_output.strip().split('
')[-1]) used_blocks = int(m.groupdict().get('used_blocks')) total_blocks = int(m.groupdict().get('total_blocks')) reserved_blocks = 0 headroom_blocks = 0 adjusted_blocks = total_blocks if has_reserved_blocks: reserved_blocks = min(4096, int(total_blocks * 0.02)) adjusted_blocks -= reserved_blocks if "partition_headroom" in prop_dict: headroom_blocks = int(prop_dict.get('partition_headroom')) / BLOCK_SIZE adjusted_blocks -= headroom_blocks if used_blocks > adjusted_blocks: mount_point = prop_dict.get("mount_point") print("Error: Not enough room on %s (total: %d blocks, used: %d blocks, " "reserved: %d blocks, headroom: %d blocks, available: %d blocks)" % ( mount_point, total_blocks, used_blocks, reserved_blocks, headroom_blocks, adjusted_blocks)) return False if not fs_spans_partition: mount_point = prop_dict.get("mount_point") partition_size = int(prop_dict.get("partition_size")) image_size = GetSimgSize(out_file) if image_size > partition_size: print("Error: %s image size of %d is larger than partition size of " "%d" % (mount_point, image_size, partition_size)) return False if verity_supported and is_verity_partition: ZeroPadSimg(out_file, partition_size - image_size) # create the verified image if this is to be verified if verity_supported and is_verity_partition: if not MakeVerityEnabledImage(out_file, verity_fec_supported, prop_dict): return False # Add AVB HASH or HASHTREE footer (metadata). if avb_footer_type: avbtool = prop_dict["avb_avbtool"] original_partition_size = prop_dict["original_partition_size"] partition_name = prop_dict["partition_name"] # key_path and algorithm are only available when chain partition is used. key_path = prop_dict.get("avb_key_path") algorithm = prop_dict.get("avb_algorithm") salt = prop_dict.get("avb_salt") # avb_add_hash_footer_args or avb_add_hashtree_footer_args additional_args = prop_dict["avb_add_" + avb_footer_type + "_footer_args"] if not AVBAddFooter(out_file, avbtool, avb_footer_type, original_partition_size, partition_name, key_path, algorithm, salt, additional_args): return False if run_fsck and prop_dict.get("skip_fsck") != "true": success, unsparse_image = UnsparseImage(out_file, replace=False) if not success: 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

この中にはたくさんのパラメータがありますが、実は非常に深い意味を持っています.私たちは学習段階で考慮する必要はありません.私たちが関連する問題に遭遇したとき、これらのパラメータと照らし合わせて、その機能と役割を理解する可能性があります.ここで重点的に見たのは、次のようなものです.
 if prop_dict["ext_mkuserimg"] == "mkuserimg_mke2fs.sh":
      if "uuid" in prop_dict:
        build_command.extend(["-U", prop_dict["uuid"]])
      if "hash_seed" in prop_dict:
        build_command.extend(["-S", prop_dict["hash_seed"]])

ここではmkuserimgを実行しましたmke2fs.shスクリプト、このスクリプトを見てみましょうパス:system/extras/ext 4_utils/mkuserimg_mke2fs.sh同様に、このファイルを開くとまたパラメータコマンドが山積みになっていることがわかり、見ても分からないが、私たちは依然としてその核心の部分に関心を持っているだけで、以下のように切り取っている.
MAKE_EXT4FS_CMD="mke2fs $MKE2FS_OPTS -t $EXT_VARIANT -b $BLOCKSIZE $OUTPUT_FILE $SIZE"
echo $MAKE_EXT4FS_ENV $MAKE_EXT4FS_CMD
env $MAKE_EXT4FS_ENV $MAKE_EXT4FS_CMD
if [ $? -ne 0 ]; then
  exit 4
fi

if [[ $E2FSPROGS_FAKE_TIME ]]; then
  E2FSDROID_ENV="E2FSPROGS_FAKE_TIME=$E2FSPROGS_FAKE_TIME"
fi

E2FSDROID_CMD="e2fsdroid $E2FSDROID_OPTS -f $SRC_DIR -a $MOUNT_POINT $OUTPUT_FILE"
echo $E2FSDROID_ENV $E2FSDROID_CMD
env $E2FSDROID_ENV $E2FSDROID_CMD
if [ $? -ne 0 ]; then
  rm -f $OUTPUT_FILE
  exit 4
fi

ここでは,(1)mke 2 fsパッケージがsystemを生成することを2つ行った.img(2)e 2 fsdroidはsystemを作製した.map mke 2 fs対応ソースコード:external/e 2 fsprogs/misc/mke 2 fs.c e 2 fsdroid対応ソースコード:external/e 2 fsprogs/contrib/android/e 2 fsdroid.c
深く考える:実は、正常なandroidコンパイルではsystemは生成されません.map、最後のパラメータ$OUTPUT_のためFILEは空です.androidのデザインでsystem.mapは、OTAのtarget-filesファイルを作成する際に生成され、block差分を作成する際にsystemが使用する.map、1つのblock 1つのblockのdiffを求めます.OTAのtarget-filesを作成すると、systemが再パッケージされます.img、そのフロー:add_img_to_target_filesはbuild_を直接呼び出しましたimage.pyのCreateImage()関数は、通常のパッケージシステムと同じです.imgパラメータが少し違うので、ここでblock_を追加しましたList="system.map"パラメータなので、パッケージが終了するとsystemが生成する.map
Q & A: 1、system.imgはどのように作られていますか?答:mke 2 fsツールを用いて作成した2、system.mapは何に使いますか?先に持っていたシステムimg、やはり先に使ったシステムです.map? 答:system.mapはOTAのtarget-filesファイルを作成する際にsystemを再パッケージする.img後、system.imgが作ったシステムmapは、制作が悪い場合はsystemを使います.mapファイル
足りないところ、指摘を歓迎します!