这几天为了搞Android源码费了不少功夫,也遇到了不少坑,在此记录作为日后参考。Android源码的编译运行只支持Linux和Mac系统,至于Windows系统只能绕道了,或是在虚拟机上安装Linux系统也是可以的。本人的系统是macOS 10.12.3,Xcode的版本是7.1。

官方教程地址为:https://source.android.com/source/index.html

一、搭建Mac系统编译环境

1、创建大小写敏感的磁盘映像

Linux和friends系统是大小写敏感的,而Windows和Mac系统正好相反,大小写不敏感,也就是说相同目录下不能同时存在aa和AA两个文件。

但是Android是基于Linux的,所以为了能够在Mac上编译运行就必须先创建一个大小敏感的磁盘印象。

下载Android 6.0的源码大约需要50GB,编译后涨到70GB左右。当然,如果磁盘空间紧张,下载源码后,你可以手动将源码根目录下的.repo目录删除,这样大约可以节省35GB的空间。我建议最好80GB空间以上,因为我的磁盘空间比较大,就直接设置为100GB。

  • 使用磁盘工具创建

打开应用程序中的磁盘工具—>文件—>新建映像—>空白映像—>设置名称、大小、格式则必须选择Mac OS扩展(区分大小写,日志式),储存后,双击储存位置的磁盘名.dmg即可挂载该硬盘。

  • 使用命令行创建

创建磁盘空间:

hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 100g ~/android.dmg

在当前的目录下会生成android.dmg.sparseimage文件,一旦挂载上,就是一个Android开发所需要的文件系统格式的磁盘。当然你也可调整磁盘空间的大小,可以使用下面的命令:

hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage

挂载磁盘映像:
当磁盘空间创建后,需要挂载才能使用,可以通过如下的命令进行挂载:

# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg.sparseimage -mountpoint /Volumes/android; }

取消挂载命令:

# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }

你可以把上面的两个命令添加到~/.bash_profile文件中,就可以直接通过mountAndroid和umountAndroid命令进行挂载和卸载。

一旦挂载后,你就可以看见在/Volumes/中挂载了一个叫android的磁盘。

2、安装JDK和Xcode

编译不同版本的Android源码所需要的软件支持也不一样:

GNU/Linux系统

  • Android 6.0 (Marshmallow) - AOSP master: Ubuntu 14.04 (Trusty)
  • Android 2.3.x (Gingerbread) - Android 5.x (Lollipop): Ubuntu 12.04 (Precise)
  • Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Ubuntu 10.04 (Lucid)

Mac OS (Intel/x86)系统

  • Android 6.0 (Marshmallow) - AOSP master: Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
  • Android 5.x (Lollipop): Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
  • Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat): Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple’s Developer Tools)
  • Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich): Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK

Java Development Kit (JDK)

具体可以参考官网文档:https://source.android.com/source/requirements.html,因为本人编译的是Android 6.0而且是MacOS 10.12系统,所以安装了JDK7和Xcode7.1。至于如何安装,网上教程很多这里就不再叙述。

3、安装MacPort

MacPort一款方便在Shell模式下进行下载、安装、编译、更新的软件,下载地址。安装完成后,请确保环境变量中/opt/local/bin是否在/usr/bin之前,如果没有请在~/.bash_profile文件中进行设置:

export PATH=/opt/local/bin:$PATH

4、设置文件同时打开数量

在Mac中,默认的文件同时打开数实在太低,一个高速并行的编译进程运行时可能会遇到瓶颈。为了增加最大文件打开数量,在~/.bash_profile中添加如下:

# set the number of open files to be 1024
ulimit -S -n 1024

二、下载Android源码

由于墙的原因,直接去google官方下载会很慢,这里推荐用中科大镜像

1、下载repo工具

# 在用户目录创建一个bin文件夹
mkdir ~/bin
# 将该目录临时添加进环境变量
PATH=~/bin:$PATH
# 从镜像下载repo工具
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
## 如果上述 URL 不可访问,可以用下面的:
## curl https://storage-googleapis.proxy.ustclug.org/git-repo-downloads/repo > ~/bin/repo
# 给repo添加执行权限
chmod a+x ~/bin/repo

为了~/bin下面的命令以后可以直接访问,我把~/bin这个目录配置一下环境变量,在.bash_profile文件中添加如下,放在刚刚配置的MacPort之后:

export PATH="/opt/local/bin:/opt/local/sbin:~/bin:$PATH"

修改完毕后,为了让配置立即生效,输入:

source .bash_profile

2、初始化仓库

在之前所创建的大小写敏感磁盘中创建存储源码的目录:

mkdir aosp
cd aosp

进入该目录,然后执行下面的命名进行仓库的初始化:

repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest
## 如果提示无法连接到 gerrit.googlesource.com,可以编辑 ~/bin/repo,把 REPO_URL 一行替换成下面的:
## REPO_URL = 'https://gerrit-googlesource.proxy.ustclug.org/git-repo'

默认是master分支,如果需要某个特定的 Android 版本,请用如下的命令,-b 表示分支的切换:(Android版本列表,需翻墙)

repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-6.0.1_r30

因为本人要编译的是Android 6.0系统,所以这里选择的是android-6.0.1_r30分支。注意,列表中每个分支后都有所支持的设备类型,如果要烧录到真机时,就要特别注意。

3、下载源码

同步源码树(以后只需执行这条命令来同步):

repo sync

注意,由于硬盘 I/O 资源有限,Git 服务器每 IP 限制 5 个并发连接。repo sync 命令默认使用 4 个并发连接,请勿使用 -j 参数增加并发连接数。

输入上面的命令后就开始真正的下载源码了,Android 6.0下载后的大小大概50GB左右。如果为了节约空间的话,那么可以删除下载好的源代码目录下的.repo文件夹,但是这样就失去了同步的能力。

三、编译Android源码

源码下载后,我们就可以进行Android源码的编译了。

1、准备编译环境

用envsetup.sh(它在源代码根目录/build下面)脚本初始化环境,注意后面的lunch命令等都跟这一步有没有执行有关。如果没有执行后面会提示找不到lunch命令:

source build/envsetup.sh

在编译新版本之前请清理之前编译过的文件,因为之前编译过的文件有可能对要编译的版本造成不可预知的影响,所以先执行下面的命令进行清理:

make clobber

2、选择编译目标

用lunch命令选择编译目标,后面跟上目标参数,比如我编译的是适用于模拟器的完整可调试版本:

lunch aosp_arm-eng

后面所携带的参数可以分为两部分:BUILD-BUILDTYPE。

  • BUILD也就是aosp_arm,代表一个特定的功能组合代号,一般是来表示版本所适配的硬件的,比如模拟器的是aosp-arm,烧录到Nexus6上的是aosp_shamu,更多关于真机代号和刷入,可以参考 Running Builds
  • BUILDTYPE也就是eng是构建类型的意思,主要是决定了你编译出的系统的权限,有以下三种:
BUILDTYPE作用
user有限的访问权限,适合生产环境
userdebug和user类似,但是具有root和debug权限,适合调试
eng有一些额外的调试和debug工具

3、开始编译

最后我们执行下面的命令就可以开始编译了:

make -j4

数字4表示并行地处理数,它一般设置为CPU线程数的1~2倍进行编译,大家可以根据自己机器性能进行调整。例如一个dual-E5520机器上(2个CPU,每个CPU 4核,每个核2线程),那最快的编译速度就在make -j16到make -j32之间。因为本人机子CPU的内核是8核的,所以开16个线程加快编译。

开始编译时,会先输出该编译版本的信息列表:

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=6.0.1
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=darwin
HOST_OS_EXTRA=Darwin-16.4.0-x86_64-i386-64bit
HOST_BUILD_TYPE=release
BUILD_ID=MOB30D
OUT_DIR=out
============================================

通过列表可以确认我们要编译的版本号和编译目标。

在开始编译后,会遇到各种异常而中止编译。编译错误后再次输入make -j4后可以重新编译,前面编译过的模块不会重复进行编译,正因为这个原因,当我们希望从零开始进行编译的话,要先执行make clobber命令来清除临时文件。不过我建议每当编译错误解决后,最好都从头开始进行编译,以免不可预知的错误发生。

编译的速度跟机子的性能有关,本人的机子整个编译过程持续了将近1个小时,如果编译成功会有类似如下的信息输出:

\e[0;32m#### make completed successfully (52:51 (mm:ss)) ####\e[00m

所有编译的文件都会在out目录下生成,整个out文件占据了20GB左右,加上源码的50GB,现在整个磁盘占了70GB左右大小的容量。这里就知道了为啥我刚开始建议设置80GB以上磁盘的原因了吧。

4、运行源码

编译成功了,我们就可以让源码在模拟器或设备上运行了。请注意之前用lunch设置的特定设备,已编译的设备版本只能在该设备上运行。

  • 模拟器:
    如果在选择编译目标那一步选择的是lunch aosp_arm-eng.那么这时候就可以直接输入emulator命令来运行模拟器了(emulator命令在编译过程中会自动添加到Path路径下)
    Shell emulator

  • 刷机
    因为本人刷的是模拟器,想了解刷入真机这块的可以参考Flashing a device(翻墙)

展示一下成功在模拟器上运行的截图:
QQ20170305-002002.png-159.4kB

5、编译问题总汇

在Mac上编译Android源码遇到了一些坑,这些问题。

问题一

Xcode版本的问题,你会收到如下错误提示:

Can not find SDK 10.6 at /Developer/SDKs/MacOSX10.6.sdk

具体错误的原因是,在编译脚本中会检查当前的Xcode sdk的版本是否是兼容的,这可能是因为你mac上的Xcode版本比较新。打开/Volumes/android/asop/build/core/combo/mac_version.mk文件,可以查看源码所以支持的mac sdk版本:

mac_sdk_versions_supported :=  10.6 10.7 10.8 10.9

在应用程序里打开XCode.app的包内容,进入/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs。在该目录下,我这里只有MacOSX10.11.sdk目录,也就说当前Xcode的sdk版本是10.11,很明显都不在上述支持的列表中。怎么办? 直接在末尾加上当前的sdk版本呗:

mac_sdk_versions_supported :=  10.6 10.7 10.8 10.9 10.11

OK,添加后果然再重新编译,就没有上面的问题发生了。

问题二

解决上面的问题后,果然一直欢快的编译下去了。可是为啥编译那么久,为什么最终花了2个小时,而且最后还编译失败了? 为毛跟别人的博客不一样。最终发现我指定的并发进程数太高了:

make -j32

指定默认值、8、或16都能编译得过,但是唯独32不行。参数的值和机子性能有关,机子性能差的还是乖乖使用默认值吧。

本人在编译和运行过程只发现这两个问题,不像别人的博客中那么多的问题,可能跟编译的版本高有关吧。

四、导入Android Studio

请确保源码已经被编译生成了out相关目录文件,并成功的在运行起来。接下来就可以把源码导入到as中了。

1、编译idegen

cd aosp 进入源码根目录,我们通过如下命令编译idegen模块:

source build/envsetup.sh // 将执行文件设置为临时变量
mmm development/tools/idegen/  //生成idegen.jar文件

这行命令的意思是编译idegen这个模块项目,然后生成idegen.jar文件,该文件的路径一般在/Volumes/android/asop/out/host/darwin-x86/framework/idegen.jar

果看到如下信息则说明编译OK:

#### make completed successfully (4 seconds) ####

接着执行如下脚本,生成IDE项目文件:

development/tools/idegen/idegen.sh

执行成功后在asop的根目录下生成android.ipr,android.iws和android.iml三个文件:

  • android.iws 包含工作区的个人设置,比如打开过的文件,版本控制工具的配置,本地修改历史,运行和debug的配置等。
  • android.ipr 一般保存了工程相关的设置,比如modules和modules libraries的路径,编译器配置,入口点等。
  • android.iml 用来描述modules。它包括modules路径、 依赖关系,顺序设置等。一个项目可以包含多个 *.iml 文件。

通过如上操作我们就完成了基本的源码配置工作。

2、优化AS内存

因为源码非常多,所以导入时IDEA/AS会需要大量内存。所以我们需要编辑IDE的VM选项,通过Help-Edit Custom VM Options即可直接编辑。请根据自己机子的实际情况进行设置,因为本人内存比较大,所以直接上4GB:

-Xms2048m
-Xmx4096m
-XX:MaxPermSize=2048m
-XX:ReservedCodeCacheSize=1024m
-XX:+UseCompressedOops

3、导入AS

很多博客说可以修改iml来减少导入库的量,可以加速导入速度,但是我不知道哪个库有用哪个没用,而且本人的机子性能贼好,所以就没有进行修改android.iml文件的操作了。

接下来直接双击android.ipr或通过AS的Open an existing Android Studio project选项选择android.ipr 就可以直接打开源码了。

整个源码的导入花了差不多10分钟左右,主要跟机子性能有关,导入后工程目录样式切换为Project,到目前为止我们就可以方便的使用Android Studio查看源码:
QQ20170305-122250.png-217.7kB

4、配置AS的JDK、SDK

为当前工程设置正确的SDK和JDK,工程右键-Open Module Settings—SDKs,比如我编译的是6.0源码,所示设置的SKD是23,JDK为8。不过这里JDK设置方式与以往的不一样,因为下载的aosp源码中已经包含了用到的所有jdk文件,所以不需要依赖我们安装的JDK:

左上角“+”号新建JDK — 取个名字叫1.8(No Libraries):
image_1baebodkr1vbc1n253uc1ji11c5j9.png-35.2kB

设置sdk依赖新建的” 1.8(No Libraries)”
image_1baebqdpgooaj0f1otgk7qpgg13.png-113.8kB

删除1.8(No Libraries)的Classpath和Sourcepath下的所有东西(右边“-”号删除)
image_1baebt5a64o1tputpq18auscv1g.png-77kB

之后在Project标签中的Project SDK中选择对应的Android API版本:image_1baebvctauap1jhhpmu80u79h1t.png-180.7kB

设置后,在源码中跳转的JDK版本不再是系统自带的JKD版本了,而是源码中的JDK了。

5、解决源码中跳转错误问题

解决代码调试时跳转到.class文件而非源码中的.java文件:这时候你打开一个Handler.java类,你会发现它跳转的是你的默认SDK中的jar内部的class文件。既然要修改查看整套源码,这么跳转得多蛋疼啊,所以我们需要配置让其能跳转到源码中的java文件:

打开Project Structure—Modules—Dependencies,让所有的jar包置于这两个下面:
image_1baecm80o1dv6t161hap12501aoa2a.png-332.4kB

大部分博客都说删除其他的依赖,只剩下上图中的前两个,但是我这么做后,源码文件打开会看到一片红,R文件找不到等等,所以我的做法是不删除任何jar包,直接把和API Platform移动到其他jar包之前,让studio先从源码文件夹找.java文件。

这时候我们再试试跳转就可以直接跳转到源码中的Handler.java文件了,可是这时你会发现Handler类下发出了如下的警告:
image_1baecthnb3q217c41inalv110412n.png-48.2kB
原来编译后的out文件下也会生成Handler.java文件,那么我们直接把out/target/common/obj目录,右键Mark Directory as->Excluded,把out下编译后生成的文件排除在工程外就可以了。

6、R文件无法跳转

虽然经过前边的设置,我们解决了代码跳转的问题(不再跳转至反编译的代码文件了),但是你会在代码窗口的右边栏发现红色的错误提示 - R文件无法找到。比如Activity中的com.android.internal.R.attr.state_focused

aosp默认生成的android.ipr文件并没有将R文件导入到项目中,所以才会出现这个问题。我们可以手动地将R文件添加到项目的依赖库中:

打开项目的Dependencies,将目录aosp/out/target/common/R以JARs or dictionaries的方式添加进去,默认会起名为Empty library。

还有一种解决R文件无法跳转的方法,请详见这里

设定好之后,你会发现R文件仍然无法被识别,这时你打开com.android.internal.R文件,看到编译器发出了如下的警告:
QQ20170304-174529.png-97.9kB

IDEA(Android Studio是基于IDEA开发的)默认限制了打开文件的最大尺寸为2500K,我们可以将其改大一点,以满足实际的需求。

配置文件的地址为AndroidStudio-root/bin/idea.properties,将下面的这一行

idea.max.intellisense.filesize=2500

替换为

idea.max.intellisense.filesize=5000

具体的数字根据你自己的需要来定,我这里设定为5000,即5000K。

7、版本控制

如果你想知道每段代码提交的意义的话,我们可以把源码添加到版本控制中:Preferences–Version Control->全选并点击+添加:
image_1baee4cnf4hdob915gu1jtf11nb3g.png-171.9kB

五、调试源码

要让Android源码可以调试,那就必须让Android studio把当前工程看成Android工程:
image_1baee93ber6o1td53q51c9qjcd3t.png-60.2kB

然后在代码中加断点,然后直接点击下图所示的图标

image_1baeehalm1ajksaanovu3t3f14n.png-50.1kB

注意,添加为Android工程后,工具栏中才会有上面的图标出现。在弹出的选择进程(Choose Process)对话框中,勾选显示所有进程,选择要DEBUG的代码所在的进程,点击OK即可(可同时debug多个进程)。

参考:

中科大镜像AOSP镜像

MacOS X 下载编译Android 4.4.4源码(上)
MacOS X 下载编译Android 4.4.4源码(下)
陈哈哈-Mac下设置Android源代码编译环境
陈哈哈-国内不翻墙下载Android 源代码
陈哈哈-编译Android AOSP代码
陈哈哈-Android编译过程中的碎碎念
Mac 10.10 编译android 4.4.4 for nexus
在macOS 10.12 上编译 Android 5.1

Android Studio系列(二)使用AS开发/调试整个android系统源代码(不定时更新)
如何使用Android Studio开发/调试Android源码
下载AOSP android源码(最小最快下载方式,跳过编译直接导入Android Studio) Ubuntu 16.04
使用Android Studio导入源码
Android源代码(AOSP)调试 - Java部分

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐