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-nodeps
和supernod
,類似於systemimage-nodeps
和snod
這一套
這個規則拋棄了很多依賴,邏輯簡單了一些,咱們下面來看看
規則
可以看到之前的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
通過make
ormake 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