修改Android操作系统源代码

2019年3月30日

获取源代码

最好的办法是《repo工具笔记》里介绍的

repo init --depth 1 -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r52
repo sync -c --no-tags -j4

注,-j4表示用4条线程运行,可以按照计算机的实际配置增加。

确定代码版本

就算知道要编译Android 8.1.0,8.1.0还有很多个细分版本,体现在repo或git里面就是很多个标签。8.1.0的最新版本是android-8.1.0_r52。

如果获取源代码时用了我推荐的命令(有选项--no-tags),版本库中没有任何标签,便无从确定代码版本。这时需要获取指定的标签。不要获取所有标签,这样会太乱,难以筛选历史记录。

如果获取源代码时运行的repo命令没加选项--no-tags,版本库中则充满了标签。这时可以删除多余标签。

获取指定的标签

$ git fetch --no-tags aosp refs/tags/android-8.1.0_r52:refs/tags/android-8.1.0_r52
From https://android.googlesource.com/platform/art
 * [new tag]             android-8.1.0_r52 -> android-8.1.0_r52

删除某些标签

git tag --list 'android-*' | xargs -I % git tag -d %

以上代码删除了所有以android-开头的标签。

批量删除本地的远端跟踪分支可以用如下命令

git branch -r --list 'aosp/*-dev' |  xargs -I % git branch -rd %

编译目标

如果打算用模拟器运行,lunch里选择aosp_x86-eng。如果没有选择这个目标,运行模拟器可能运行速度可能会非常慢。如果打算用真机运行,要先在《Driver Binaries for Nexus and Pixel Devices》下载对应的二进制文件。具体怎么对应呢?

假设源代码的标签为android-8.1.0_r52,就要在《代号、标签和细分版本号》搜索android-8.1.0_r52对应的细分版本(build number),可以找到是OPM7.181205.001。

真机是什么版本应该在包装上有说明,假设我的真机是Nexus 5X。那么,要在《Driver Binaries for Nexus and Pixel Devices》下载Nexus 5X binaries for Android 8.1.0 (OPM7.181205.001)。

首次编译

如果用Ubuntu 18.04编译Android 7.1.2或以上源代码,需要在make前运行export LC_ALL=C

export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4g"

增加JVM堆大小。然后重启jack。

export LC_ALL=C意思是设置环境变量LC_ALL,并导出为全局环境变量。[1][2]

LC_ALL的值可以是……

编译范围

WORKING_DIRECTORY/build/make/core/build-system.html 写道,编译时选择lunch包括了选择Build flavors/types。“eng is the default flavor. A plain “make” is the same as “make eng”. droid is an alias for eng. … Installs modules tagged with: eng, debug, user, and/or development.”

所以我们知道,eng版就是调试版,user版是发布版。显然调试版比user版提供更多的功能或模块。

延伸问题:既然WORKING_DIRECTORY/system/extras/su提供了su程序,为什么我还需要root?root的本质是什么?

破解Root权限的原理就是在手机的/system/bin/或/system/xbin/目录下放置一个可执行文件“su”。但WORKING_DIRECTORY/system/extras/su不是提供了su程序吗?原来,su程序的tag是debug,发布版并不会包括su。

另外,Android su跟Linux的su不同。从源代码和帮助文件来看,Android su缺少很多命令行选项,如-c选项没有。另外,Android su仅允许root和adb shell调用。[3]所以,root工具都会给bin文件夹里加一个类似于linux su的su。

系统配置

adb shell su root 'svc bluetooth disable'  #关闭蓝牙
adb shell su root date "$(date +%m%d%H%M%Y)" #更新Android系统时间
Jared Burrows. How to turn off Wifi via ADB?. . 2012-04-06 [2019-04-03].

编译单独模块

运行. build/envsetup.sh之后,输入hmm可以看帮助

$ hmm
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch:     lunch <product_name>-<build_variant>
- tapas:     tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user]
- croot:     Changes directory to the top of the tree.
- m:         Makes from the top of the tree.
- mm:        Builds all of the modules in the current directory, but not their dependencies.
- mmm:       Builds all of the modules in the supplied directories, but not their dependencies.
             To limit the modules being built use the syntax: mmm dir/:target1,target2.
- mma:       Builds all of the modules in the current directory, and their dependencies.
- mmma:      Builds all of the modules in the supplied directories, and their dependencies.
- provision: Flash device with all required partitions. Options will be passed on to fastboot.
- cgrep:     Greps on all local C/C++ files.
- ggrep:     Greps on all local Gradle files.
- jgrep:     Greps on all local Java files.
- resgrep:   Greps on all local res/*.xml files.
- mangrep:   Greps on all local AndroidManifest.xml files.
- mgrep:     Greps on all local Makefiles files.
- sepgrep:   Greps on all local sepolicy files.
- sgrep:     Greps on all local source files.
- godir:     Go to the directory containing a file.

Environment options:
- SANITIZE_HOST: Set to 'true' to use ASAN for all host modules. Note that
                 ASAN_OPTIONS=detect_leaks=0 will be set by default until the
                 build is leak-check clean.

Look at the source to view more functions. The complete list is:
addcompletions add_lunch_combo build_build_var_cache cgrep check_product check_variant choosecombo chooseproduct choosetype choosevariant core coredump_enable coredump_setup cproj croot destroy_build_var_cache findmakefile get_abs_build_var getbugreports get_build_var getdriver getlastscreenshot get_make_command getprebuilt getscreenshotpath getsdcardpath gettargetarch gettop ggrep godir hmm is isviewserverstarted jgrep key_back key_home key_menu lunch _lunch m make mangrep mgrep mm mma mmm mmma pez pid printconfig print_lunch_menu provision qpid rcgrep resgrep runhat runtest sepgrep set_java_home setpaths set_sequence_number set_stuff_for_environment settitle sgrep smoketest stacks startviewserver stopviewserver systemstack tapas tracedmdump treegrep

似乎没有网上的官方文档提供以上内容,除了源代码

既然编译单独模块,就使用mm命令。经实测,似乎必须指定模块目录

WORKING_DIRECTORY$ mm art

而不是

WORKING_DIRECTORY/art$ mm

用后一个方法似乎某些配置文件不会导入,代码样式会出错。待探究。

重新打包

$ make snod

怎么知道这个命令呢?

编译结果放在环境变量ANDROID_PRODUCT_OUT所指向的目录,用echo $ANDROID_PRODUCT_OUT查看。返回值形如WORKING_DIRECTORY/out/target/product/generic_x86,其中generic_x86是以前选择的lunch combo。

怎么知道ANDROID_PRODUCT_OUT呢?

emulator -help-disk-images写道

If you are building from the Android build system, you should
have ANDROID_PRODUCT_OUT defined in your environment, and the
emulator shall be able to pick-up the right image files automatically.
See -help-build-images for more details.

脚本化

#Try to only flash system partition, thus don't have to flash TWRP recovery image over and over.
fastboot flash system #光flash system不行,原来的程序还在
fastboot flash userdata
# recovery模式下,电脑不一定能访问手机。新镜像刷进后,可能至少要重启一次才能在recovery模式被电脑识别。


adb push Magisk-v18.1.zip /sdcard/
adb push open_gapps-arm64-8.1-mini-20190409.zip /sdcard/
# 安装root管理器
adb install MagiskManager-v7.1.1.apk

# 这是打开Magisk应用,会显示未安装Magisk。

adb reboot recovery


# 用指定的镜像文件重启。
fastboot boot twrp-3.2.3-0-angler.img

# 安装magisk,即root
adb shell twrp install /sdcard/Magisk-v18.1.zip

# 重启到系统,测试一下root
# 运行magisk应用,应该显示Magisk已安装


# 安装Google服务
adb shell twrp install open_gapps-arm64-8.1-mini-20190409.zip

# The first boot after installation takes 10 minutes!

adb reboot recovery

# note the syntax has changed because the su has been changed to magisk su.
adb shell su -c date "$(date +%m%d%H%M%Y)"
adb shell su -c 'svc bluetooth disable'
adb shell settings put system accelerometer_rotation 0 #disable auto rotate

https://android.stackexchange.com/a/201213/97993

疑难解答

Q:运行fastboot flashall -w,却提示“could not load ‘boot.img’: No such file or directory”。

A:检查lunch是否对应真机版本。

Q: 仓库无法推送到另一个远端仓库,提示“git shallow update not allowed”。

A:这是因为当初克隆的时候,加了选项--depth。浅克隆的仓库不能推送到另一个远端仓库,需要深化才可以。[4]

git fetch --unshallow --no-tags origin

Q:不小心运行了git fetch或git pull,获取了很多不必要的分支、标签和提交,如何撤销?

用上面“确定代码版本”一节里的代码清理标签和分支。

git update-ref refs/remotes/aosp/master HEAD

把远程master分支重置回HEAD(你正在工作的几年前的版本)。

参考资料

参考资料

  1. . Bourne Shell Builtins. . [2019-04-16].
  2. Richard Blum, Christine Bresnahan; . Linux命令行与shell脚本编程大全 第三版. . 2016, (): 108 [].
  3. . su.cpp. . [].
  4. Sascha Wolf. Remote rejected (shallow update not allowed) after changing Git remote URL. . 2015-03-11 [2019-04-23].