减小差分包文档分析

本文解析了Android编译流程中优化差分包大小的策略,包括编译文件排序、内嵌时间戳处理及镜像生成时的特殊处理。通过对编译初始化过程、时间戳控制和镜像生成细节的改进,有效减少了OTA升级包的大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述
对于谷歌文档关于减小差分包大小,在Android代码中进行了确认,大致分为以下三部分,说明修改思路和
具体修改内容,并给出相应总结。 源:https://source.android.com/devices/tech/ota/reduce_size
一、编译初始化过程中处理文件排序
二、编译生成文件(jar,zip,lib.so,apk)的内嵌时间戳处理
三、其他生成镜像时处理(两个被弃用的方法,简单说明)

一、编译初始化文件排序
1、简单说明编译初始化过程
make -j8
执行make命令会执行code/mode/Makefile文件
include build/core/main.mk
main.mk文件里定义了整个Android的编译关系,它主要引入了下列几个重要的mk文件:
include $(BUILD_SYSTEM)/config.mk
根据board配置信息和host配置参数定义编译时用到的变量
include $(BUILD_SYSTEM)/cleanbuild.mk 定义删除编译结果的函数和目标
include $(BUILD_SYSTEM)/definitions.mk 定义了编译过程中通用的变量和宏(我们主要跟踪对象)
执行make/core/Makefile,编译镜像文件

2、definitions.mk文件说明

该文件里定义了Android.mk里的通用的字段,我们编译androi.mk编译APK或者lib,有一些方法提取 成通用放在了definitions.mk文件里边,例如

获取包含Android.mk的目录路径LOCAL_PATH := $(call my-dir)  

获取编译目录下的全部makefile文件include $(call all-makefiles-under,$(LOCAL_PATH))

编译target需要使用到的source源文件,.cpp;.c文件 LOCAL_SRC_FILES := $(call all-subdir-cpp-files) $(call all-subdir-c-files)

3、举例说明修正文件排序问题
以call all-subdir-c-files和call all-subdir-java-files为例,获取当前目录下的全部.cpp文件和.java文件
最好在definition.mk文件里都走了同一个宏控,因为其实相同的find shell命令,传入不同的后缀即可
其中patsubst属于makefile文件中放通配符,通配符一共有三种
1、wildcard : 扩展通配符
2、notdir : 去除路径
3、patsubst :替换通配符
define find-files-in-subdirs
$(patsubst ./%,%, $(shell cd $(1) ; find -L $(3) -name $(2) -and -not -name ".*") \)
endef
find命令是没有顺序的,那么我们可以加入sort方法,让输出变成有序,变更代码如下
define find-files-in-subdirs
$(sort $(patsubst ./%,%, $(shell cd $(1) ; find -L $(3) -name $(2) -and -not -name ".*") ))
endef
我们把这句话在Android.mk中加入做一个小测试如下,就可以发现文件展开结果的差别,有sort的文件将有序:

4、交给底层编译器的路径问题
因.cpp .cc文件交给GCC编译器编译时,会转化为.o文件,如果新老版本编译在不同编译环境,不同电脑,
可能交给编译器的文件路径而产生变化,所以使用静态路径PWD=/proc/self/cwd替换之前的绝对路径。
主要运用在了difinition.mk中,加入RELATIVE_PWD := PWD=/proc/self/cwd
define transform-cpp-to-o
@echo "$($(PRIVATE_PREFIX)DISPLAY) $(PRIVATE_ARM_MODE) C++: $(PRIVATE_MODULE) <= $<"
@mkdir -p $(dir $@)
$(if $(PRIVATE_TIDY_CHECKS),$(clang-tidy-cpp))
$(hide) $(RELATIVE_PWD) $(PRIVATE_CXX) \
$(transform-cpp-to-o-compiler-args) \
-MD -MF $(patsubst %.o,%.d,$@) -o $@ $<
endef
总结:
主要优化思路执行shell-find和通配符wildcard,notdir,patsubst时加入sort,使拿到的文件都会有顺序,但是
实际对比来说,编译文件的有序其实并不会对输出结果造成影响,这一部分的修改只会让代码编译时比较规整

二、内嵌时间戳处理
1、加入Android 7.0 开启了 -Werror=date-time
大致查了一些资料,-werror应该是GCC编译器的规则,且在Android9.0 soong(8.0之后新的编译方式)
中也有加入
GCC 4.9 and newer have a new warning -Wdate-time, which warns on any use
of __DATE__, __TIME__, or __TIMESTAMP__, which would make the build
non-deterministic. Now that the kernel does not use any of those
macros, turn on -Werror=date-time if available, to keep it that way.
加入该控制后,代码中不能出现 __DATE__, __TIME__, or __TIMESTAMP__相关的字符或者打印,测试后发现
在.cpp中加入确实时会编译报错
本身去除时间戳是为了避免生成文件的不必要变化,那么这就引入一个问题,在不能加入时间戳的情况下,
我们如何处理jar,zip,lib,嵌入编译时间呢,下面我们作下解读

1、lib文件处理
以external/libchrome为例
android.bp中引入了"libcutils",该库中有获取prop属性的方法,
通过propery_get方法,可以读取到ro.build.date最后返回的integral_build_time也就是ro.build.date

TODO:这里的修改不能得到完全理解,如果按照之前的const char kDateTime[] = "Sep 02 2008 08:00:00 PST";那生成的两个lib应该时一样的 按照目前读取编译时间怎么会使生成结果相同呢

2、zip ,jar文件处理-ziptime
由于jar本身也属于一种压缩格式,所以两个被归为一类处理;
这里引入一个Android编译时用到的工具./make/tools/ziptime
原本介绍:
ziptime -- zip timestamp tool
usage: ziptime file.zip
file.zip is an existing Zip archive to rewrite
This tools replaces the timestamps in the zip headers with a static time
(Jan 1 2008). The extra fields are not changed, so you'll need to use the
-X option to zip so that it doesn't create the 'universal time' extra.
大致解读为,所有的zip.jar文件最后生成时内部文件时间标记为2008年1月1日00:00
这也时为什么中间包中看里面的压缩时间为2008年0101的原因
解压了一些jar包,以及中间文件,发现都是在这个时间,而core/Makefile中并没有对压缩target文件单独
添加ziptime,所以这是编译时全局工具,所有的压缩文件都会使用该时间


3、sign签名apk和升级包处理
为了保证签名后的内嵌时间一致,在build/tools/signapk/src/com/android/signapk/SignApk.java中加入

// Set all ZIP file timestamps to Jan 1 2009 00:00:00.
long timestamp = 1230768000000L;
// The Java ZipEntry API we're using converts milliseconds since epoch into MS-DOS
// timestamp using the current timezone. We thus adjust the milliseconds since epoch
// value to end up with MS-DOS timestamp of Jan 1 2009 00:00:00.
timestamp -= TimeZone.getDefault().getOffset(timestamp);

设置timestamp为2009年1月1号00:00,SignApk.signWholeFile和signFile中加入该时间timestamp
这样涉及到签名的APK和升级包都为该内嵌时间
这也就是我们查看升级包时间时,内部显示文件时间为2009年,如果我们解压平台签名APK的话里面也是2009年

4、去除编译APK中的BUILD_NUMBER
去除app_version中的时间戳字段BUILD_NUMBER
ifneq "" "$(filter eng.%,$(BUILD_NUMBER))"
git_hash := $(shell git --git-dir $(LOCAL_PATH)/.git log -n 1 --pretty=format:%h)
date_string := $$(date +%m%d%y_%H%M%S)
变更version_name为:
version_name_package := $(base_version_major).$(base_version_minor).$(base_version_build)
这样如果APK没有修改的话,不会因为版本号差异而产生patch
总结:
内嵌时间戳的问题处理,将会减少一些文件不必要的差异化存在,降低一些patch的生成,
对减小差分包有一定的作用。

三、其他生成镜像时处理

这个方面中介绍的两个方面都是在7.0后没有什么作用的,不过可以简单了解下
1、target_files_diff.py
查询代码后,该文件现在只用于打印metadata 元数据的对比信息
在ota_from_target_files.py中以--log_diff 做包加入后会运行

如果做包的命令中有--log_diff 会调用recursivediff方法

最后会输出log信息,为ota_target_file.zip/META 中所有文件 source和target的对比信息

2、system_base_fs_file
在文档中提到的理论make_ext4fs 会接受可选的 -d base_fs ,这样生成system.img的时候会用到老版本的
system.map,尽量把对应文件放在相对应的块上,这样确实不会减少差分包的大小,因为块的差异数量是
没有变化的,但是确实会减少升级过程中move的情况出现,实际来说查询7.0到9.0的代码,并不存在这个功能
首先大概说下make otapackage过程中生成system.img的大概过程
makefile中定义了
define generate-userimage-prop-dictionary 会定义给一部分字段,这些字段会追加到
system_image_info.txt和misc_info.txt中,代码如下
$(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt, \
skip_fsck=true)
$(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt)
make ota过程中会通过add_img_to_target_files最后调用build_image,py重新生成system.img
build/make/tools/releasetools/add_img_to_target_files -a -v -p $(HOST_OUT) $(zip_root)
而生成的规则都是在misc_info.txt中定义的
为什么说没有这个功能的原因
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH),
$(hide) echo "system_base_fs_file=$(PRODUCTS.$(INTERNAL_PRODUCT).
PRODUCT_SYSTEM_BASE_FS_PATH)" >> $(1))
define generate-userimage-prop-dictionary 中确实定义了该字段,但是后续misc_info.txt文件中并没有
system_base_fs_file相关的定义,本身PRODUCT_SYSTEM_BASE_FS_PATH应该指向一个文件路径
而代码中也没有查到,

最后执行mkuserimg_mke2fs.sh 也有没有-d base_fs选项,编译system.img log如下

四、总结

 以上对文档内容划分并进行了解读,因文档比较老,一些方法或者文件已经不在使用,而且基本涉及都是编译生成 文件阶段,对于OTA升级包减小其实没有太大的帮助,不过可以更好的理解一些编译相关的机制。  。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值