前言
工作中发现在MTK平台编译某一模块时,Android Q的系统源码编译速度比Android P慢了许多,需要分析下原因并改善编译速度。
从Android Q编译时的输出日志中看出:每次mm编译一个app模块时,都会打印如下信息:
$(file <out/build_number.txt) was changed, regenerating...
[ 0% 0/1] initializing build system ...
接着就是长达几分钟的等待,哪怕什么代码都没改,编译依然耗费一段时间。
熟悉Android编译系统的应该知道,每次显示修改mk文件或git pull操作时都会触发.ninja文件的重新生成。这个几百M大小的文件是由ckati工具生成的,我们查看out目录下的文件,build-full_xxx-packages_noahapps_xxx_Android.mk.ninja每次都刷新了时间戳。很明显在没有修改任何源码的情况下这次生成是不必要的。
分析过程
分析build_number.txt文件为什么每次编译时都会生成,即使里面的内容是没有变化的。
1、查看build/make/core/main.mk:
# Write the build number to a file so it can be read back in
# without changing the command line every time. Avoids rebuilds
# when using ninja.
$(shell mkdir -p $(OUT_DIR) && \
echo -n $(BUILD_NUMBER) > $(OUT_DIR)/build_number.txt)
BUILD_NUMBER_FILE := $(OUT_DIR)/build_number.txt
可以看出build_number.txt中的内容是根据BUILD_NUMBER属性生成的。
2、查看build/make/core/Makefile:
BUILD_NUMBER="$(BUILD_NUMBER_FROM_FILE)" \
3、查看build/make/core/config.mk:
BUILD_NUMBER_FROM_FILE := $$(cat $(OUT_DIR)/build_number.txt)
BUILD_DATETIME_FROM_FILE := $$(cat $(BUILD_DATETIME_FILE))
可以看出BUILD_NUMBER来源于BUILD_NUMBER_FROM_FILE属性,而BUILD_NUMBER_FROM_FILE又是读取out/build_number.txt的文件内容。
4、其中的关系如图
from
from
from
build_number.txt
BUILD_NUMBER
BUILD_NUMBER_FROM_FILE
看来形成了一个闭环链关系,等等,这不自相矛盾了吗?
5、再全局搜索BUILD_NUMBER属性是否还有赋值的地方:
发现device/mediatek/build/vendorsetup.sh:
export TEMPORARY_DISABLE_PATH_RESTRICTIONS=true
if [ "$BUILD_NUMBER" = "" ] ; then
if [ -f "vendor/mediatek/proprietary/buildinfo/label.ini" ] ; then
export BUILD_NUMBER=$BUILD_NUMBER
fi
fi
看来设备厂商也有一个生成BUILD_NUMBER的方法,有可能是这里,通过初始化编译环境时也能看到相关log,一开始就加载了device目录下的vendorsetup.sh
liuke@youxuepai-PC1:~/work/P713_mt6779$ source set_env.sh
call set_env.sh
including noah device/mediatek/build/vendorsetup.sh
加载逻辑位于build/make/envsetup.sh中的source_vendorsetup()方法
function source_vendorsetup() {
allowed=
for f in $(find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); do
if [ -n "$allowed" ]; then
echo "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:"
echo " $allowed"
echo " $f"
return
fi
allowed="$f"
done
allowed_files=
[ -n "$allowed" ] && allowed_files=$(cat "$allowed")
for dir in device vendor product; do
for f in $(test -d $dir && \
find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do
if [[ -z "$allowed" || "$allowed_files" =~ $f ]]; then
#在这里include device目录下的vendorsetup.sh
echo "including noah $f"; . "$f"
else
echo "ignoring $f, not in $allowed"
fi
done
done
}
6、至此,我们再回到build/make/core/main.mk文件,删除这里生成的build_number.txt的方法:
7、验证编译make services:由于修改了main.mk,重新触发了.ninja文件生成所以第一次会耗时,稍微改动下java文件并再次编译发现没有生成build_number.txt和.ninja文件了,速度快了很多。
============================================
19:43:31 AllowBuildBrokenUsesNetwork: true
19:43:31 BuildBrokenUsesNetwork: true
[100% 16/16] Copy: out/target/product/yxp_752_pad/system/framework/oat/arm64/services.odex
build completed successfully (01:10 (mm:ss))(2022年 09月 28日 星期三 19:44:13 CST)
最终实现
对比Android P下build_number.txt的生成过程:
在build/make/core/version_default.mk:
ifndef BUILD_NUMBER
# BUILD_NUMBER should be set to the source control value that
# represents the current state of the source code. E.g., a
# perforce changelist number or a git hash. Can be an arbitrary string
# (to allow for source control that uses something other than numbers),
# but must be a single word and a valid file name.
#
# If no BUILD_NUMBER is set, create a useful "I am an engineering build
# from this date/time" value. Make it start with a non-digit so that
# anyone trying to parse it as an integer will probably get "0".
BUILD_NUMBER := eng.$(shell echo $${USER:0:6}).$(shell $(DATE) +%Y%m%d.%H%M%S)
HAS_BUILD_NUMBER := false
endif
同时发现device/mediatek/build/vendorsetup.sh源码中也没有属性BUILD_NUMBER的赋值定义。
所以两个平台的build_number.txt内容形式也不一样。
Android P:eng.liuke.20220926.200349
Android Q:mp1V9110
最后我们完善下Android Q中main.mk文件build_number.txt的这块内容,避免不必要的重新生成:
$(shell mkdir -p $(OUT_DIR) && \
echo -n $(BUILD_NUMBER) > $(OUT_DIR)/build_number.tmp; \
if ! cmp -s $(OUT_DIR)/build_number.tmp $(OUT_DIR)/build_number.txt; then \
mv $(OUT_DIR)/build_number.tmp $(OUT_DIR)/build_number.txt; \
else \
rm $(OUT_DIR)/build_number.tmp; \
fi)
提交,万事大吉!