属性文件生成过程分析

这是一个介绍 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,其他属性文件我们都可以依葫芦画瓢进行分析了。

相关推荐
程序员JerrySUN24 分钟前
OP-TEE + YOLOv8:从“加密权重”到“内存中解密并推理”的完整实战记录
android·java·开发语言·redis·yolo·架构
TeleostNaCl2 小时前
Android | 启用 TextView 跑马灯效果的方法
android·经验分享·android runtime
TheNextByte12 小时前
Android USB文件传输无法使用?5种解决方法
android
quanyechacsdn3 小时前
Android Studio创建库文件用jitpack构建后使用implementation方式引用
android·ide·kotlin·android studio·implementation·android 库文件·使用jitpack
程序员陆业聪4 小时前
聊聊2026年Android开发会是什么样
android
编程大师哥5 小时前
Android分层
android
极客小云6 小时前
【深入理解 Android 中的 build.gradle 文件】
android·安卓·安全架构·安全性测试
Juskey iii6 小时前
Android Studio Electric Eel | 2022.1.1 Patch 2 版本下载
android·ide·android studio
Android技术之家6 小时前
2025年度Android行业总结:AI驱动生态重构,跨端融合开启新篇
android·人工智能·重构
洞见前行6 小时前
Android第二代加固技术原理详解(附源码)
android