Android源码之下载编译导入AS(Mac版)
AOSP源码下载和编译
环境准备
官方指南:
要求
搭建编译环境
推荐准备250G可用磁盘空间。
创建分区大小写的磁盘映像
Mac OS默认会在不区分大小写的文件系统中运行,但由于Git并不支持此类文件系统,所以需要在Mac OS上建立一个区分大小写的磁盘分区。我们这里使用命令行来创建,一是比较方便,二是后期可扩展。
您可以使用磁盘映像在现有的 Mac OS 环境中创建区分大小写的文件系统。要创建磁盘映像,请启动磁盘工具,然后选择“新建映像”。这里推荐准备250G的磁盘空间;更大的空间能够更好地满足未来的需求。使用稀疏映像有助于节省空间,而且以后可以随着需求的增加进行扩展。请务必选择“Case sensitive, Journaled”存储卷格式。
您也可以通过 shell 使用以下命令创建磁盘映像:
$ hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 250g ~/android.dmg
这将创建一个 .dmg
(也可能是 .dmg.sparseimage
)文件,该文件在装载后可用作具有 Android 开发所需格式的存储卷。
如果您以后需要更大的存储卷,还可以使用以下命令来调整稀疏映像的大小:
$ hdiutil resize -size g ~/android.dmg.sparseimage
比如需要把250G调整成300G:
$ hdiutil resize -size 300g ~/android.dmg.sparseimage
注意:调整分区大小的命令,需要在该分区磁盘映像已卸载的情况下才能生效。
添加装载和卸载磁盘分区的命令和函数
对于存储在当前用户目录下的名为 android.dmg
的磁盘映像,您可以向 ~/.bash_profile
中添加辅助函数:
# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }
注意:如果系统创建的是 .dmg.sparseimage
文件,请将 ~/android.dmg
替换成 ~/android.dmg.sparseimage
。
需要装载分区磁盘映像时,执行如下命令即可,装载路径为/Volumes/android
:
$ mountAndroid
同样,卸载的函数如下,我们也将它添加到~/.bash_profile
文件中:
# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }
执行如下命令,便可卸载该分区磁盘映像:
$ umountAndroid
安装JDK
如果Mac已经安装JDK且配好了环境变量,可省略这步。
要查看在开发各种 Android 版本时要使用的 Java 版本,请参阅相关要求。
安装Xcode和其他软件包
1.安装Xcode命令行工具:
$ xcode-select --install
2.安装Xcode,直接在AppStore里安装即可。
3.安装MacPorts或Homebrew,MacPorts和Homebrew是软件包管理工具,可用来直接在终端里安装、更新和卸载软件包。建议二者都安装,笔者在通过MacPorts安装gnupg时死活装不上,最后通过Homebrew安装成功,如果网页访问不了,请翻墙。
4.在~/.bash_profile
文件中导入路径,就可以使用port或brew命令来管理软件包了:
export PATH=/opt/local/bin:$PATH
export PATH=/usr/local/bin:$PATH
5.安装gmake、libsdl、git和gnupg
- 如果是使用MacPorts,则执行如下命令:
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg
- 如果是使用Homebrew,则执行如下命令:
$ brew install gmake libsdl git gnupg2
设置文件描述符数量上限
在 Mac OS 中,可同时打开的文件描述符的默认数量上限太低,在高度并行的编译流程中,可能会超出此上限。要提高此上限,请将下列行添加到 ~/.bash_profile
中:
# set the number of open files to be 1024
ulimit -S -n 1024
至此,一切准备工作就绪,接下来就是下载源码了。
下载源码
官方教程,由于有墙的原因,下载过程中可能会出现各种问题,这里推荐使用清华大学镜像站来下载。
下载安装Repo工具
由于Android源码庞大复杂,所以Google专门开发了Repo来管理Android源码库,这里不多作介绍,有兴趣可自行阅读repo工具介绍。
按照官方建议,首先在用户主目录下有一个 bin/
目录,并且将该目录包含在路径中:
$ mkdir ~/bin
$ PATH=~/bin:$PATH
然后下载Repo工具,并确保它可执行:
$ curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
$ chmod a+x ~/bin/repo
初始化Repo客户端
在前面,我们通过mountAndroid
命令装载了我们分区后的磁盘映像,其装载路径为/Volumes/android
,所以我们需要在该目录下进行初始化,切换到该目录下,并且创建一个aosp
的工作目录:
$ cd /Volumes/android/
$ mkdir aosp
$ cd aosp
现在,我们的源码根目录全路径为/Volumes/android/aosp
。
Repo的运行过程中会尝试访问官方的git源更新自己,如果想使用清华的镜像源进行更新,可以将如下内容复制到你的~/.bashrc
(没有该文件则创建一个)里:
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
然后配置git,需要姓名和邮箱(如果已经配置过,不需要再配置):
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
运行repo init
来初始化master
分支:
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
要对master
以外的分支进行校验,请使用 -b
来指定相应分支。要查看分支列表,请参阅源代码标记和版本,笔者这里指定的是android-9.0.0_r35
分支:
$ repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r35
下载源代码
在终端进入/Volumes/android/aosp
源码根目录下,输入下面命令来同步代码:
$ repo sync
下载源代码的过程很漫长,期间可能会因为网络等原因,导致下载出错,因为repo同步支持断点续传,所以这里推荐使用shell脚本下载:
在源码根目录下创建一个reposync.sh
脚本文件,脚本内容如下:
#!/bin/bash
#FileName reposync.sh
PATH=~/bin:$PATH
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r35
repo sync
while [ $? = 1 ]; do
echo "================sync failed, re-sync again ====="
sleep 3
repo sync
done
保存好后,在源码根目录下的执行下面命令:
$ ./reposync.sh
这样就开始下载了,等待...
由于下载过程漫长,建议将Mac节能设置成防止进入睡眠。
当下载完成会提示:
Syncing work tree: 100%(xxx/xxx), done.
编译
编译命令还是在源码根目录下进行:/Volumes/android/aosp
初始化编译环境
使用envsetup.sh
脚本初始化环境:
$ source build/envsetup.sh
选择编译目标
使用lunch
选择编译目标:
$ lunch
You're building on Darwin
Lunch menu... pick a combo:
1. aosp_arm-eng
2. aosp_arm64-eng
3. aosp_mips-eng
4. aosp_mips64-eng
5. aosp_x86-eng
6. aosp_x86_64-eng
7. aosp_car_arm-userdebug
8. aosp_car_arm64-userdebug
9. aosp_car_x86-userdebug
10. aosp_car_x86_64-userdebug
11. mini_emulator_arm64-userdebug
12. m_e_arm-userdebug
13. m_e_mips-userdebug
14. m_e_mips64-eng
15. mini_emulator_x86-userdebug
16. mini_emulator_x86_64-userdebug
17. uml-userdebug
18. aosp_crosshatch-userdebug
19. aosp_blueline-userdebug
20. aosp_cf_x86_auto-userdebug
21. aosp_cf_x86_phone-userdebug
22. aosp_cf_x86_tablet-userdebug
23. aosp_cf_x86_tablet_3g-userdebug
24. aosp_cf_x86_tv-userdebug
25. aosp_cf_x86_wear-userdebug
26. aosp_cf_x86_64_auto-userdebug
27. aosp_cf_x86_64_phone-userdebug
28. aosp_cf_x86_64_tablet-userdebug
29. aosp_cf_x86_64_tablet_3g-userdebug
30. aosp_cf_x86_64_tv-userdebug
31. aosp_cf_x86_64_wear-userdebug
32. cf_x86_auto-userdebug
33. cf_x86_phone-userdebug
34. cf_x86_tablet-userdebug
35. cf_x86_tablet_3g-userdebug
36. cf_x86_tv-userdebug
37. cf_x86_wear-userdebug
38. cf_x86_64_phone-userdebug
39. cf_x86_64_tablet-userdebug
40. cf_x86_64_tablet_3g-userdebug
41. cf_x86_64_tv-userdebug
42. cf_x86_64_wear-userdebug
43. aosp_marlin-userdebug
44. aosp_marlin_svelte-userdebug
45. aosp_sailfish-userdebug
46. aosp_walleye-userdebug
47. aosp_walleye_test-userdebug
48. aosp_taimen-userdebug
49. hikey-userdebug
50. hikey64_only-userdebug
51. hikey960-userdebug
Which would you like? [aosp_arm-eng]
这里列出了所有的可编译的目标,所有编译目标都采用 BUILD-BUILDTYPE
形式。
BUILD
BUILD
表示特定功能的组合名称,即编译出的镜像可以在什么环境上运行,其中aosp(Android Open Source Project)代表Android开源项目,arm表示系统是运行在arm架构的处理器上,arm64则是指64位arm架构;处理器,x86则表示x86架构的处理器;此外,还有一些单词代表了特定的Nexus设备,下面是常用的设备代码和编译目标,更多参考官方文档
受型号 | 设备代码 | 编译目标 |
---|---|---|
Nexus 6P | angler | aosp_angler-userdebug |
Nexus 5X | bullhead | aosp_bullhead-userdebug |
Nexus 6 | shamu | aosp_shamu-userdebug |
Nexus 5 | hammerhead | aosp_hammerhead-userdebug |
BUILDTYPE
BUILDTYPE
表示编译类型,一般有三种:
编译类型 | 含义 |
---|---|
user | 表示编译出的系统镜像是可以用来正式发布到市场的版本,其权限是被限制的(如:没有root权限,不能dedug等) |
userdebug | 在user版本的基础上开放了root权限和debug权限 |
eng | 表示engineer,也就是所谓的开发工程师的版本,拥有最大的权限(root等),此外还附带了许多debug工具 |
如果你有Pixel或Nexus真机,选择对应的编译目标即可,否则我们就选模拟器,即5.aosp_x86-eng
。
在上面的Which would you like? [aosp_arm-eng]
后面输入5
即可。也直接选择:
$ lunch 5
或
$ lunch aosp_x86-eng
编译代码
在编译之前,可以输入以下命令,查看你的Mac CPU核数:
$ sysctl -n machdep.cpu.core_count
4
输出为4核,我们就可以启动4个线程来编译源码:
$ make -j4
接下来就是漫长的编译过程,一般需要2~3小时,如果看到下面的提示,则表示编译完成:
#### build completed successfully (02:15:52 (hh:mm:ss)) ####
运行模拟器
在编译完成之后,在终端里输入以下命令,可使用模拟器运行编译出的镜像:
$ emulator
如果想要模拟器能联网的话,可以这样启动模拟器:
$ emulator -dns-server 8.8.8.8,114.114.114.114
如果终端关闭了,下次进入源码根目录时想要启动模拟器,需要这样做:
$ source build/envsetup.sh
$ lunch aosp_x86-eng
$ emulator -dns-server 8.8.8.8,114.114.114.114
AOSP源码导入AS
编译idegen模块
在源码根目录下使用下面命令编译idegen
模块:
$ mmm development/tools/idegen/
编译完成后有如下提示:
#### build completed successfully (02:14 (mm:ss)) ####
继续执行下面命令,会在源码根目录下生成android.ipr
、android.iml
IDEA工程配置文件:
$ development/tools/idegen/idegen.sh
Read excludes: 26ms
Traversed tree: 118715ms
注意:对于平常看源码调试源码来说AOSP源码整体编译一遍就可以了,目前我们用到的单编就是上面所说的idegen模块,如果我们在源码导入AS的过程中出现了android.ipr/android.iml文件以及随后导入AS自动生成的android.iws文件损坏情况,我们只需在AOSP源码根目录下找到这三个文件删掉,然后重复上面的步骤重新生成一下就行了。
精简android.iml文件
android源码在一个类文件中点击类名能够跳转到另一个类文件依赖的就是android.iml
文件中的配置,但是默认生成的android.iml
文件中导入了太多不必要的代码,直接导入AS会导致indexing很长时间,我们可以精简一部分,比如测试类的文件,它们在android.iml
文件中都有这么一个特征,以isTestSource="true"/>
结尾,所以,我们可以用VSCode打开android.iml
文件,然后用VSCode的文本替换功能把以isTestSource="true"/>
结尾的行替换成空格,所有被替换的文件都不会导入AS,加快了indexing速度。
因为以isTestSource="true"/>
结尾的行太多了,我们不可能一行行的删,怎么办呢?使用正则表达式匹配这些行。
我们使用VSCode的文本替换功能,然后在匹配栏输入
(前提把匹配栏切换成支持正则表达式),这时候你会发现所有匹配上的行都高亮显示了,然后在替换栏输入空格,点击替换按钮就会一键替换完成,然后保存。
导入源码
我们在AOSP源码目录下找到上面生成的android.ipr
文件,然后鼠标右键选择“打开方式”,找到Android Studio,然后打开,如果遇到convert
一类的提示,千万不要convert
,因为convert
之后,你的android.iml
文件标签中的属性会发生变化,导致的结果就是Source Folders
识别不出你导入了哪些文件夹。
然后就等待吧,直到AS indexing完成...
接下来,我们需要看看源码有没有导入成功,怎么判断成没成功呢?
我们打开AS上的Project Structure
按钮,如图:
然后出现下面这个界面:
在Source Folders
里面出现了很多类似于上图中的蓝色路径,那恭喜你,源码导入成功了(由于导入的源码太多,你可能在打开上述页面时会非常卡顿)。
导入源码成功之后,我们就需要一些配置才能更方便的阅读源码和调试。
第一步:配置一个Module SDK
,如下图。
我们在Project Structure
页面中点开SDKs
,然后点击+
号添加一个名为1.8 (No Libraries)
的SDK,JDK home path
可以选择Android Studio自带的JDK home目录,也可以选择Mac上已安装的JDK home目录,无所谓,最重要的一点来了,就是要把上图中的Classpath
和Sourcepath
中的依赖删除干净,一个不留,这里说一下Classpath
和Sourcepath
的意义:
Classpath
:表示项目依赖的类,一般是jar包;
Sourcepath
:表示依赖的这些类的源代码目录,如果没有设置Sourcepath
,我们在项目中跳转到这些依赖的类时,看到的是字节码文件反编译后的Java代码,没有任何的代码注释,但设置了Sourcepath
,就是跳转到Sourcepath
中的源代码,是有注释的,一般Classpath
中的jar包是由Sourcepath
中的源代码打成jar包得来的。
第二步:配好了Module SDK
后,我们需要把它引用到AOSP源码中。
我们在Project Structure
界面点击Modules
,然后在1
处选择我们刚刚配置的1.8 (No Libraries)
sdk,然后2
处就有了这个sdk的引用,你会发现这个引用是没有-
删除按钮的,这就意味着你必须选择一个Module SDK
引用,但是AOSP源码中的所有代码都比较完全,没有必要去引用其他的依赖,所以我们前面配置了一个没有任何依赖的Module SDK
供源码引用(删除了所有的Classpath
和Sourcepath
中的依赖)。
第三步:最后也是很重要的一步,没有这一步,看源码是没有问题的,但是想要调试就不行了。
还是在Project Structure
界面中点击Project
,然后画红框部分选择一个Android SDK,最好是和AOSP源码版本对应的SDK。
最后,点击Apply
和OK
,完成设置,等待一会indexing后就可以愉快的看源码了。