参考转载:
https://blog.csdn.net/xujiaofu6181/article/details/86598988
https://blog.csdn.net/Thanksgining/article/details/83374493
分析 system 生成过程
source build/envsetup.sh
lunch full-eng
make -j24
make其实就是执行Makefile文件,在没有指定Makefile的情况下,执行当前路径下的Makefile文件。Android系统执行make命令就是source code跟目录下Makefile文件,而此Makefile文件的内容只有一句,include另外一个main.mk文件, 现在android P 上,main.mk 内容比较多,其实流程是一样的
### DO NOT EDIT THIS FILE ###
include build/make/core/main.mk
### DO NOT EDIT THIS FILE ###
根据Makefile书写规则,在main.mk开始不久,就出现了一个droid伪目标,也是默认目标(default target)。这个默认目标是一个伪目标,make工具遇到伪目标以后,会检查解析伪目标的依赖,如果伪目标存在依赖,就会检查这些依赖,如果这些依赖是伪目标,继续检查这个伪目标的依赖,如果不是伪目标,就会生成这个目标。
最终目标droid默认目标droid依赖于droid_targets,根据build/make/core/main.mk文件可知完整编译Android系统时,droid_targets的依赖于droidcode和dist_files两大伪目标
BUILD_SYSTEM := $(TOPDIR)build/make/core
# This is the default target. It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets
.PHONY: droid_targets
droid_targets:
# Set up various standard variables based on configuration
# and host information.
include $(BUILD_SYSTEM)/config.mk
droid_targets依赖
根据上面代码可知默认目标droid依赖于droid_targets,根据build/make/core/main.mk文件可知完整编译Android系统时,droid_targets的依赖于droidcode和dist_files两大伪目标.
注意: mk 文件中定义 .PHONY 目标才可以进行,build , 在MK 可以调用shell 脚本
ifneq ($(TARGET_BUILD_APPS),)
......
.PHONY: apps_only
apps_only: $(unbundled_build_modules)
droid_targets: apps_only
......
else # TARGET_BUILD_APPS
......
# Building a full system-- the default is to build droidcore
droid_targets: droidcore dist_files
......
endif # TARGET_BUILD_APPS
droidcode目标依赖files、systemimage、INSTALLED_BOOTIMAGE_TARGET等目标,dist_files没有看到依赖情况;
# $(INSTALLED_BOOTIMAGE_TARGET)取INSTALLED_BOOTIMAGE_TARGET的环境变量值
# Build files and then package it into the rom formats
.PHONY: droidcore
droidcore: files
systemimage
$(INSTALLED_BOOTIMAGE_TARGET)
$(MTK_BOOTIMAGE_TARGET)
$(INSTALLED_RECOVERYIMAGE_TARGET)
$(INSTALLED_VBMETAIMAGE_TARGET)
$(INSTALLED_USERDATAIMAGE_TARGET)
$(INSTALLED_CACHEIMAGE_TARGET)
$(INSTALLED_TRANFSIMAGE_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
# dist_files only for putting your library into the dist directory with a full build.
.PHONY: dist_files
files目标依赖modules_to_install和INSTALLED_ANDROID_INFO_TXT_TARGET目标;
# All the droid stuff, in directories
.PHONY: files
files: $(modules_to_install)
$(INSTALLED_ANDROID_INFO_TXT_TARGET)
INSTALLED_SYSTEMIMAGE依赖
build/make/core/main.mk文件包含如下.mk和Makefile文件
systemimage目标依赖在build/make/core/Makefile中说明,可知systemimage目标依赖INSTALLED_SYSTEMIMAGE目标;INSTALLED_SYSTEMIMAGE赋值为(PRODUCT_OUT)/system.img目标依赖:
-BUILT_SYSTEMIMAGE
-RECOVERY_FROM_BOOT_PATCH
NSTALLED_SYSTEMIMAGE := $(PRODUCT_OUT)/system.img
SYSTEMIMAGE_SOURCE_DIR := $(TARGET_OUT)
......
# Rules that need to be present for the all targets, even
# if they don't do anything.
.PHONY: systemimage
systemimage:
# build/make/core/config.mk定义了hide := @,即$(hide)表示在命令前加“@”
# 在命令前加@表示不回显命令
# call 一个可以用来创建新的参数化的函数
**$(INSTALLED_SYSTEMIMAGE): $(BUILT_SYSTEMIMAGE) $(RECOVERY_FROM_BOOT_PATCH)**
@echo "Install system fs image: $@"
$(copy-file-to-target)
$(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
systemimage: $(INSTALLED_SYSTEMIMAGE)
#QEMU表示软件化模拟器
ifeq ($(BUILD_QEMU_IMAGES),true)
......
systemimage: $(INSTALLED_QEMU_SYSTEMIMAGE)
......
endif
BUILT_SYSTEMIMAGE赋值为$(systemimage_intermediates)/system.img,其依赖:
FULL_SYSTEMIMAGE_DEPS
INSTALLED_FILES_FILE
BUILD_IMAGE_SRCS
systemimage_intermediates :=
$(call intermediates-dir-for,PACKAGING,systemimage)
BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img
......
$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(BUILD_IMAGE_SRCS)
$(call build-systemimage-target,$@)
目标INSTALLED_SYSTEMIMAGE执行两个动作,分别是:
copy-file-to-target,此命令在build/make/core/definitions.mk文件定义了,可知此命令就是将第一个依赖项拷贝到目标处,即$(PRODUCT_OUT)/system.img是由拷贝$(systemimage_intermediates)/system.img过来的。
# $@ --> 表示目标
# $ 表示第一个依赖项
# mkdir -p --> 可创建多级文件目录 如:mkdir -p a/b/c
define copy-file-to-target
@mkdir -p $(dir $@)
$(hide) rm -f $@
$(hide) cp "$
assert-max-image-size,此命令在build/make/core/definitions.mk文件定义了
# build/make/core/combo/HOST_linux-x86.mk中定义了get_file-size
# $(1): The file to check
define get-file-size
stat --format "%s" "$(1)" | tr -d 'n'
endef
# build/make/core/definitions.mk
# $(1): The file(s) to check (often $@)
# $(2): The partition size.
define assert-max-image-size
$(if $(2),
size=$$(for i in $(1); do $(call get-file-size,$$i); echo +; done; echo 0);
total=$$(( $$( echo "$$size" ) ));
printname=$$(echo -n "$(1)" | tr " " +);
maxsize=$$(($(2)));
if [ "$$total" -gt "$$maxsize" ]; then
echo "error: $$printname too large ($$total > $$maxsize)";
false;
elif [ "$$total" -gt $$((maxsize - 32768)) ]; then
echo "WARNING: $$printname approaching size limit ($$total now; limit $$maxsize)";
fi
,
true
)
endef
在分析assert-max-image-size之前,先看看RECOVERY_FROM_BOOT_PATCH和BOARD_SYSTEMIMAGE_PARTITION_SIZE
,RECOVERY_FROM_BOOT_PATCH描述的是一个patch文件,这个patch文件的名称为recovery_from_boot.p,保存在设备上system分区中,描述recovery.img与boot.img之间的差异。也就是说,在设备上,可以通过boot.img和recovery_from_boot.p文件生成一个recovery.img文件,使得设备可以进入recovery模式。好比OTA通过recovery_from_boot.p方式升级recovery.img(OTA卡包里面必须要有boot.img、recovery-from-boot.p、install-recovery.sh三个文件缺一不可),在OTA升级完之后,系统重启时会去升级recovery.img(通过boot.img与recovery-from-boot.p生成的)。
RECOVERY_FROM_BOOT_PATCH依赖规则如下:
# The system partition needs room for the recovery image as well. We
# now store the recovery image as a binary patch using the boot image
# as the source (since they are very similar). Generate the patch so
# we can see how big it's going to be, and include that in the system
# image size check calculation.
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
ifneq ($(BOARD_USES_FULL_RECOVERY_IMAGE),true)
ifneq (,$(filter true, $(BOARD_BUILD_SYSTEM_ROOT_IMAGE) $(BOARD_INCLUDE_RECOVERY_DTBO)))
diff_tool := $(HOST_OUT_EXECUTABLES)/bsdiff
else
diff_tool := $(HOST_OUT_EXECUTABLES)/imgdiff
endif
intermediates := $(call intermediates-dir-for,PACKAGING,recovery_patch)
RECOVERY_FROM_BOOT_PATCH := $(intermediates)/recovery_from_boot.p
$(RECOVERY_FROM_BOOT_PATCH): PRIVATE_DIFF_TOOL := $(diff_tool)
$(RECOVERY_FROM_BOOT_PATCH):
$(INSTALLED_RECOVERYIMAGE_TARGET)
$(INSTALLED_BOOTIMAGE_TARGET)
$(diff_tool)
@echo "Construct recovery from boot"
mkdir -p $(dir $@)
$(PRIVATE_DIFF_TOOL) $(INSTALLED_BOOTIMAGE_TARGET) $(INSTALLED_RECOVERYIMAGE_TARGET) $@
else # $(BOARD_USES_FULL_RECOVERY_IMAGE) == true
RECOVERY_FROM_BOOT_PATCH := $(INSTALLED_RECOVERYIMAGE_TARGET)
endif
endif
BOARD_SYSTEMIMAGE_PARTITION_SIZE是system分区大小,在对应产品的Makefile文件中定义了
BOARD_SYSTEMIMAGE_PARTITION_SIZE:=838860800
如下操作是将“1,“分区size”作为一组参数$2,传入assert-max-image-size中,再根据assert-max-image-size的定义,我们可知以下操作就是在比较镜像文件总和是否大于分区大小,如果大于允许的最大分区的大小,这里就会报错。因此,assert-max-image-size函数可以理解为检查system.img size的合法性。
$(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PATCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
通过编译log也可以看到如下信息:
[100% 81510/81510] Install system fs image: out/target/product/${project}/system.img
out/target/product/${project}/system.img+out/target/product/${project}/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=2415114240 blocksize=4224 total=1860325777 reserve=24397824
至此,$(PRODUCT_OUT)/system.img就生成了