android10 super.img編譯

make superiamge

superiamge是僞目標,依賴於INSTALLED_SUPERIMAGE_TARGET

# For devices that uses super image directly, the superimage target points to the file in $(PRODUCT_OUT).
.PHONY: superimage
superimage: $(INSTALLED_SUPERIMAGE_TARGET)

INSTALLED_SUPERIMAGE_TARGET

這個INSTALLED_SUPERIMAGE_TARGET就厲害了,它就是我們的本文要克服的小目標super.img

INSTALLED_SUPERIMAGE_TARGET := $(PRODUCT_OUT)/super.img

牛逼哄哄的droidcore就依賴於它

droidcore: $(INSTALLED_SUPERIMAGE_TARGET)

規則

既然確定了INSTALLED_SUPERIMAGE_TARGET是我們的小目標,我們就要看看它對應的規則

# If BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT is set, super.img is built from images in the
# $(PRODUCT_OUT) directory, and is built to $(PRODUCT_OUT)/super.img. Also, it will
# be built for non-dist builds. This is useful for devices that uses super.img directly, e.g.
# virtual devices.
ifeq (true,$(BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT))
$(INSTALLED_SUPERIMAGE_TARGET): $(INSTALLED_SUPERIMAGE_DEPENDENCIES)
	$(call pretty,"Target super fs image for debug: $@")
	$(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\
	  $(call intermediates-dir-for,PACKAGING,superimage_debug)/misc_info.txt)

MTK項目中BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT爲true,高通則不是

高通走的INTERNAL_SUPERIMAGE_DIST_TARGET這一套(根目錄下搞了build.sh作爲編譯入口),暫且不說

再來看看它的依賴INSTALLED_SUPERIMAGE_DEPENDENCIES

INSTALLED_SUPERIMAGE_DEPENDENCIES := $(LPMAKE) $(BUILD_SUPER_IMAGE) \
    $(foreach p, $(BOARD_SUPER_PARTITION_PARTITION_LIST), $(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET))

make superimage-nodeps or make supernod

superimage-nodepssupernod,類似於systemimage-nodepssnod這一套

這個規則拋棄了很多依賴,邏輯簡單了一些,咱們下面來看看

規則

可以看到之前的INSTALLED_SUPERIMAGE_DEPENDENCIES作爲了order-only request了。

可以明目張膽的不理這些亂七八糟的依賴了,直接開搞。

# Build $(PRODUCT_OUT)/super.img without dependencies.
.PHONY: superimage-nodeps supernod
superimage-nodeps supernod: intermediates :=
superimage-nodeps supernod: | $(INSTALLED_SUPERIMAGE_DEPENDENCIES)
	$(call pretty,"make $(INSTALLED_SUPERIMAGE_TARGET): ignoring dependencies")
	$(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\
	  $(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt)

命令

規則下面兩個命令:

命令1,打印下log,意思意思。告知開發者,我開搞了,您稍後

$(call pretty,"make $(INSTALLED_SUPERIMAGE_TARGET): ignoring dependencies")

命令2,super.img打包的主體邏輯

$(call build-superimage-target,$(INSTALLED_SUPERIMAGE_TARGET),\
	  $(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt)

我們可以看到它調用了build-superimage-target函數,並傳入了兩個參數

$(INSTALLED_SUPERIMAGE_TARGET)$(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt

參數1,沒啥講的,不說了

參數2,這個就有意思了,我們繼續往下看

intermediates-dir-for宏函數

這個宏函數在/build/make/core/definitions.mk中定義。

作用是,返回指定格式的OUT目錄(帶_intermediates後綴)

可以傳入6個參數,返回的是一個字符串,具體見倒數第3行

$(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates

###########################################################
## The intermediates directory.  Where object files go for
## a given target.  We could technically get away without
## the "_intermediates" suffix on the directory, but it's
## nice to be able to grep for that string to find out if
## anyone's abusing the system.
###########################################################

# $(1): target class, like "APPS"
# $(2): target name, like "NotePad"
# $(3): { HOST, HOST_CROSS, AUX, <empty (TARGET)>, <other non-empty (HOST)> }
# $(4): if non-empty, force the intermediates to be COMMON
# $(5): if non-empty, force the intermediates to be for the 2nd arch
# $(6): if non-empty, force the intermediates to be for the host cross os

define intermediates-dir-for
$(strip \
    $(eval _idfClass := $(strip $(1))) \
    $(if $(_idfClass),, \
        $(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \
    $(eval _idfName := $(strip $(2))) \
    $(if $(_idfName),, \
        $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \
    $(eval _idfPrefix := $(call find-idf-prefix,$(3),$(6))) \
    $(eval _idf2ndArchPrefix := $(if $(strip $(5)),$(TARGET_2ND_ARCH_VAR_PREFIX))) \
    $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \
        $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \
      ,$(if $(filter $(_idfClass),$(PER_ARCH_MODULE_CLASSES)),\
          $(eval _idfIntBase := $($(_idf2ndArchPrefix)$(_idfPrefix)_OUT_INTERMEDIATES)) \
       ,$(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \
       ) \
     ) \
    $(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \
)
endef

misc_info.txt

參數2,現在弄明白了,是misc_info.txt文件的路徑(帶_intermediates後綴的Android標準obj目錄格式)

`$(call intermediates-dir-for,PACKAGING,superimage-nodeps)/misc_info.txt`

build-superimage-target

這個函數就厲害了,是我們make supernod主體邏輯之所在

# Build super.img by using $(INSTALLED_*IMAGE_TARGET) to $(1)
# $(1): built image path
# $(2): misc_info.txt path; its contents should match expectation of build_super_image.py
define build-superimage-target
  mkdir -p $(dir $(2))
  rm -rf $(2)
  $(call dump-super-image-info,$(2))
  $(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
    echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(2);)
  mkdir -p $(dir $(1))
  PATH=$(dir $(LPMAKE)):$$PATH \
    $(BUILD_SUPER_IMAGE) -v $(2) $(1)
endef

這一上來,創建目錄mkdir -p $(dir $(2))並刪除舊文件rm -rf $(2)自不必說

我們看下這個dump-super-image-info宏函數

dump-super-image

# Dump variables used by build_super_image.py.
define dump-super-image-info
  $(call dump-dynamic-partitions-info,$(1))
  $(if $(filter true,$(AB_OTA_UPDATER)), \
    echo "ab_update=true" >> $(1))
endef

看來是個套娃,繼續往下找dump-dynamic-partitions-info

dump-dynamic-partitions-info

# $(1): file
define dump-dynamic-partitions-info
  $(if $(filter true,$(PRODUCT_USE_DYNAMIC_PARTITIONS)), \
    echo "use_dynamic_partitions=true" >> $(1))
  $(if $(filter true,$(PRODUCT_RETROFIT_DYNAMIC_PARTITIONS)), \
    echo "dynamic_partition_retrofit=true" >> $(1))
  echo "lpmake=$(notdir $(LPMAKE))" >> $(1)
  $(if $(filter true,$(PRODUCT_BUILD_SUPER_PARTITION)), $(if $(BOARD_SUPER_PARTITION_SIZE), \
    echo "build_super_partition=true" >> $(1)))
  $(if $(filter true,$(BOARD_BUILD_RETROFIT_DYNAMIC_PARTITIONS_OTA_PACKAGE)), \
    echo "build_retrofit_dynamic_partitions_ota_package=true" >> $(1))
  echo "super_metadata_device=$(BOARD_SUPER_PARTITION_METADATA_DEVICE)" >> $(1)
  $(if $(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \
    echo "super_block_devices=$(BOARD_SUPER_PARTITION_BLOCK_DEVICES)" >> $(1))
  $(foreach device,$(BOARD_SUPER_PARTITION_BLOCK_DEVICES), \
    echo "super_$(device)_device_size=$(BOARD_SUPER_PARTITION_$(call to-upper,$(device))_DEVICE_SIZE)" >> $(1);)
  $(if $(BOARD_SUPER_PARTITION_PARTITION_LIST), \
    echo "dynamic_partition_list=$(BOARD_SUPER_PARTITION_PARTITION_LIST)" >> $(1))
  $(if $(BOARD_SUPER_PARTITION_GROUPS),
    echo "super_partition_groups=$(BOARD_SUPER_PARTITION_GROUPS)" >> $(1))
  $(foreach group,$(BOARD_SUPER_PARTITION_GROUPS), \
    echo "super_$(group)_group_size=$(BOARD_$(call to-upper,$(group))_SIZE)" >> $(1); \
    $(if $(BOARD_$(call to-upper,$(group))_PARTITION_LIST), \
      echo "super_$(group)_partition_list=$(BOARD_$(call to-upper,$(group))_PARTITION_LIST)" >> $(1);))
  $(if $(filter true,$(TARGET_USERIMAGES_SPARSE_EXT_DISABLED)), \
    echo "build_non_sparse_super_partition=true" >> $(1))
  $(if $(filter true,$(BOARD_SUPER_IMAGE_IN_UPDATE_PACKAGE)), \
    echo "super_image_in_update_package=true" >> $(1))
endef

這個函數的作用一目瞭然,就是把makefile中的變量導出到misc_info.txt中。

由此看來,這個misc_info.txt文件,對於打包super.img很重要

BOARD_SUPER_PARTITION_PARTITION_LIST

生成misc_info.txt文件後,build-superimage-target函數開始把BOARD_SUPER_PARTITION_PARTITION_LIST變量也導入到misc_info.txt文件中,繼續完善它。

$(foreach p,$(BOARD_SUPER_PARTITION_PARTITION_LIST), \
    echo "$(p)_image=$(INSTALLED_$(call to-upper,$(p))IMAGE_TARGET)" >> $(2);)

創建super.img所在路徑

徹底搞定misc_info.txt文件後,

build-superimage-target函數開始,創建super.img所在路徑

mkdir -p $(dir $(1))

調用py腳本build_super_image.py

build-superimage-target函數最後一步的代碼如下

  PATH=$(dir $(LPMAKE)):$$PATH \
    $(BUILD_SUPER_IMAGE) -v $(2) $(1)

重定義PATH變量,添加LPMAKE命令的路徑到環境變量PATH中,讓其可以正常執行。(爲後面做準備)

LPMAKE := $(HOST_OUT_EXECUTABLES)/lpmake$(HOST_EXECUTABLE_SUFFIX)

最後一步,萬事具備,調用build_super_image.py生成$(1)(即super.img)

備註:

BUILD_SUPER_IMAGE是在/build/make/core/config.mk中定義的

BUILD_SUPER_IMAGE := build/make/tools/releasetools/build_super_image.py

build_super_image.py

入口

很明顯,腳本的入口是main函數

if __name__ == "__main__":
  try:
    common.CloseInheritedPipes()
    main(sys.argv[1:])
  except common.ExternalError:
    logger.exception("\n   ERROR:\n")
    sys.exit(1)
  finally:
    common.Cleanup()

main函數

先處理命令行傳入的參數,然後打開log,最後是調用負責主體業務邏輯的BuildSuperImage函數

def main(argv):

  args = common.ParseOptions(argv, __doc__)

  if len(args) != 2:
    common.Usage(__doc__)
    sys.exit(1)

  common.InitLogging()

  BuildSuperImage(args[0], args[1])

BuildSuperImage函數

inp爲misc_inf.txt

out爲super.img

def BuildSuperImage(inp, out):

  if isinstance(inp, dict):
    logger.info("Building super image from info dict...")
    return BuildSuperImageFromDict(inp, out)

  if isinstance(inp, str):
    if os.path.isdir(inp):
      logger.info("Building super image from extracted target files...")
      return BuildSuperImageFromExtractedTargetFiles(inp, out)

    if zipfile.is_zipfile(inp):
      logger.info("Building super image from target files...")
      return BuildSuperImageFromTargetFiles(inp, out)

    if os.path.isfile(inp):
      with open(inp) as f:
        lines = f.read()
      logger.info("Building super image from info dict...")
      return BuildSuperImageFromDict(common.LoadDictionaryFromLines(lines.split("\n")), out)

  raise ValueError("{} is not a dictionary or a valid path".format(inp))

isinstance()函數來判斷一個對象是否是一個已知的類型

我們這裏inp明顯是一個file

故,只有最後一個if條件走通了。不至於跑的最後一句raise顯示地引發異常,導致腳本運行失敗。

BuildSuperImageFromDict

BuildSuperImageFromDict函數調用lpmake命令生成super.img

def BuildSuperImageFromDict(info_dict, output):

  cmd = [info_dict["lpmake"],
         "--metadata-size", "65536",
         "--super-name", info_dict["super_metadata_device"]]

  ...//省略

  cmd += ["--output", output]

  common.RunAndCheckOutput(cmd)

  if retrofit and has_image:
    logger.info("Done writing images to directory %s", output)
  else:
    logger.info("Done writing image %s", output)

  return True

相關編譯log

生成 super_empty.img

[ 74% 86513/116625] Target empty super fs image: out/target/product/k62v1_32_bsp/super_empty.img
2020-02-13 02:16:53 - build_super_image.py - INFO    : Building super image from info dict...
2020-02-13 02:16:53 - common.py - INFO    :   Running: "lpmake --metadata-size 65536 --super-name super --metadata-slots 2 --device super:4294967296 --group main:4292870144 --partition product:readonly:0:main --partition system:readonly:0:main --partition vendor:readonly:0:main --sparse --output out/target/product/k62v1_32_bsp/super_empty.img"
2020-02-13 02:16:53 - common.py - INFO    : 
2020-02-13 02:16:53 - build_super_image.py - INFO    : Done writing image out/target/product/k62v1_32_bsp/super_empty.img

通過makeormake superiamge生成 super.img

[100% 116625/116625] Target super fs image for debug: out/target/product/k62v1_32_bsp/super.img
2020-02-13 03:31:23 - build_super_image.py - INFO    : Building super image from info dict...
2020-02-13 03:31:23 - sparse_img.py - INFO    : Total of 61048 4096-byte output blocks in 9 input chunks.
2020-02-13 03:31:23 - sparse_img.py - INFO    : Total of 166135 4096-byte output blocks in 13 input chunks.
2020-02-13 03:31:23 - sparse_img.py - INFO    : Total of 45595 4096-byte output blocks in 9 input chunks.
2020-02-13 03:31:23 - common.py - INFO    :   Running: "lpmake --metadata-size 65536 --super-name super --metadata-slots 2 --device super:4294967296 --group main:4292870144 --partition product:readonly:250052608:main --image product=out/target/product/k62v1_32_bsp/product.img --partition system:readonly:680488960:main --image system=out/target/product/k62v1_32_bsp/system.img --partition vendor:readonly:186757120:main --image vendor=out/target/product/k62v1_32_bsp/vendor.img --sparse --output out/target/product/k62v1_32_bsp/super.img"
2020-02-13 03:31:28 - common.py - INFO    : lpmake I 02-13 03:31:23 25555 25555 builder.cpp:937] [liblp]Partition product will resize from 0 bytes to 250052608 bytes
lpmake I 02-13 03:31:23 25555 25555 builder.cpp:937] [liblp]Partition system will resize from 0 bytes to 680488960 bytes
lpmake I 02-13 03:31:23 25555 25555 builder.cpp:937] [liblp]Partition vendor will resize from 0 bytes to 186757120 bytes
2020-02-13 03:31:28 - build_super_image.py - INFO    : Done writing image out/target/product/k62v1_32_bsp/super.img

misc_info.txt文件

out/target/product/xxxx/obj/PACKING/super_empty_intermediates/misc_info.txt

use_dynamic_partitions=true
lpmake=lpmake
build_super_partition=true
super_metadata_device=super
super_block_devices=super
super_super_device_size=4831838208
dynamic_partition_list= product system vendor
super_partition_groups=main
super_main_group_size=4349001728
super_main_partition_list=product system vendor
super_image_in_update_package=true

out/target/product/xxxx/obj/PACKING/superimage_debug_intermediates/misc_info.txt

use_dynamic_partitions=true
lpmake=lpmake
build_super_partition=true
super_metadata_device=super
super_block_devices=super
super_super_device_size=4831838208
dynamic_partition_list= product system vendor
super_partition_groups=main
super_main_group_size=4349001728
super_main_partition_list=product system vendor
super_image_in_update_package=true
product_image=out/target/product/xxxx/product.img
system_image=out/target/product/xxxx/system.img
vendor_image=out/target/product/xxxx/vendor.img
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章