AOSP

Posted on By ᵇᵒ

Prologue

由于 GFW 的原因,使用国内镜像下载更快,这里以清华镜像为例。

准备编译环境

在编译之前,需要先做一些 设置编译环境 之类的准备工作;由于当前使用 Mac OS,故需要做以下几步准备:

  1. Mac OS 默认的 APFS 卷(Volume)是不区分大小写、不加密的,而编译 AOSP 会对 case-sensitive 进行检查(因为不区分大小写会导致某些 Git 命令行为出现异常),所以编译 AOSP 必须基于区分大小写的卷上操作,否则会报如下错误:

     $make -j4
     Checking build tools versions...
     build/core/main.mk:90: ************************************************************
     build/core/main.mk:91: You are building on a case-insensitive filesystem.
     build/core/main.mk:92: Please move your source tree to a case-sensitive filesystem.
     build/core/main.mk:93: ************************************************************
     uild/core/main.mk:94: *** Case-insensitive filesystems not supported. Stop.
    

    有两种方式建立一个区分大小写(case-sensitive)的 APFS 卷:

    • 使用 hdiutil 指令的方式,可参考 官方指南 或者 StackOverFlow

    • macOS High Seirra 及其以上的系统版本可直接使用系统的磁盘工具(Disk Utility),在 container disk 里增加一个区分大小写的 APFS 卷(打开磁盘工具,选择 container disk,点击顶部的+)。

    推荐使用系统的磁盘工具,使用 hdiutil 指令的方式还需要考虑 convert、mount、unmount 等操作。
    case-sensitive 的卷建好后,后续的下载和编译都基于此卷进行操作。如果先下载,后建卷,然后移动下载的源码至新建的卷,会出现部分软链接文件依然指向移动前的源文件,导致无法编译。

    NOTE
    Mac 从终端进入另一个卷的方法:

     cd /Volumes/{卷名}
    

    所有的卷都存在于系统所在卷的 Volumes 目录下。

  2. 安装 Xcode 和 Command Line Tools

    编译过程中需要用到 Xcode 的开发者 SDK,如果没有安装 Xcode 则编译会报错 Could not find a supported mac sdk

     ninja: no work to do.
     [1/1] out/soong/.bootstrap/bin/soong_build out/soong/build.ninja
     FAILED: out/soong/build.ninja 
     out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
     internal error: Could not find a supported mac sdk: ["10.10" "10.11" "10.12" "10.13"]
     internal error: xcrun failed with: "exit status 1"
     internal error: xcrun failed with: "exit status 1"
     internal error: xcrun failed with: "exit status 1"
     internal error: xcrun failed with: "exit status 1"
     ninja: build stopped: subcommand failed.
     10:41:26 soong bootstrap failed with: exit status 1
    
     #### failed to build some targets (14 seconds) ####
    

    当然,没有安装 Xcode 只是的错误原因之一,出现这种错误也可能是 Xcode 对应的开发者 SDK 目录下没有编译支持的 SDK 版本。

     # 查看 Xcode 开发者 SDK 版本
     ls /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
    

    对于这种情况,有两种解决方案:

    • 下载 AOSP 编译支持的 Xcode 开发者 SDK,解压到 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ 目录。

    • 把 Xcode 当前的开发者 SDK 版本加入到 AOSP 编译支持的版本配置里:

        vim build/soong/cc/config/x86_darwin_host.go
      
        80         darwinSupportedSdkVersions = []string{
        81                 "10.10",
        82                 "10.11",
        83                 "10.12",
        84                 "10.13",
        85                 "10.14", // 支持列表添加 Xcode 开发者 SDK 10.14
        86         }
      

    NOTE
    从 App Store 上下载 Xcode 后,默认是不会安装 Command Line Tools 的,在 Xcode 缺少 Command Line Tools 的情况下编译 AOSP 同样会报 Could not find a supported mac sdk 错误。可在终端输入以下命令:xcode-select --install 进行安装,安装完成后再次执行该指令可检测是否安装成功,安装成功会显示 command line tools are already installed

  3. 设置文件描述符数量上限
    在 Mac OS 中,可同时打开的文件描述符的默认数量上限太低(可使用 ulimit -n 查看,一般默认是256),在高度并行的编译流程中,可能会超出此上限。要提高此上限,请将下列行添加到 ~/.bash_profile 中:

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

    修改完后不要忘记刷新生效: source .bash_profile 或者 . .bash_profile

下载 AOSP

  1. 安装 git 和 repo

     // https://source.android.com/source/downloading.html#installing-repo
     curl https://storage.googleapis.com/git-repo-downloads/repo > /usr/local/bin/repo
     chmod a+x /usr/local/bin/repo
    
  2. 创建 AOSP 源码存放文件夹(Mac OS 必须位于 case-sensitive 的卷上)

     mkdir AndroidPlatform
     cd AndroidPlatform
    
  3. 初始化 repo

     repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
    
  4. 切换分支:
    自行选择 manifests 列出来的分支,这里的 android-9.0.0_r35 是当前最新分支(根据分支命名规则),pull 操作可省略(刚创建的 manifests 所有分支代码都是最新的)。

     cd .repo/manifests
     git branch -a | cut -d / -f 3
     git checkout -b android-9.0.0_r35 origin/android-9.0.0_r35
     git pull --rebase
     cd ../..
    

    NOTE
    如果能事先确定 manifests 存在自己需要的分支,则可以合并第 3、4 步,直接使用如下命令(这里仍然以 origin/android-9.0.0_r35 分支为例):

     repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r35
    
    • 这种初始化方式的不同之处在于,manifests 里是 default 分支指向 origin/android-9.0.0_r35,而 3、4 步骤的 default 分支指向默认的 master 分支,新建的 android-9.0.0_r35 才指向 origin/android-9.0.0_r35 分支(可以使用 git branch -vv 查看分支指向情况)。

    • 查看可用的 manifests 分支列表,列表更新不是那么及时,实际 manifests 里可能会存在表里没有列出的新分支。

  5. 同步代码(清华的镜像服务器不要超过4线程)

     repo sync -j4
    
  6. 漫长的等待,几个小时(视网速而定),如果 sync 失败,再次执行步骤 5,继续 sync 会接着之前的进度。sync 成功后会有提示:Syncing work tree: 100% (xxx/xxx), done.

  7. 检查大小,同步完成后目前大概在 73G 左右,可以作为同步是否成功的一个大概判断。. 表示当前路径,可省略(无路径参数时默认为当前路径)。

     du -sh .
    

    NOTE
    由于 AOSP 工程过大,可以使用一些小技巧减少同步时间和空间:

    • repo init 使用 --depth=1 参数,省去同步历史记录。

    • repo sync 使用 -c 或者 --current-branch 参数,指定只抓取特定分支代码。

    加上优化参数后同步,空间占 50G 左右,减少了大约 23G;由于是下班后丢在公司下载的,没有统计时间,但是节省的时间百分比应该和空间大致差不多。

make m mm mmm 的区别

  1. make
    GNU 的 make 构建工具,用于解释 Makefile 规则。

  2. m mm mmm
    这三个指令其实是 build/envsetup.sh 脚本里定义的几个函数,只有执行过该 shell 脚本后才能生效:

     . build/envsetup.sh
    

    这三者的简单解释可以通过同样定义在该 shell 脚本里的函数 hmm 进行查看(详细解释还是得看三个函数对应实现的源码):

     hmm
    
    • m
      其实质就是 make 指令,只不过封装成从工程根部开始编译。更多用法可以查看帮助信息:m help

    • mm
      编译当前路径下的所有模块。

    • mmm
      编译指定路径下的所有模块

编译

  • 全编译

      . build/envsetup.sh
      lunch
      make -j8
    
  • 首次编译 idegen

      . build/envsetup.sh
      make idegen
    
  • 增量编译 idegen

      . build/envsetup.sh
      mmm development/tools/idegen/
    

    NOTE

    1. idegen 是用来生成针对 Eclipse 和 IntelliJ IDEA 的 Android 系统源代码工程配置文件的一个工具,它位于 Android 系统源代码工程目录的下列位置:development/tools/idegen/,更多详细信息可以参考该目录下的 README。
      对于 Android Studio 加载 AOSP 源码,只需要编译 idegen 即可,并不需要编译整个工程。

    2. 初次接触 AOSP,编译很难一次顺畅通过,过程中可能会多次遇上错误而中断,耐心搜索解决相应错误即可。

Android Studio 加载 AOSP

  1. 编译 idegen 成功后,运行 idegen.sh 便可生成 Android Studio 能够打开的工程文件 android.ipr 以及工程配置文件 android.iml:

     . development/tools/idegen/idegen.sh
    

    必须在 AOSP 源码根目录执行该指令,否则会报错,最后生成的两个文件也处于源码根目录下。

  2. 双击文件 android.ipr 便可自动关联打开 Android Studio 进行加载。
    android.ipr 包含了基本上 Android 源码里的所有模块,直接打开 android.ipr,会等待相当长时间的 scanning index。如果只是想调试 framework,没有必要加载其他模块。 android.iml 文件的excludeFolder就是用于配置不需要加载的模块,打开该文件 替换默认生成的 excludeFolder 配置为如下项(只保留了 framework 模块):

     <excludeFolder url="file://$MODULE_DIR$/./external"/>
     <excludeFolder url="file://$MODULE_DIR$/.repo"/>
     <excludeFolder url="file://$MODULE_DIR$/art"/>
     <excludeFolder url="file://$MODULE_DIR$/bionic"/>
     <excludeFolder url="file://$MODULE_DIR$/bootable"/>
     <excludeFolder url="file://$MODULE_DIR$/build"/>
     <excludeFolder url="file://$MODULE_DIR$/compatibility"/>
     <excludeFolder url="file://$MODULE_DIR$/cts"/>
     <excludeFolder url="file://$MODULE_DIR$/dalvik"/>
     <excludeFolder url="file://$MODULE_DIR$/developers"/>
     <excludeFolder url="file://$MODULE_DIR$/development"/>
     <excludeFolder url="file://$MODULE_DIR$/device"/>
     <excludeFolder url="file://$MODULE_DIR$/external"/>
     <excludeFolder url="file://$MODULE_DIR$/hardware"/>
     <excludeFolder url="file://$MODULE_DIR$/kernel"/>
     <excludeFolder url="file://$MODULE_DIR$/libcore"/>
     <excludeFolder url="file://$MODULE_DIR$/libnativehelper"/>
     <excludeFolder url="file://$MODULE_DIR$/out"/>
     <excludeFolder url="file://$MODULE_DIR$/packages"/>
     <excludeFolder url="file://$MODULE_DIR$/pdk"/>
     <excludeFolder url="file://$MODULE_DIR$/platform_testing"/>
     <excludeFolder url="file://$MODULE_DIR$/prebuilts"/>
     <excludeFolder url="file://$MODULE_DIR$/sdk"/>
     <excludeFolder url="file://$MODULE_DIR$/system"/>
     <excludeFolder url="file://$MODULE_DIR$/test"/>
     <excludeFolder url="file://$MODULE_DIR$/toolchain"/>
     <excludeFolder url="file://$MODULE_DIR$/tools"/>
    

    Android Studio 加载成功后,依然会显示 exclude 的模块,这是因为 IDE 默认勾选开启了 Show Excluded Files,在 show option menu 里取消勾选就可以隐藏掉。

Android Studio 调试 framework

Todo