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, , }
# $(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
参数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
很重要
生成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))
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()
先处理命令行传入的参数,然后打开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])
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
函数调用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
生成 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
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