早些年刚毕业,在老东家参与开发Launcher的时候就接触过AOSP,那时的早教平板还是基于Android 4.4的源码进行定制的。后续跑路了,就一直在应用层摸鱼,最近一时兴起,想复习一些基础姿势,所以本文来了~
Tips:本文并非笔者亲身实践,是借鉴了参考文献处几位大佬的文章总结得出。asop源码的下载费时,笔者没有编译扫写源码的需求,只是解BUG或了解底层机制时看看源码,SDK自带的android.jar和一些在线源码站点已经够用。环境搭建流程基本是一致的,遇到问题善用搜索引擎~
0x1、名词
① AOSP
中文官网:source.android.google.cn/
Android Open Source Package,安卓系统开源源码包
,Android移动终端平台 (高通、MTK等) 先基于原生的Android代码进行更改,形成自己的平台代码,其他 手机厂商 再根据平台代码提供自己的移动端解决方案 (系统定制
)。
asop源码编译后会生成一系列的产物(out目录下):
- /out/host → Android开发工具相关的产物,包含各种SDK工具,如adb、dex2oat、aapt等;
- /out/target/common → 一些通用的编译产物,包含Java应用代码和Java库;
- /out/target/product/[product_name] → 针对特定设备的编译产物,以及平台相关C/C++代码与二进制文件(如system.img、ramdisk.img、userdata.img、boot.img等);
我们平时在AS里看到的源码库 android.jar
是打包后的 classes.jar
,详细路径:out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar。以前在一些场景,需要使用SDK中隐藏的API (@hide注解),一种解法就是用aosp编译生成的classes.jar替换原生sdk中的android.jar。具体导入示例可见:《Android Studio 3.5导入AOSP编译的classes.jar》
② Gerrit
Android使用Git作为代码管理工具,开发了 Gerrit
进行 代码审核,以便更好地对代码进行集中式管理。实际上就是一个 Git服务器,它为在其服务器上托管的Git仓库提供了一系列 权限控制,以及一个用作Code Review 的 Web页面。
③ Repo
Repo命令行工具,用Python对Git命令进行封装,简化对多个Git库的集中式管理。
0x2、Repo工作流
如下图:
简要描述下关键命令:
repo init
→ 在当前目录下初始化Repo,生成.repo
目录,其中会包含一个manifest.xml
文件,列出每个project的克隆方式 (版本库地址、和工作区地址的对应关系、分支对应关系等);repo sync
→ 同步所有project到本地工作区;repo start
→ 创建并切换到本地工作分支;Git相关命令
→ 本地修改某些Project的代码,常规提交;repo upload
→ 将代码修改发布到审核服务器;repo prune
→ 功能开发完,合并后,安全移除过时主题分支;
更详细内容可参见:《源代码控制工作流程》
0x3、系统准备
只是单纯下载源码,啥系统都可以,但如果还想进行编译的话,需要 Linux
或 Mac OS
系统。
Windows想编译的话,可以通过 虚拟机 安装上述系统间接达成,常规方式:Docker
或 VirtualBox
。后者安装示例可见:《Android AOSP基础(一)VirtualBox 安装 Ubuntu》
更详细内容可参见:《搭建构建环境》
0x4、源码下载
走一波下述命令~
# ① 安装Git、Curl、Python,有些系统自带~
sudp apt-get install git
sudo apt-get install curl
sudo apt-get install python
# ② 创建bin,并添加到PATH中
mkdir ~/bin
PATH=~/bin:$PATH
# ③ 下载Repo工具,并设置为可执行
# Tips:国外源可能有问题,可以替换为国内镜像,比如:https://mirrors.tuna.tsinghua.edu.cn/git/git-repo
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
# ④ 创建工作文件目录 (存源码)
mkdir aosp
cd aosp
# Tips:Repo在运行过程中会尝试访问官方Git源更新自己,如果想用tuna镜像更新,可复制
# 下述内容到~/.bashrc中
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
# ⑤ Git设置身份信息(名字、邮箱)
git config --global user.name "User Name"
git config --global user.email "user@example.com"
# ⑥ 初始化仓库 (同样支持替换镜像源)
repo init -u https://android.googlesource.com/platform/manifest
# 也支持指定分支,可选值查看:https://source.android.com/source/build-numbers#source-code-tags-and-builds
repo init -u https://android.googlesource.com/platform/manifest -b android-9.0.0_r8
# ⑦ 同步代码 (拉取aosp源码到工作目录,一般要几个小时)
repo sync
# Tips:下载过程可能出现某些project找不到,可能是镜像问题,也可能是网的问题,
# 试试可以单独同步该项目,支持-jN参数,-j4如:
repo sync -c platform/frameworks/layoutlib
# 附:asop不包含内核代码,有需要可以单独下载,版本有很多,如:
# common → 通用linux内核、goldfish → Android模拟器内核、msm → 高通MSM芯片
mkdir kernel
cd kernel
git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git
cd goldfish
# 可以查看有哪些内核版本分支可以下载
git branch -a
# 下载对应版本内核代码
git checkout remotes/origin/android-goldfish-3.4
更详细内容可参见:《下载源代码》
另外,国外镜像难免不稳定,也可以直接用 清华镜像,首次同步容易失败,建议先用迅雷等软件直接下载初始化包 aosp-latest.tar 进行初始化,然后再同步。
0x5、编译
同样,先是一些名词的解释:
Makefile
→ Android平台编译系统,用Makefile写出来的一个独立项目,定义了编译规则,实现自动化编译,将分散在数百个Git库中的代码整合起来,统一编译,而且把产物分门别类地输出到一个目录,打包成手机ROM,还可以生成应用开发时使用的SDK、NDK等。Android.mk
→ 定义一个模块的必要参数,使模块随着平台编译,简单点说就是告诉系统以什么规则编译源代码,并生成对应目标文件;kati
→ Google专门为Android研发的小工具,基于Golang和C++,作用是:将Android中的Makefile转换为Ninja文件Ninja
→ 致力于速度的小型编译系统,把Makefile看做高级语言,那它就是汇编,文件后缀为.ninja;Android.bp
→ 替换Android.mk的配置文件;Blueprint
→ 解析Android.bp文件翻译成Ninja语法文件;Soong
→ Makefile编译系统的替代品,负责解析Android.bp文件,并将之转换为Ninja文件;
关系描述:
- Android工程越来越大,Makefile编译耗时越来越长,Android 7.0引入速度和并行效率更佳的Ninja来编译系统;
- Soong 借助 Blueprint定义的Android.bp语法,完成Android.bp的解析,最终转换成Ninja文件;
- Makefile文件(.make或.mk)通过kati转换为Ninja文件(.ninja);
- Makefile是设计来给开发编写的,而Ninja则是设计给其他程序生成的,可类比做高级语言和汇编语言;
① 编译环境准备
# ① 安装jdk 8
sudo apt-get update
sudo apt-get install openjdk-8-jdk
# Tips:使用ubuntu 14+,还需要安装下述依赖包
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip
② 源码整编
# ① 初始化环境
source build/envsetup.sh
# ② 删除out与中间文件,clean会删除本次设置生成的、clobber会删除所有配置生成的
make clobber
# ③ 选择编译目标,下述命令会进入菜单,选择相应的版本,输入序号回车
# 编译目标都采用 BUILD-BUILDTYPE 形式,BUILD 表示特定功能代号,BUILDTYPE是以下类型之一:
# user → 权限受限、适用于生产环境,没root权限,不能debug,adb默认处于停用状态;
# userdebug → 与user类似,但具备root权限和debug权限,一般用于调试真机。
# eng → 具有额外调试工具的开发配置,拥有最大的权限(root等),一般用于模拟器。
# 编译目标示例 → Pixel 3a XL的编译目标 → aosp_bonito-userdebug
lunch
# 也可以直接指定编译目标,如:lunch aosp_bonito-eng
# 还可以直接用序号,如:lunch 8,但不建议,因为不同的系统版本序号对应可能有偏差~
# ③ 开始编译,后面的-jN参数用来设置编译的并行任务数,CPU核心数为6,N值最好选6-12间
# 根据自己CPU核心数动态修改哈,见过有32的~
make -j6
# 也可以把输出结果打印到log文件中:make -j6 2>&1 | tee build_20211206_1403.log
# 编译成功后会生成out目录,比如这里的:~/aosp/out/target/product/bonito
# Tips:有需要还可以键入:make sdk,编译SDK生成修改后的android.jar
③ 源码单编
整编一般会耗费几小时,有时可能只是修改了其中某个应用模块,只需单独编译这个模块,以设置模块为例:
source build/envsetup.sh
lunch aosp_bonito-eng
# 进入模块目录
cd package/apps/Setting
# 编译单独模块的可选指令如下:
# mm → 编译当前目录下的模块,不编译依赖模块
# mmm → 编译指定目录下的模块,不编译依赖模块
# mma → 编译当前目录下的模块及其依赖项
# mmmma → 编译指定路径下所有模块,切包含依赖
mm
# 编译成功会提示生成文件的存放路径,除了生成Setting.odex外,还会在
# priv-app/Settings目录下生成Settings.apk,可直接adb push或adb install
# 安装APK验证效果,也可以使用make snod命令重新打包生成system.img,运行模拟器查看
0x6、刷机
① 亲儿子Pixel或Nexus
恭喜,可以直接刷,先到 Driver Binaries for Nexus and Pixel Devices 根据自己的机型和Android版本号,下载对应的驱动。接着解压执行:
./extract-qcom-sargo.sh
./extract-google_devices-sargo.sh
进入bootloader,执行烧写命令(-w代表清空数据)
adb reboot bootloader
fastboot flashall -w
然后等待烧写完成即可~
② Android虚拟机
得自己编译AVD镜像,lunch那里选择 sdk_phone_x86_64 编译目标,除常规编译外,还得附加 sdk 和 sdk_repo 包。
上述方法不生效的话,可以把镜像Copy到 SDK/system-images/android-xx/
的其中一个目录中。
③ 其他手机
不是亲儿子,驱动啊、厂商库啥的,只能找第三方ROM进行二次开发咯,以前最出名的就是CM (CyanogenMod) 了,不过好像凉凉了,可以试试 LineageOS
限于篇幅,就一一叙述了,感兴趣想自己试下的可参考:《自己动手编译Android(LineageOS)源码》
0x7、查看Android系统源码的其它方式
除了直接把完整源码下载到本地外,还可以直接在线查看,或者通过AS直接查看。
① 在线查看
不用下一堆代码,而且多个版本挑着看,很香~
- cs.android.com (官方,速度快,可能需要科学上网)
- platform_frameworks_base (Github直接看)
- googlesource (非常全,适合单个模块直接git clone)
- AndroidXref (有点旧了,最新版本到Android 9)
② AS快速查看
依次点击:Settings → Appearance&Behavior → System Settings → Android SDK → 选择所需Android SDK版本源码下载:
接着build.gradle设置下 compileSdk 版本号,Sync一下,点击跳转Framework的类即可跳转。
0x8、调试Android系统源码
① 生成索引
Android源码提供了直接生成AS可识别的文件工具,编译完成Android源码后,会在源码根目录生成一个 android.ipr
。
AS 以 Open an existing Android Studio Project
方式打开此文件,静待索引生成完毕。
索引生成后,调整下AS监视源代码的目录,如out这样的目录,每次编译完都会产生变化,但基本不会用到此目录,直接去掉索引(Excluded掉),以out目录为例,其他不需要的目录也是这样处理:
② 设置JDK和SDK
根据源码版本选择对应的SDK:
设置JDK:
③ 调试源码
源码下断点,然后点击 Attach Debugger to Android Process
选中待调试进程,然后就可以愉快的调试啦~
真机想调试系统进程需要Root权限,然后利用Magisk等软件修改:ro.debuggable = 1,可以新建模拟器时选择 非 Google Play的64位镜像,也可以得到 ro.debuggable = 1 的设备。
大部分时候调试源码是用不到所有的AOSP源码的,也可以直接导入部分源码进行调试。
另外,真机调试,可能出现调试行号与源码不一致,行号跑注释里的情况,大多数原因是国产ROM对相关源码进行了修改,可以在Debugger/Frames看到调用方法,了解这一步进入的哪个方法,然后Ctrl+F查找方法名,定位到正确位置。
0x9、小结
本节快速过了一下AOSP基础相关的姿势,算是为Framework的学习做准备,后续有搞这一块再深入学一波吧~
参考文献: