随着移动端设备增量的放缓和市场上各行各业 App 的饱和,连笔者的手机都很久未安装过新 App,更不用提更换手机的频率。与此同时,移动开发也由上半场拼点子拼速度的快捷玩法,进入到下半场拼质量拼生态的高阶玩法。作为一名一线开发人员,大环境的走向与业务形态的发展虽由不得我们控制,但核心技术的掌握则是我们可以身体力行的( 笑~)。

AOSP 是 Android 系统的代码,囊括了 Andorid 系统的全部内容,从应用开发 Framework 层到 Android 虚拟机 ART/Dalvik 层再到 Linux 内核层,所有的疑惑都能在源码中找到答案,其源码的重要性不言而喻。本文作为系列的开篇,主要对 AOSP 的下载、编译过程进行阐述,同时记录下过程中遇到的问题及解决方案。

笔者的系统版本为 macOS 10.14.5,截止文章发布时仍是最新的操作系统,AOSP-android-9.0.0_r42 的源码加编译产物需要 200G 的磁盘空间,请提前预留好磁盘空间。若主机磁盘空间不足,可使用外置移动硬盘来解决。

编译后将近 200G

1. Xcode 的安装

Xcode 包含了编译过程所需的各种工具,如 git、clang、make 等,在编译之前,我们先处理好 Xcode 相关的问题。

截止到2019年6月,AOSP 仍不支持使用 Xcode 10 编译。虽可在 AOSP 配置文件增加 10.14 字段绕过该限制,但后续编译时仍会出现莫名其妙的错误。因此,建议直接使用 Xcode9.4 来避免此类问题。Xcode9.4 的下载地址为Apple Developer Download,登录苹果账号后选中 Xcode 9.4 条目即可看到下载按钮。

若之前已安装 Xcode10 或更高版本,建议在 Xcode9.4 下载成功后进行以下操作:

  1. 将原有 Xcode.app 更名为 Xcode10.app 或其他
  2. 解压缩 Xcode 9.4 对应的 Xcode.xip 文件,随后将解压缩出的 Xcode.app 移动至 /Applications 目录

Xcode 9.4 安装后,在终端内输入 clang -version 进行验证,若出现如下输入内容,则表示 Xcode 9.4 切换成功。

1
2
3
4
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

2. macOS 大小写敏感磁盘的创建

macOS 文件系统的默认类型是大小写不敏感,大部分人的 macOS 文件系统类型均为大小写不敏感,然而 AOSP 项目中的代码却对大小写敏感。因此在下载 AOSP 源码之前,需要先创建一个大小写敏感的磁盘区域,创建命令如下。

1
hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 200g -volname AOSP /PathTo/AOSP.dmg.sparseimage

其中,-size 200g 表示新建磁盘空间的最大容量为200g,-volname AOSP 表示磁盘挂载时的名称为 AOSP,/PathTo/AOSP.dmg.sparseimage 是新建磁盘空间文件的存放位置。磁盘空间创建后并不会立即占用200g,而是随着该磁盘空间内数据存储的增多而扩大。当磁盘空间不足时,可在磁盘未挂载的状态下采用如下命令对原有磁盘空间进行扩容

1
hdiutil resize -size 220g /PathTo/AOSP.dmg.sparseimage

为了方便后续的使用,建议在终端环境下增加挂载与卸载 AOSP 磁盘空间的指令。所需函数如下,将其添加到 .zshrc.bashrc 即可。

1
2
3
4
# 加载 AOSP 磁盘空间
mountAndroid() { hdiutil attach /PathTo/AOSP.dmg.sparseimage -mountpoint /Volumes/AOSP; }
# 卸载 AOSP 磁盘空间
umountAndroid() { hdiutil detach /Volumes/AOSP; }

添加成功后,在终端内输入 mountAndroidumountAndroid 即可快速挂载和卸载 AOSP 磁盘空间。

3. AOSP 源码下载

最新的 AOSP 的源码约35G,数据量较大,建议从国内镜像获取,本小节使用科大镜像源演示下载流程。

3.1 安装 repo

最新的 AOSP 项目下含有 700+ 个git仓库,若用 git-submodule,git-subtree 管理的话非常复杂,为此谷歌专门编写了 repo 工具,用来管理多个 git 仓库间的代码同步。 0. 在当前用户目录下创建 bin 目录

mkdir ~/bin

1. 下载 repo 到当前用户下的 bin 目录

curl -sSL  'https://gerrit-googlesource.proxy.ustclug.org/git-repo/+/master/repo?format=TEXT' |base64 -d > ~/bin/repo

2. 为 repo 赋予可执行权限

chmod a+x ~/bin/repo

3. 将 bin 目录注册到终端环境

# zsh
echo 'export PATH=~/bin:$PATH'>>~/.zshrc

3.2 下载 AOSP 源码

0. 初始化 AOSP 仓库清单

1
2
3
4
5
6
# 挂载 AOSP 磁盘空间
mountAndroid
# 进入 AOSP 磁盘空间
cd /Volumes/AOSP
# 初始化 AOSP 仓库清单
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-9.0.0_r42

首次使用 git ,需按提示填写 git.username 与 git.email 信息

执行以上命令,会将AOSP清单仓库拉取到/Volumes/AOSP/.repo目录下,其中的 manifest.xml是一个软链接,链接到/Volumes/AOSP/.repo/manifests/default.xml 文件,文件中存储的即为 AOSP当前分支下所有仓库的清单文件。

/Volumes/AOSP/manifest.xml清单文件内容

清单文件内容

清单中列出了 AOSP 当前分支所需的全部仓库,仓库以 project 条目的形式描述,其中 path 属性表示下载到本地后的文件目录,name 属性表示远程仓库的相对路径。

Manifest.git_config

/Volumes/AOSP/.repo/manifests/.git/config是一个指向/Volumes/AOSP/.repo/manifests.git/config文件的软链接,config 文件记录了 AOSP 清单仓库的基本信息。

# /Volumes/AOSP/.repo/manifests/.git/config
[core]
    repositoryformatversion = 0
    filemode = true
    precomposeunicode = true
[filter "lfs"]
    smudge = git-lfs smudge --skip -- %f
    process = git-lfs filter-process --skip
[remote "origin"]
    url = git://mirrors.ustc.edu.cn/aosp/platform/manifest
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "default"]
    remote = origin
    merge = refs/heads/android-9.0.0_r42

1. 下载 AOSP 代码

1
repo sync

执行此操作时,repo 先解析上一步得到的manifest.xml来获取仓库信息,然后对清单中的所有仓库依次执行类似 git clone (git://mirrors.ustc.edu.cn/aosp + $project.name) $project.path 类似的操作将 AOSP 源码同步到本地。

clone 过程又可分为 Fetching projects(下载 bare 仓库)与 Syncing work tree(解压到工作目录)两个阶段。

Fetching projects 阶段会将 AOSP 中的700+个仓库陆续拉取到本地,内容暂存在 /Volumes/AOSP/.repo/projects 与 /Volumes/AOSP/.repo/project-objects 目录下的 bare 仓库内,此阶段大约需要下载 35G 的数据。下载过程中在 /Volumes/AOSP 目录内看不到明显变化,可使用磁盘命令du -h -d 1来查看下载进度。

Syncing work tree阶段会将 /Volumes/AOSP/.repo 下 bare 仓库的内容逐个取出,并放置到 /Volumes/AOSP 目录中,解压所需的空间也在35G左右。此阶段同样可以使用du -h -d 1来查看解压进度。

4. 编译 AOSP

0. 加载编译环境变量

1
2
3
cd /Volumes/AOSP
# 设置 AOSP 编译所需的环境变量
source build/envsetup.sh

1. 设置编译对象

1
2
# 设置编译对象
lunch aosp_x86_64-eng

此处是将 aosp 编译为 x86 架构的 64 位版本,如需编译其他版本,可键入 lunch 后在列表中选择。 2. 开始编译

1
m -j16

-j16 表示开启16个作业来同时编译,此处的数字与 CPU 相关,一般可设置为 CPU 核心数量的 2-4 倍。

接下来便耐心等待,编译成功后会出现如下提示,笔者所使用的4核8线程处理器,完整编译一次大约需要三个半小时。编译产物最终存储在 /Volemes/ASOP/out 目录,大约105G。

1
2
3
4
5
6
7
8
Setting name!
partNum is 0
REALLY setting name!
Warning: The kernel may continue to use old or deleted partitions.
You should reboot or remove the drive.
The operation has completed successfully.

#### build completed successfully (03:35:23 (hh:mm:ss)) ####

5. 常见问题

  1. Could not find a supported mac sdk: [“10.10” “10.11” “10.12” “10.13”]

AOSP 暂只支持在 10.10-10.13 上编译,其本质是对 Xcode 编译套件 MacOS.sdk 的限定。若当前 /Application/Xcode 对应的版本为 Xcode 10,则会出现这个错误提示,因为 Xcode10 内置的 MacOS.sdk 为 10.14 。以往虽有魔改 AOSP 编译配置的方式,为其添加 “10.14” 来避免此错误。但因 Xcode10 的改动较大,不建议普通用户尝试魔改 AOSP 编译配置,最稳妥的方式还是参照步骤1中的描述进行操作。

  1. <IOKit/IOReturn.h> not found

与问题1一样,可通过步骤1 更换 Xcode 9.4 为默认 Xcode 解决。