安卓构建自定义镜像

文章详细介绍了如何基于AOSP构建手机厂商自定义镜像的步骤,包括定义makefile、设置镜像参数、定义模块和拷贝文件,以及构建流程。构建过程涉及Android.mk、全局变量和build_image.py脚本,最终通过avbtool进行签名。
摘要由CSDN通过智能技术生成

安卓构建自定义镜像

背景

谷歌提供的aosp都是一些标准的架构,不会完全符合手机厂商的需求。那么手机厂商基于自己的业务需求,自定义镜像就成了不错的拓展方法。

自定义镜像步骤

 1、步骤总结
  1. 定义描述镜像的makefile
  2. 将所有镜像的makefile名字,添加到全局变量PRODUCT_CUSTOM_IMAGE_MAKEFILES
  3. 定义需要安装到image的module
  4. 将需要安装的module,添加到全局变量CUSTOM_IMAGE_MODULES
  5. 将需要拷贝到Image的文件,添加到全局变量CUSTOM_IMAGE_COPY_FILES
 2、步骤详解
  1. 定义描述镜像的makefile
  		1. 定义makefile文件名
  		假设我们定义一个xuanfeng.mk。那么生成的镜像名就是xuanfeng.img
  		2. 定义makefile内容
  		 - CUSTOM_IMAGE_MOUNT_POINT:=/odm
  		 挂载点, 比如 "oem", "odm" 等
  		 - CUSTOM_IMAGE_PARTITION_SIZE:=1024
  		 分区大小
  		 - CUSTOM_IMAGE_FILE_SYSTEM_TYPE:=ext2
  		 文件系统类型,ext或者erofs格式
  		 - CUSTOM_IMAGE_DICT_FILE:=dict_file
  		 字典文件,build_image.py中BuildImage()用到的一个文本,这里定义了一个字典
  		 - CUSTOM_IMAGE_MODULES:=xuanfengtest
  		 镜像模块列表,把需要安装到镜像的模块,添加到这个列表,可使用CUSTOM_IMAGE_MODULES +=实现
  		 - CUSTOM_IMAGE_COPY_FILES += <src>:<dest>
  		 拷贝文件列表,被定义的拷贝文件将从<src>路径拷贝到镜像的<dest>路径。<dest>路径相对于镜像的根目录
  		 <dest>如果不填,直接放到根目录
  		 - CUSTOM_IMAGE_SELINUX := true
  		 设置镜像是否支持selinux
  		 - CUSTOM_IMAGE_SUPPORT_VERITY := true
  		  设置镜像是否支持avb.
  		 - CUSTOM_IMAGE_SUPPORT_VERITY_FEC := true
  		 设置镜像是否支持FEC (forward error correction)
  		 - CUSTOM_IMAGE_VERITY_BLOCK_DEVICE := /dev/block/…./by-name/odm
  		  提前装载分区,需要配置这个变量
  		 - CUSTOM_IMAGE_AVB_HASH_ENABLE:=true
  		   设置镜像AVB签名时,添加hash footer
  		 - CUSTOM_IMAGE_AVB_ADD_HASH_FOOTER_ARGS:=xxx
  		   设置镜像添加hash footer时的附加参数
  		 - CUSTOM_IMAGE_AVB_HASHTREE_ENABLE:=true
  		   设置镜像avb签名时,添加hashtree footer
  		 - CUSTOM_IMAGE_AVB_ADD_HASHTREE_FOOTER_ARGS:=xxx
  		    设置镜像添加hashtree footer时的附加参数
  		 - CUSTOM_IMAGE_AVB_KEY_PATH:=external/avb/test/data/testkey_rsa2048.pem
  		    设置镜像AVB签名时的私钥
  		 - CUSTOM_IMAGE_AVB_ALGORITHM:=SHA256_RSA2048
  		    设置镜像AVB签名时的算法
  2. 将所有镜像的makefile名字,赋值给全局变量PRODUCT_CUSTOM_IMAGE_MAKEFILES
  		Build System在构建自定义镜像的时候,首先从build_custom_images.mk开始。通过PRODUCT_CUSTOM_IMAGE_MAKEFILES的遍历开始构建
  3. 定义需要安装到image的module
  		1、定义编译使用的Android.mk
  		2、编写module用到的源码文件,比如.c
  		3、Android.mk语法参考
  		https://blog.csdn.net/xuanfengwuxiang/article/details/129306679?spm=1001.2014.3001.5501
  4. 将需要安装的module名字,添加到全局变量CUSTOM_IMAGE_MODULES
  		构建流程走到build_custom_image.mk里的时候,会收集CUSTOM_IMAGE_MODULES里的模块
  		添加module示例:CUSTOM_IMAGE_MODULES += xuanfeng
  5. 将需要直接拷贝到Image的文件,添加到全局变量CUSTOM_IMAGE_COPY_FILES
  		构建流程走到build_custom_image.mk里的时候,会收集CUSTOM_IMAGE_COPY_FILES里的文件
  		添加拷贝文件示例:CUSTOM_IMAGE_COPY_FILES += <src>:<dest>

Build System构建自定义镜像的流程

 1、构建流程概览
		1. build_custom_images.mk遍历所有的自定义镜像的makefile,调用build_custom_image.mk构建
		2. build_custom_image.mk收集自定义镜像各种参数,调用build_image.py构建
		3. build_image.py解析入参,调用BuildImage()构建
		4. BuildImage()构建出纯净镜像,调用avbtool进行签名
		5. avbtool签名流程
 2、构建流程详情
		1. build_custom_images.mk遍历所有的自定义镜像的makefile,调用build_custom_image.mk构建
		关键代码如下:
		# PRODUCT_CUSTOM_IMAGE_MAKEFILES是个列表,代表所有的自定义镜像makefile
		$(foreach mk, $(PRODUCT_CUSTOM_IMAGE_MAKEFILES),\
  			$(eval my_custom_imag_makefile := $(mk))\
  			$(eval include $(BUILD_SYSTEM)/tasks/tools/build_custom_image.mk))
		2. build_custom_image.mk收集自定义镜像各种参数,调用build_image.py构建
				1、根据自定义镜像makefile,解析镜像名称、镜像生成的中间目录、挂载点路径
		intermediates := $(call intermediates-dir-for,PACKAGING,$(my_custom_image_name))
		my_built_custom_image := $(intermediates)/$(my_custom_image_name).img
		# 打包image之前,build system构建出的image内部的内容都放在这个临时文件夹
		my_staging_dir := $(intermediates)/$(CUSTOM_IMAGE_MOUNT_POINT)
				2、收集CUSTOM_IMAGE_MODULES变量定义安装的模块和PICKUP_FILES
		$(foreach m,$(CUSTOM_IMAGE_MODULES),\
		  ...........
		  # 收集pickup files
		  $(eval my_pickup_files += $(_pickup_files))\
		  $(foreach i, $(_built_files),\
		    .............
		    $(if $(filter $(TARGET_OUT_ROOT)/%,$(ins)),\
		      $(eval bui := $(word 1,$(bui_ins)))\
		      # 收集构建的modules
		      $(eval my_built_modules += $(bui))\
		      ...........
		      # 模块中有些也是copy类型
		      $(eval my_copy_pairs += $(bui):$(my_staging_dir)/$(my_copy_dest)))\
		  ))
				3、收集CUSTOM_IMAGE_COPY_FILES变量定义的拷贝文件
			my_image_copy_files :=
			$(foreach f,$(CUSTOM_IMAGE_COPY_FILES),\
			  $(eval pair := $(subst :,$(space),$(f)))\
			  $(eval src := $(word 1,$(pair)))\
			  $(eval my_image_copy_files += $(src))\
			  # copy类型文件收集
			  $(eval my_copy_pairs += $(src):$(my_staging_dir)/$(word 2,$(pair))))
				4、拷贝所有文件。也就是my_copy_pairs、my_pickup_files变量收集到的文件	
			$(my_built_custom_image): PRIVATE_COPY_PAIRS := $(my_copy_pairs)
			$(my_built_custom_image): PRIVATE_PICKUP_FILES := $(my_pickup_files)
			.........
			# 拷贝所有文件
			$(hide) $(foreach p,$(PRIVATE_COPY_PAIRS),\
			          $(eval pair := $(subst :,$(space),$(p)))\
			          mkdir -p $(dir $(word 2,$(pair)));\
			          cp -Rf $(word 1,$(pair)) $(word 2,$(pair));)
			$(if $($(PRIVATE_PICKUP_FILES)),$(hide) cp -Rf $(PRIVATE_PICKUP_FILES) $(PRIVATE_STAGING_DIR))
				5、将描述镜像的信息存到image_info.txt。后面build_image.py构建会用
			# Generate the dict.
			$(hide) echo "# For all accepted properties, see BuildImage() in tools/releasetools/build_image.py" > $(PRIVATE_INTERMEDIATES)/image_info.txt
			$(hide) echo "mount_point=$(PRIVATE_MOUNT_POINT)" >> $(PRIVATE_INTERMEDIATES)/image_info.txt
			........
			  $(hide) echo "# Properties from $(PRIVATE_DICT_FILE)" >> $(PRIVATE_INTERMEDIATES)/image_info.txt;\
			    cat $(PRIVATE_DICT_FILE) >> $(PRIVATE_INTERMEDIATES)/image_info.txt)
				6、调用build_image.py来构建镜像,并传入3个参数
			# Generate the image.
				$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
				  ./build/tools/releasetools/build_image.py \
				  $(PRIVATE_STAGING_DIR) $(PRIVATE_INTERMEDIATES)/image_info.txt $@
	   3. build_image.py解析入参,调用BuildImage()构建
			# 构建image的输入源。代表着build system构建出的module存放的临时文件夹
			in_dir = argv[0]
  			glob_dict_file = argv[1]
  			# 自定义的image
  			out_file = argv[2]
  			# 将image_info.txt转换成字典
  			glob_dict = LoadGlobalDict(glob_dict_file)
  			..............
			 # 调用BuildImage()
			 BuildImage(in_dir, image_properties, out_file, target_out)
	 4. BuildImage()构建出纯净镜像,调用avbtool进行签名
				1. 创建builder,带AVB签名功能
				verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict)
				2. 计算partition size
				# 如果定义了use_dynamic_partition_size=true就动态就算partition
				if (prop_dict.get("use_dynamic_partition_size") == "true" and "partition_size" not in prop_dict):
				    # erofs格式,先构建image,unsparse后再获取压缩后的erofs格式大小
				    if fs_type.startswith("erofs"):
				      mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
				      # 使用了sparse格式,需转回到erofs格式,再du获取大小
				      if "erofs_sparse_flag" in prop_dict and not disable_sparse:
				        image_path = UnsparseImage(out_file, replace=False)
				        size = GetDiskUsage(image_path)
				        os.remove(image_path)
				      else:
				        size = GetDiskUsage(out_file)  # 没有使用sparse格式,直接du获取大小
				    else:
				      size = GetDiskUsage(in_dir)   # 其他非压缩格式,使用du命令获取输入目录(需打包目录)的大小
				    ........				    
				    # ext格式,构建image后,unsparse后得到ext,根据文件系统信息重新调整size
				    if fs_type.startswith("ext"):
				      prop_dict["partition_size"] = str(size)
				      prop_dict["image_size"] = str(size)
				      ..........
				      BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
				      ..........
				      # 构建image后,根据image的文件系统信息(比如inode),预留一些空间,重新调整size
				      ..........
				      prop_dict["partition_size"] = str(size)
				      ............
				    # f2fs格式处理方式和ext类似
				    elif fs_type.startswith("f2fs") and prop_dict.get("f2fs_compress") == "true":
				      prop_dict["partition_size"] = str(size)
				      prop_dict["image_size"] = str(size)
				      BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
				      ............
				      prop_dict["partition_size"] = str(size)
				    # 为AVB继续调整size
				    if verity_image_builder:
				      size = verity_image_builder.CalculateDynamicPartitionSize(size)
				    prop_dict["partition_size"] = str(size)
  				prop_dict["image_size"] = prop_dict["partition_size"]	
				3. 计算image大小
				# 将分区大小赋值给image
				prop_dict["image_size"] = prop_dict["partition_size"]
				# 调整image大小,给avb的hash留空间.
				if verity_image_builder:
					max_image_size = verity_image_builder.CalculateMaxImageSize()
					prop_dict["image_size"] = str(max_image_size)
				# 非erofs格式,根据最新的参数在此构建image
				if not mkfs_output:
					 mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
				# 计算image大小,以适应挂载到分区以block形式存放的大小
  				prop_dict["image_size"] = common.sparse_img.GetImagePartitionSize(out_file)
  				...........
				4. 调用avb签名流程
				# AVB签名流程
				if verity_image_builder:
				    verity_image_builder.Build(out_file)
	  5. avbtool签名流程

    avb签名流程

参考资料

链接: build_custom_images.mk
链接: build_custom_image.mk
链接: build_image.py
链接: Android 系统架构及HAL层概述Android 系统架构及HAL层概述
链接: Gitiles某个提交
链接: Android.mk的GNU make语法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值