AOSP是如何构造userdata.img
在AOSP中,userdata.img的制作命令如下,可以知道make的target是userdataimage
。
make userdataimage -j4
第一步: 执行AOSP根目录的Makefile
内容如下:
include build/make/core/main.mk
跳转到main.mk
进行处理。
第二步: build/make/core/目录下的main.mk
这个文件是各种编译的核心文件,用于处理不同的make target,根据userdataimage
的target,可以在该文件找到相关信息:
.PHONY: userdataimage
userdataimage: $(INSTALLED_USERDATAIMAGE_TARGET)
跳转到$(INSTALLED_USERDATAIMAGE_TARGET)
中。
第三步: build/make/core/目录下的Makefile
上面提到的PHONY目标$(INSTALLED_USERDATAIMAGE_TARGET)
记录build/make/core/Makefile
,如下:
INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET)
对于$(BUILT_USERDATAIMAGE_TARGET)
需要满足一定的依赖关系才能执行继续执行,如下:
$(INSTALLED_USERDATAIMAGE_TARGET): $(INSTALLED_USERDATAIMAGE_TARGET_DEPS)
依赖$(INSTALLED_USERDATAIMAGE_TARGET_DEPS)
,有如下定义:
INSTALLED_USERDATAIMAGE_TARGET_DEPS := \
$(INTERNAL_USERIMAGES_DEPS) \
$(INTERNAL_USERDATAIMAGE_FILES) \
$(BUILD_IMAGE_SRCS)
核心是第一个依赖:INTERNAL_USERIMAGES_DEPS
这是一个工具依赖,用于将制作userdata.img的工具连接在一起行程工具链,用于以后循环使用:
ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
INTERNAL_USERIMAGES_DEPS := $(SIMG2IMG)
INTERNAL_USERIMAGES_DEPS += $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(E2FSCK)
ifeq ($(TARGET_USERIMAGES_USE_F2FS),true)
INTERNAL_USERIMAGES_DEPS += $(MKF2FSUSERIMG) $(MAKE_F2FS)
endif
endif
ifeq ($(BOARD_AVB_ENABLE),true)
INTERNAL_USERIMAGES_DEPS += $(AVBTOOL)
endif
ifneq (true,$(TARGET_USERIMAGES_SPARSE_SQUASHFS_DISABLED))
INTERNAL_USERIMAGES_SPARSE_SQUASHFS_FLAG := -s
endif
ifneq ($(filter $(BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE) $(BOARD_PRODUCT_SERVICESIMAGE_FILE_SYSTEM_TYPE) $(BOARD_ODMIMAGE_FILE_SYSTEM_TYPE) $(BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE) $(BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE),squashfs),)
INTERNAL_USERIMAGES_DEPS += $(MAKE_SQUASHFS) $(MKSQUASHFSUSERIMG) $(IMG2SIMG)
endif
INTERNAL_USERIMAGES_BINARY_PATHS := $(sort $(dir $(INTERNAL_USERIMAGES_DEPS)))
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY))
INTERNAL_USERIMAGES_DEPS += $(BUILD_VERITY_METADATA) $(BUILD_VERITY_TREE) $(APPEND2SIMG) $(VERITY_SIGNER)
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY_FEC))
INTERNAL_USERIMAGES_DEPS += $(FEC)
endif
endif
SELINUX_FC := $(call intermediates-dir-for,ETC,file_contexts.bin)/file_contexts.bin
INTERNAL_USERIMAGES_DEPS += $(SELINUX_FC)
INTERNAL_USERIMAGES_DEPS += $(BLK_ALLOC_TO_BASE_FS)
ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
INTERNAL_USERIMAGES_DEPS += $(MKE2FS_CONF)
endif
工具的对应的变量,即工具所在的路径,如$(SIMG2IMG)
和$(MKEXTUSERIMG)
等,可以在build/make/core/config.mk
找到,如下:
SIMG2IMG := $(HOST_OUT_EXECUTABLES)/simg2img$(HOST_EXECUTABLE_SUFFIX)
IMG2SIMG := $(HOST_OUT_EXECUTABLES)/img2simg$(HOST_EXECUTABLE_SUFFIX)
满足了上述依赖以后,回到目标INSTALLED_USERDATAIMAGE_TARGET
,有:
INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET)
BUILT_USERDATAIMAGE_TARGET := $(PRODUCT_OUT)/userdata.img
这里$(PRODUCT_OUT)
表示AOSP编译完成后的输出目录,$(PRODUCT_OUT)/userdata.img
即我们需要的文件。
确定了制作目标文件$(PRODUCT_OUT)/userdata.img
以后,就要开始进行制作,具体是通过$(build-userdataimage-target)
函数进行制作:
define build-userdataimage-target
$(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")
@mkdir -p $(TARGET_OUT_DATA)
@mkdir -p $(userdataimage_intermediates) && rm -rf $(userdataimage_intermediates)/userdata_image_info.txt
$(call generate-image-prop-dictionary, $(userdataimage_intermediates)/userdata_image_info.txt,userdata,skip_fsck=true)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt $(INSTALLED_USERDATAIMAGE_TARGET) $(TARGET_OUT)
$(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATAIMAGE_PARTITION_SIZE))
endef
第一行打印debug的信息,打印出打包后userdata.img
文件的保存位置:
$(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")
INSTALLED_USERDATAIMAGE_TARGET
的值默认情况一般是:
INSTALLED_USERDATAIMAGE_TARGET=BUILT_USERDATAIMAGE_TARGET=out/target/product/hikey960/userdata.img
第二、三行用于创建文件夹,以及删除上次使用的配置文件 userdata_image_info.txt:
@mkdir -p $(TARGET_OUT_DATA)
@mkdir -p $(userdataimage_intermediates) && rm -rf $(userdataimage_intermediates)/userdata_image_info.txt
第四行用于重新生成配置文件userdata_image_info.txt
:
$(call generate-image-prop-dictionary, $(userdataimage_intermediates)/userdata_image_info.txt,userdata,skip_fsck=true)
其中函数generate-image-prop-dictionary
的关键部分如下,echo 了一些信息到userdata_image_info.txt
:
define generate-image-prop-dictionary
...
$(if $(filter $(2),userdata),\
$(if $(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE),$(hide) echo "userdata_fs_type=$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)" >> $(1))
$(if $(BOARD_USERDATAIMAGE_PARTITION_SIZE),$(hide) echo "userdata_size=$(BOARD_USERDATAIMAGE_PARTITION_SIZE)" >> $(1))
)
...
endef
其中$(BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE)
和$(BOARD_USERDATAIMAGE_PARTITION_SIZE)
等值在编译的时候,或者BoardConfig.mk
中指定了。
第五行先配置一下打包image所使用到的工具的环境变量,然后调用一个python脚本build_image.py
去打包:
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt $(INSTALLED_USERDATAIMAGE_TARGET) $(TARGET_OUT)
用于配置环境变量的$(INTERNAL_USERIMAGES_BINARY_PATHS)
是由上面提及的工具链变量$(INTERNAL_USERIMAGES_DEPS)
转换而来的变量,定义如下:
INTERNAL_USERIMAGES_BINARY_PATHS := $(sort $(dir $(INTERNAL_USERIMAGES_DEPS)))
然后通过foreach循环,加入到PATH中:
PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH
然后执行python脚本build_image.py
去制作image:
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt $(INSTALLED_USERDATAIMAGE_TARGET) $(TARGET_OUT)
上述提及到变量一般在Hikey设备中的具体路径就是:
$(TARGET_OUT_DATA)=out/target/product/hikey960/data
$(userdataimage_intermediates)/userdata_image_info.txt=out/target/product/hikey960/obj/PACKAGING/userdata_intermediates/userdata_image_info.txt
$(INSTALLED_USERDATAIMAGE_TARGET)=out/target/product/hikey960/userdata.img
$(TARGET_OUT)=out/target/product/hikey960/system
python脚本的核心是调用shell脚本mkf2fsuserimg.sh
,这是用于制作f2fs类型的userdata.img,如果是ext4则是ext_mkuserimg
,调用的形式如下:
mkf2fsuserimg.sh \
out/target/product/hikey960/userdata.img \
25845301248 \
-f out/target/product/hikey960/data \
-D out/target/product/hikey960/system \
-s out/target/product/hikey960/obj/ETC/file_contexts.bin_intermediates/file_contexts.bin \
-t data -L data
脚本mkf2fsuserimg.sh
一般在out/host/linux-x86-bin
可以找到它的定义:
#!/bin/bash
...
MAKE_F2FS_CMD="make_f2fs -S $SIZE -f -O encrypt -O quota -O verity $MKFS_OPTS $OUTPUT_FILE"
echo $MAKE_F2FS_CMD
$MAKE_F2FS_CMD
if [ $? -ne 0 ]; then
exit 4
fi
SLOAD_F2FS_CMD="sload_f2fs -S $SLOAD_OPTS $OUTPUT_FILE"
echo $SLOAD_F2FS_CMD
$SLOAD_F2FS_CMD
if [ $? -ne 0 ]; then
rm -f $OUTPUT_FILE
exit 4
fi
可以看到分别使用了make_f2fs
对userdata.img进行格式化,然后使用sload_f2fs
将预置app或者文件保存到userdata.img中。