这是一个介绍 Android 属性系统的系列文章:
- Android 属性系统入门
- 属性文件生成过程分析 (本文)
- 如何添加系统属性
- 属性与 Selinux
- 属性系统整体框架与启动过程分析
- 属性读写过程源码分析
上文我们说到,在运行的系统中有很多属性文件:
bash
/default.prop
/data/local.prop
/system/build.prop
/system/product/build.prop
/vendor/build.prop
/vendor/odm/etc/build.prop
/vendor/default.prop
那么这些属性文件是从哪里来的呢?
我们先看一下 /system/build.prop
文件的开头:
bash
# begin common build properties
# autogenerated by build/make/tools/buildinfo_common.sh
ro.system.build.date=Fri Oct 13 17:23:40 CST 2023
# ......
注释里面说,当前文件由 build/make/tools/buildinfo_common.sh
自动生成,我们去看一下这个 shell 脚本的具体内容:
bash
cat build/make/tools/buildinfo_common.sh
#!/bin/bash
partition="$1"
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <partition>" 1>&2
exit 1
fi
echo "# begin common build properties"
echo "# autogenerated by $0"
echo "ro.${partition}.build.date=`$DATE`"
echo "ro.${partition}.build.date.utc=`$DATE +%s`"
echo "ro.${partition}.build.fingerprint=$BUILD_FINGERPRINT"
echo "ro.${partition}.build.id=$BUILD_ID"
echo "ro.${partition}.build.tags=$BUILD_VERSION_TAGS"
echo "ro.${partition}.build.type=$TARGET_BUILD_TYPE"
echo "ro.${partition}.build.version.incremental=$BUILD_NUMBER"
echo "ro.${partition}.build.version.release=$PLATFORM_VERSION"
echo "ro.${partition}.build.version.sdk=$PLATFORM_SDK_VERSION"
echo "ro.product.${partition}.brand=$PRODUCT_BRAND"
echo "ro.product.${partition}.device=$PRODUCT_DEVICE"
echo "ro.product.${partition}.manufacturer=$PRODUCT_MANUFACTURER"
echo "ro.product.${partition}.model=$PRODUCT_MODEL"
echo "ro.product.${partition}.name=$PRODUCT_NAME"
echo "# end common build properties"
上述脚本中,通过 echo 打印了许多信息。这些信息都进入了文件中,那么调用过程中一定做了重定向操作。
我们在 build/make
中搜索 buildinfo_common.sh
,看看哪里使用了这个脚本:
bash
cd build/make
grep -R "buildinfo_common.sh" .
./core/Makefile:BUILDINFO_COMMON_SH := build/make/tools/buildinfo_common.sh
可以看到在 build/make/core/Makefile
文件中,脚本的路径赋值给了 BUILDINFO_COMMON_SH 变量。
我们接着搜这个变量:
bash
# 还是在 build/make 目录下
grep -R "BUILDINFO_COMMON_SH" .
./core/Makefile:BUILDINFO_COMMON_SH := build/make/tools/buildinfo_common.sh
./core/Makefile: bash $(BUILDINFO_COMMON_SH) "$(1)" >> $(2)
./core/Makefile:$(INSTALLED_DEFAULT_PROP_TARGET): $(BUILDINFO_COMMON_SH) $(intermediate_system_build_prop)
./core/Makefile:$(intermediate_system_build_prop): $(BUILDINFO_SH) $(BUILDINFO_COMMON_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(system_prop_file) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(API_FINGERPRINT)
./core/Makefile:$(INSTALLED_VENDOR_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH) $(intermediate_system_build_prop)
./core/Makefile:$(INSTALLED_PRODUCT_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH) $(product_prop_files)
./core/Makefile:$(INSTALLED_ODM_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH)
./core/Makefile:$(INSTALLED_PRODUCT_SERVICES_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH)
注意到第二行的输出 ./core/Makefile: bash $(BUILDINFO_COMMON_SH) "$(1)" >> $(2)
,这里调用了上面的 shell 脚本
打开文件,看到它是函数 generate-common-build-props-with-product-vars-set
的一部分:
Makefile
define generate-common-build-props-with-product-vars-set
BUILD_FINGERPRINT="$(BUILD_FINGERPRINT_FROM_FILE)" \
BUILD_ID="$(BUILD_ID)" \
BUILD_NUMBER="$(BUILD_NUMBER_FROM_FILE)" \
BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \
DATE="$(DATE_FROM_FILE)" \
PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \
PLATFORM_VERSION="$(PLATFORM_VERSION)" \
TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)" \
bash $(BUILDINFO_COMMON_SH) "$(1)" >> $(2)
endef
这里用函数的参数做了从定向,我们接着搜,哪里使用这个函数:
bash
grep -R "generate-common-build-props-with-product-vars-set" .
./core/Makefile: $(call generate-common-build-props-with-product-vars-set,$(1),$(2))
./core/Makefile:define generate-common-build-props-with-product-vars-set
./core/Makefile: $(call generate-common-build-props-with-product-vars-set,system,$@)
有两个地方调用了 generate-common-build-props-with-product-vars-set
函数:
我们主要看第一个地方:
bash
# 定义 system_prop_file 变量的值
# system_prop_file 代表了一个 prop 属性文件
ifdef TARGET_SYSTEM_PROP
system_prop_file := $(TARGET_SYSTEM_PROP)
else
system_prop_file := $(wildcard $(TARGET_DEVICE_DIR)/system.prop)
endif
# 这里是一个 Makefile 规则
# intermediate_system_build_prop 的值类似于 out/target/product/xxx/obj/ETC/system_build_prop_intermediates/build.prop 是一个中间文件,用于生成最终的 /system/build.prop
$(intermediate_system_build_prop): $(BUILDINFO_SH) $(BUILDINFO_COMMON_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(system_prop_file) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(API_FINGERPRINT)
@echo Target buildinfo: $@
@mkdir -p $(dir $@)
$(hide) echo > $@
ifneq ($(PRODUCT_OEM_PROPERTIES),)
$(hide) echo "#" >> $@; \
echo "# PRODUCT_OEM_PROPERTIES" >> $@; \
echo "#" >> $@;
$(hide) $(foreach prop,$(PRODUCT_OEM_PROPERTIES), \
echo "import /oem/oem.prop $(prop)" >> $@;)
endif
$(hide) PRODUCT_BRAND="$(PRODUCT_SYSTEM_BRAND)" \
PRODUCT_MANUFACTURER="$(PRODUCT_SYSTEM_MANUFACTURER)" \
PRODUCT_MODEL="$(PRODUCT_SYSTEM_MODEL)" \
PRODUCT_NAME="$(PRODUCT_SYSTEM_NAME)" \
PRODUCT_DEVICE="$(PRODUCT_SYSTEM_DEVICE)" \
# 在这里调用 generate-common-build-props-with-product-vars-set 生成中间文件
# out/target/product/xxx/obj/ETC/system_build_prop_intermediates/build.prop
$(call generate-common-build-props-with-product-vars-set,system,$@)
$(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_VARIANT)" \
TARGET_BUILD_FLAVOR="$(TARGET_BUILD_FLAVOR)" \
TARGET_DEVICE="$(TARGET_DEVICE)" \
PRODUCT_DEFAULT_LOCALE="$(call get-default-product-locale,$(PRODUCT_LOCALES))" \
PRODUCT_DEFAULT_WIFI_CHANNELS="$(PRODUCT_DEFAULT_WIFI_CHANNELS)" \
PRIVATE_BUILD_DESC="$(PRIVATE_BUILD_DESC)" \
BUILD_ID="$(BUILD_ID)" \
BUILD_DISPLAY_ID="$(BUILD_DISPLAY_ID)" \
DATE="$(DATE_FROM_FILE)" \
BUILD_USERNAME="$(BUILD_USERNAME)" \
BUILD_HOSTNAME="$(BUILD_HOSTNAME)" \
BUILD_NUMBER="$(BUILD_NUMBER_FROM_FILE)" \
BOARD_BUILD_SYSTEM_ROOT_IMAGE="$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)" \
AB_OTA_UPDATER="$(AB_OTA_UPDATER)" \
PLATFORM_VERSION="$(PLATFORM_VERSION)" \
PLATFORM_SECURITY_PATCH="$(PLATFORM_SECURITY_PATCH)" \
PLATFORM_BASE_OS="$(PLATFORM_BASE_OS)" \
PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \
PLATFORM_PREVIEW_SDK_VERSION="$(PLATFORM_PREVIEW_SDK_VERSION)" \
PLATFORM_PREVIEW_SDK_FINGERPRINT="$$(cat $(API_FINGERPRINT))" \
PLATFORM_VERSION_CODENAME="$(PLATFORM_VERSION_CODENAME)" \
PLATFORM_VERSION_ALL_CODENAMES="$(PLATFORM_VERSION_ALL_CODENAMES)" \
PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION="$(PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION)" \
BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \
$(if $(OEM_THUMBPRINT_PROPERTIES),BUILD_THUMBPRINT="$(BUILD_THUMBPRINT_FROM_FILE)") \
TARGET_CPU_ABI_LIST="$(TARGET_CPU_ABI_LIST)" \
TARGET_CPU_ABI_LIST_32_BIT="$(TARGET_CPU_ABI_LIST_32_BIT)" \
TARGET_CPU_ABI_LIST_64_BIT="$(TARGET_CPU_ABI_LIST_64_BIT)" \
TARGET_CPU_ABI="$(TARGET_CPU_ABI)" \
TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \
bash $(BUILDINFO_SH) >> $@
# 把 system_prop_file 中的内容写入中间文件
$(hide) $(foreach file,$(system_prop_file), \
if [ -f "$(file)" ]; then \
echo Target buildinfo from: "$(file)"; \
echo "" >> $@; \
echo "#" >> $@; \
echo "# from $(file)" >> $@; \
echo "#" >> $@; \
cat $(file) >> $@; \
echo "# end of $(file)" >> $@; \
fi;)
# FINAL_BUILD_PROPERTIES 的值来自 ADDITIONAL_BUILD_PROPERTIES
# ADDITIONAL_BUILD_PROPERTIES 主要是由 PRODUCT_PROPERTY_OVERRIDES 这个变量赋值, 而这个变量就是我们开发时经常用于自定义属性的, 一般在产品配置目录下定义
# 这里把 FINAL_BUILD_PROPERTIES 中的属性写入中间文件
$(if $(FINAL_BUILD_PROPERTIES), \
$(hide) echo >> $@; \
echo "#" >> $@; \
echo "# ADDITIONAL_BUILD_PROPERTIES" >> $@; \
echo "#" >> $@; )
$(hide) $(foreach line,$(FINAL_BUILD_PROPERTIES), \
echo "$(line)" >> $@;)
$(hide) build/make/tools/post_process_props.py $@ $(PRODUCT_SYSTEM_PROPERTY_BLACKLIST)
build_desc :=
ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY)))
INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img
else
INSTALLED_RECOVERYIMAGE_TARGET :=
endif
# INSTALLED_BUILD_PROP_TARGET 的值为 out/target/product/xxx/system/build.prop
# 也就是我们最终要生成的文件
$(INSTALLED_BUILD_PROP_TARGET): $(intermediate_system_build_prop) $(INSTALLED_RECOVERYIMAGE_TARGET)
@echo "Target build info: $@"
# 这里把中间文件写入到最终文件中,同时剔除 ro.product.first_api_level 相关的行
$(hide) grep -v 'ro.product.first_api_level' $(intermediate_system_build_prop) > $@
以上代码总结一下:
- 准备好一个中间文件
out/target/product/xxx/obj/ETC/system_build_prop_intermediates/build.prop
- 调用
buildinfo_common.sh
,向中间文件写入数据 - 把 system_prop_file 中的内容写入中间文件
- 这里把用户自定义的的属性(PRODUCT_PROPERTY_OVERRIDES)写入中间文件
- 这里把中间文件写入到最终文件(out/target/product/xxx/system/build.pro)中,同时剔除 ro.product.first_api_level 相关的行
以上就是 /system/build.prop
,其他属性文件我们都可以依葫芦画瓢进行分析了。