由于之前的渣本试过一次裸ubuntu编译Android源码,一次则用虚拟机。过程中参考了官网/网络博客的教程,失败了好几次,也成功了两次。上一次买了个稍微好一点的笔记本,也裸ubuntu编译过一次7.0的源码,后面因为其他工作的需求,暂且换成window系统,再一次重新折腾编译源码。整理下之前的笔记及参考资料,写下记录供需要者参考,减少踩坑。
题外话:把之前在ubuntu编译的源码拉到windowAS阅读,虽然能够根据方法栈不断深入查看方法调用的逻辑,但是无法调试且难以修改原生应用。所以强烈建议在ubuntu上折腾,把整个过程弄得够熟悉就行了,也对整个Android系统有个大致的了解。
准备环境
编译环境选择
Ubuntu- 我的电脑
Window64bit,8G内存,256固态硬盘 - ubuntu-16.04.3-desktop-amd64 运行于
VMware,分配4G内存,100G硬盘空间 - 若是其他硬件基础,可参考源代码-下载和构建-概要-硬件要求
- 我的电脑
Git安装
1 | $ sudo apt-get install git |
下载源码
1 | mkdir ~/bin |
- 弃用官方下载源码方法,改用清华大学开源软件镜像
这里我选择传统的初始化方法下载源码,创建存放源码的source目录,取名自定。
1 | mkdir source |
新建auto_asyn_source.sh是用来保证执行repo编译环境选择
sync命令同步代码如果失败,则可以自动重试,参考的是自己动手编译最新Android源码及SDK一文的做法,感谢该博主。
写入shell脚本自动同步内容:
1 | vim auto_asyn_source.sh |
把下面的代码复制进去并保存
1 | PATH=~/bin:$PATH |
其中android-6.0.1_r66是我选择下载的源码分支,可替换成其他。然后添加修改Repo的url
1 | cd ~/ |
把下面的链接添加进入并保存
1 | REPO_URL = 'https://gerrit-google.tuna.tsinghua.edu.cn/git-repo' |
最后,跑一下脚本下载,静心等待呗…
1 | cd source |
Tip:过程中我的虚拟机比较卡,可能会出现卡死的现象=。=,只需要Ctrl+C结束之后重新执行脚本就行了。
由于上班折腾下很久才下载完,和下载环境的网络有关,下载完成后大概有58G大小。
1 | yummylau@ubuntu:~/source$ du -h --max-depth=1 |
选择编译目标
使用lunch选择要编译的目标。根据官网教程。该命令表示针对模拟器进行完整编译,并且所有调试功能均处于启用状态。 如果没有提供任何参数就运行命令,lunch将提示您从菜单中选择一个目标,所有编译目标都采用BUILD-BUILDTYPE形式。
这里,我输入以下指令选择编译目标。
1 | lunch aosp_arm-eng |
解释下上述名下的参数,aosp_arm-eng即BUILD-BUILDTYPE形式,分为BUILD和BUILDTYPE两部分。
- BUILD为特定功能的组合代号,如
aosp_arm为支持32位ARM架构,也有64位ARM架构,X86也有。关于CPUARM和X86架构,可以看下这篇分不清ARM和X86架构,别跟我说你懂CPU!科普文。 - BUILDTYPE为编译类型,主要用于指定系统权限,有以下三种:
user,权限受限,适用于生产环境;userdebug,与“user”类似,但具有 root 权限和可调试性;是进行调试时的首选编译类型;eng,具有额外调试工具的开发配置。
这里我选择aosp_arm-eng作为编译目标进行编译。
开始编译
官方使用make来编译任何代码。Make可以借助 -jN 参数处理并行任务,通常使用的任务数 N 介于编译时所用计算机上硬件线程数的 1-2 倍之间。由于我用的是虚拟机,主机是司核四线程,虽然我Ubuntu虚拟机分配了2个处理器,每个处理器核数为2。一开始我用make -j4编译,可卡死我了,不小心点击了清理内存和高CPU程序,把我虚拟机直接杀了,后面直接使用make编译,大家随自己设备决定即可。window平台下可在运行中输入wmic,在新窗口中输入cpu get即可查看物理CPU数、CPU核心数、线程数。
- Name:表示物理CPU数
- NumberOfCores:表示CPU核心数
- NumberOfLogicalProcessors:表示CPU线程数
运行make使用单线程编译。
1 | make |
慢悠悠看了几集冰与火之歌,大概编译了4个多小时,就搞定了,编译后的产物有out目录中。
1 | yummylau@ubuntu:~/source/out$ du -h --max-depth=1 |
其中各个目录的内容为:/out/host/:该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等。/out/target/common/:该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库。/out/target/product/<product_name>/:包含了针对特定设备的编译结果以及平台相关的 C/C++ 库和二进制文件。其中,<product_name>是具体目标设备的名称,产物如下图。
1 | yummylau@ubuntu:~/source/out/target/product$ cd generic/ |
注意下,上述有三个核心的镜像文件:system.img,ramdisk.img和userdata.img。system.img:包含了 Android OS 的系统文件,库,可执行文件以及预置的应用程序,将被挂载为根分区。ramdisk.img:在启动时将被 Linux 内核挂载为只读分区,它包含了 /init 文件和一些配置文件。它用来挂载其他系统镜像并启动 init 进程。userdata.img:将被挂载为 /data,包含了应用程序相关的数据以及和用户相关的数据。
关于如何理解Android的Build系统,推荐阅读IBM-理解 Android Build 系统。
运行编译系统
在源码个目录重新执行
1 | yummylau@ubuntu:~/source$ source build/envsetup.sh |
在之前的编译流程会自动将模拟器添加到您的路径中,emulator加载的内核所在的目录为
1 | yummylau@ubuntu:~/source/prebuilts/qemu-kernel/arm$ ls |
其中,kernel-qemu为加载的内核。
同时在~/source/out/target/product/generic中生成的system.img,ramdisk.img和userdata.img也被载入了。
最后,我们就静静地等待系统启动吧~