Ubuntu 下编译AOSP源码

前言

AOSP是谷歌维护的一个开源项目,它包含了Android系统的源码和功能。

狭义的Android系统是谷歌的一个商标,除了包括asop的源码部分,还包括手机处理器、摄像头等硬件所需的固件等内核设备驱动,以及要谷歌移动服务(GSM、如Chrome、Google Play等等。其他第三方厂商在AOSP的基础上构建出自己的RoM,获得Android商标的授权后也可以标注Android的字样。

编译完AOSP后,可以导入Android studio进行阅读学习、修改和调试。谷歌提供了的nexus和pixel手机的硬件驱动代码,它们是使用AOSP作为原生系统,因此我们如果有nexus和pixel手机也可以对AOSP进行定制并刷到设备上。

编译配置要求
  • 16 GB 以上的内存,越大越好,这里是指构建过程的可用内存, Google 建议提供 64 GB。
  • 400G以上可用磁盘空间。代码占150-200GB,构建产物占150多G,重复构建占用更多
  • Ubuntu 18.04 以上,64位。官方现已不再支持在 Windows 或 MacOS 上进行构建。

以下以获取android-13.0.0_r44源码为例:

1 搭建编译环境

1.1 检查JDK环境

在Ubuntu请使用OpenJDK,如果是AOSP的master分支会自带OpenJDK,其他版本需要自行安装

# 检查jdk版本,如果提示找不到命令 “java”字样说明未安装
java -version

# 安装jdk
sudo apt install openjdk-11-jdk

1.2 检查python环境

Ubuntu 自 16.04 版本已经默认预装python3,如果变异过程中报错`找不到命令 “python”,只需要建立一个python的链接即可。

# 通过软链接将python命令默认指向python3
sudo ln -s /usr/bin/python3 /usr/bin/python

# 查看 python 版本 
python --version

1.3 安装基础软件包

这条命令一次性安装了常用软件包例如git、curl、zip、unzip以及其他开发工具和库。

sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig

其中Git安装完还需配置一下用户信息,否则在使用repo拉取代码时会被拒绝。

# 配置Git的用户名
git config --global user.name "Your Name"
# 配置邮箱
git config --global user.email you@example.com

1.4 安装Repo

Repo是Google专门用来管理Android大型源码库的一个工具,比如AOSP项目。 简单说就是一个封装了Git命令的python脚本,用以简化跨多个Git仓库的代码管理和同步。通过 Repo,你可以在一个命令行中对所有仓库进行同步、检出特定的分支、以及执行其他 Git 操作。

# 安装repo
sudo apt install repo

# 查看repo版本(是否安装成功)
repo version

2 下载AOSP源码

Android 源代码树位于由 Google 托管的 Git 代码库中,因此我们可以通过Git(Repo)下载源码。

2.1 官方同步方式

这种方式对网络有一定要求,更推荐使用镜像站提供的初始化包的方式。

(1)初始化Repo并指定代码库地址 使用mkdir <dirName>命令或右键创建文件夹,作为AOSP的根目录。在该目录下打开终端,输入以下命令进行仓库的初始化,指定源和AOSP版本。

# 从Google下载Android13源码
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r44

# 从镜像站下载android-13.0.0_r44源码
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-13.0.0_r44

命令说明:repo init -u <url> -b <branch>会获取最新版本的 Repo 及其最新的 bug 修复。执行命令后创建一个 .repo/ 目录,其中包含存放 Repo 源代码和标准 Android 清单文件的 Git 代码库。其中可以通过-b 来指定相应分支,可以从谷歌使用文档-关于-源代码标记和build分类中,根据设备型号和Android版本号来选择标记(分支)。

如果谷歌服务器被墙,可以设置科学上网,或者从清华大学镜像站中科大镜像等镜像源中获取。

部分AOSP的标记和 build源码版本标记:

Build ID标记版本更新日期
TQ2A.230505.002.A1android-13.0.0_r44Android132023-05-05
9575282android-security-13.0.0_r3Android132022-08-05
SP1A.210812.016.A1android-12.0.0_r3Android122021-10-05
RQ1A.201205.008.A1android-11.0.0_r21Android11 P2020-12-05
6780337android-10.0.0_r47Android102019-09-05
6780336android-9.0.0_r61Pie2018-08-05
OPR5.170623.014android-8.0.0_r36Oreo2017-12-01
NRD91Dandroid-7.0.0_r7Nougat2016-10-05
MRA59Bandroid-6.0.0_r7Marshmallow2015-12-01
LMY48Iandroid-5.1.1_r9Lollipop/

(2)同步源码到工作目录

# 默认命令
repo sync

# 只拉取当前分支且不拉取远程仓库的标签信息,设置同步任务数量为8
repo sync -c --no-tags -j8

命令说明:repo sync会将 Android 源代码树从默认清单中指定的代码库下载到工作目录。如过从未进行过这步操作,这相当于git clone

可选参数-c:只拉取当前分支,–no-tags 不拉取tags,-jthreadcount:指定同步任务数量,这些参数有助于加快同步速度。

Android源码非常大,需要同步很长的时间,如果同步过程中有出现某个地方卡顿了很久,可以使用Ctrl+Z来中断同步,重新执行 repo sync进行同步。

2.2 使用镜像站提供的初始化包(推荐)

首次同步的数据包特别大,从Google官方同步方式耗时较长且可能由于网络原因造成失败,可以使用一些镜像站提供的打包好的 AOSP压缩文件。例如清华大学镜像源提供的每月更新初始化包

1. 下载初始包

使用浏览器或者curl命令进行下载压缩包。文件大约60G,如果使用curl下载下来只有几k就结束了,大概是请求被禁止了,可以使用浏览器直接下载。

# 下载初始化包,-O:下载远程文件到本地,-C:断点续传
curl -OC - https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar

2. 提取文件 解包后得到的 AOSP 工程目录,里面有一个隐藏的 .repo 目录

# 提取文件,-x:解包,-v:显示过程,-f:指定文件
tar xvf aosp-latest.tar

3. 进入aosp目录再指定分支并同步

# 进入aosp目录
cd aosp

# 指定分支
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-13.0.0_r44

# 同步代码
repo sync -c --no-tags

当终端输出类似下面的信息表示同步完成。

Checking out: 100% (1317/1317), done in 47m8.048s
repo sync has finished successfully.

下载完成后的部分文件夹:

aosp
|-- art                # 与Android Runtime (ART) 相关的源代码
|-- bionic             # 包含C库(libc)以及其他与C运行时库相关的代码
|-- bootable           # 启动相关的代码,如bootloader、kernel等
|-- build              # 构建系统相关的代码,包括构建工具和构建规则(重要)
|-- dalvik             # 与Dalvik虚拟机相关的代码
|-- development        # 开发工具、库和样例代码
|-- device             # 设备特定的源代码,例如驱动程序和配置文件
|-- external           # Android系统使用的一些外部库和工具,如SQLite、libpng等
|-- frameworks         # Android应用框架的代码(重要)
|-- hardware           # 硬件抽象层 (HAL) 的实现,以及一些硬件相关的代码
|-- kernel             # Linux内核源代码
|-- packages           # 一些预装的应用程序和服务的源代码(重要)
|-- prebuilts          # 一些预编译的二进制文件,如编译工具链等
|-- system             # Android系统的核心组件,如服务和系统应用
|-- vendor             # 设备制造商提供的特定设备的源代码和二进制文件

3 开始编译

3.1 设置环境

执行以下命令进行初始化环境。

# 执行该命令,envsetup.sh 脚本初始化环境
source build/envsetup.sh

envsetup.sh脚本位于aosp根目录/build/envsetup.sh,作用是设置环境变量和封装一些用于构建Android源码的函数。每次开始构建前请先执行一下这个脚本以便加载lunch等命令。

3.2 选择构建目标

使用lunch 命令选择要构建的目标(选择你的午餐)。

# 默认,从后续列表中选择构建目标,
lunch

命令说明:lunch product_name-build_variant,参数的product_name表示需要构建的设备型号,build_variant表示构建类型,共3种。 可以从从谷歌使用文档-构建-刷写设备-选择设备build分类下选择目标机型对应的build参数。

构建类型:

  • user: 用户版,权限受限;适用于生产环境。
  • userdebug:用户调试版,与“user”类似,但具有 root 权限和调试功能;是进行调试时的首选编译类型。
  • eng:工程版,具有额外调试工具的开发配置,适用于深度开发和调试

如果在没有参数的情况下运行,则 lunch 会提示您从菜单中选择目标,但是注意菜单中并未包含所有可能的选项。如果你打算跑在Android模拟器上可以选择带x86_64/x86标识的选项。

# 选择具体目标,例如这里选择x86_64 架构模拟器和用户调试版为构建目标
# lunch sdk_pc_x86_64-userdebug

3.3 构建代码

1. 全量编译 使用 make 命令从源代码树的顶部开始编译 Android 源代码。

m -j10     

-jN可选参数可以设置处理并行任务的数量。如果您没有提供-j参数,构建系统会自动选择您认为最适合您系统的并行任务计数,Google推荐执行源码编译的线程数=CPU核心数x2+2。

构建完成后会生成各种库文件、输出产物默认在out/target/product/<device>下,例如:

  • 各种库文件:libhardware.so、libssl.so 等
  • Java 类文件:framework.jar、core.jar 等
  • 系统映像文件:boot.img、system.img、recovery.img等,用于刷机将系统烧录到 Android 设备上。
/out/target/product/<device>/
|-- system.img           # Android系统的核心镜像文件,它包括系统库、框架、应用程序、资源文件和配置文件等
|-- boot.img             # 引导镜像文件,用于引导设备启动Android操作系统。它包含了Linux内核(Kernel)和用于启动Android系统的引导程序(Bootloader)
|-- vendor.img           # 厂商分区镜像文件,用于存储厂商定制的系统组件、驱动程序和特定的应用程序等。vendor.img通常由设备制造商提供,并在编译AOSP时与系统镜像一起构建
|-- ramdisk.img          # 根文件系统镜像
|-- userdata.img         # 用户数据镜像

2. 编译指定模块 如果只想编译某个模块,可以使用命令mmm <directory>,该命令只编译指定目录中的模块,而不是整个源代码树。

# 指定编译frameworks/base
mmm frameworks/base

3.4 其他命令

清除文件重新构建。

# 清除已生成的构建输出文件
make clean

# 清除构建缓存
make clobber

# 删除已构建的目标文件和生成的镜像
rm -rf out/

3.5 编译完成

编译过程耗时比较久,对CPU线程数和主频要求比较高,这里用E5-2678 v3(12核24线程)/64G内存大概跑了一个多小时。 当终端输出类似下面的日志说明构建完成。

#### make completed successfully (01:24:41 (hh:mm:ss)) ####

编译完成后,如果我们选择的目标是x86,可以使用模拟器来运行,由于已经使用 lunch 选择了构建目标,因此只能运行在我们选定的目标上。

# 构建流程会自动将模拟器添加到您的路径中,如需运行模拟器,请输入以下命令
emulator

此外我们还可以将源码导入Android studio进行阅读或者调试等操作。

4 阅读源码

如果需要将AOSP源码导入Android studio主要有以下3种方式:

4.1 平台版 Android Studio

Android Studio for Platform (ASfP)是 Android Studio针对Framework开发做的版本,添加了对AOSP项目相关的一些支持。不过目前仅支持 Ubuntu 系统。 可以从ASfP官网下载,目前官网简中网页打不开,可以使用英文或者繁中

# 1.从官网网页或执行以下命令下载安装包
wget https://googledownloads.cn/android/asfp/asfp-2023.1.1.19-linux.deb

# 2.令安装ASfP
sudo dpkg -i /path/to/asfp-2023.1.1.19-linux.deb

# 3.命令运行ASfP
/opt/android-studio-for-platform/bin/studio.sh

AIDEGen

AIDEGen是 Android 10 开始引入的为Android studio 等idea工具生成系统源码的project,它能自动配置Android Studio或IntelliJ项目文件,并解析相关模块依赖关系,不过也只支持Ubuntu。 AIDEGen需要运行在选定目标之后,即执行了source build/envsetup.sh && lunch之后。

# Settings:模块名称 -i:需要运行的ides:Android studio
# 编译完成会自动运行Android studio
aidegen Settings -i s

idegen

idegen 是 Android 源代码中的一个模块,专门用来为idea工具生成系统源码的project。这是最早提供的一种方式,不推荐。如果需要在Windows 下导入源码或者只关注AOSP的一部分源码,可以使用这种方式。 默认情况下AOSP编译并不会生成该文件,另外编译idegen模块不需要先进行全量编译,直接执行以下命令: 1. 生成ipr和iml文件

# 执行该命令后,将在out目录生成idegen.jar
mmm development/tools/idegen/ 

# 执行以下命令,会在源码目录生成android.ipr,android.iml及android.iws.
sudo ./development/tools/idegen/idegen.sh

其中ipr文件和iml文件是主要的IEDA工程配置文件:

  • android.ipr:Android Studio 项目文件的主配置文件,包含了项目的基本信息、模块、依赖项、构建设置等
  • android.iml:模块的配置信息,例如源代码目录、依赖项等
  • android.iws:存储工作空间(workspace)相关设置的文件,可省略。

2. 导入到Android Studio 如果只想关注framework层的源码,可以删除其他模块,只保留framework文件夹和packages文件夹以及idegen配置文件,这样可以大大减少源码体积。 将项目文件复制到Windows后,点击Android Studio->File->Open,选择刚才生成的android.ipr文件即可

排除模块

如果不想导入某些模块,可以修改android.iml文件中

<excludeFloder url="file://$MODULE_DIR$"/模块名>

5.刷机

如果我们谷歌系列的手机,可以将编译出来的AOSP镜像刷写到设备上。

5.1 下载驱动

AOSP只含有纯源代码部分,不包含行与硬件相关的其他专有库(驱动),如果编译AOSP是为了刷机并且拥有Pixel 系列的手机,则还需要下载 Google 的驱动程序。

  1. 下载驱动文件:在Google官网Nexus 和 Pixel 设备的驱动程序页面可以找设备对应的驱动压缩文件,注意驱动要和aosp build号对应。
  2. 解压文件:将驱动压缩包文件解压得到.sh文件并放到AOSP源码根目录,
# 解压
tar -zxvf FileName.tgz

# 解压后会生成以下两个文件
extract-google_devices-sailfish.sh
extract-qcom-sailfish.sh

  1. 使用bash运行这两个文件,浏览协议并同意后,执行后会创建vendor文件夹,其下包含驱动。
bash extract-google_devices-sailfish.sh
bash extract-qcom-sailfish.sh

5.2使用 fastboot 刷机

  1. 解锁BL和下载配置fastboot工具,可以在aosp目录下通过make fastboot命令编译出来,也可以直接从网上下载
  2. 设备确保解锁BL、打开开发者模式、连接上adb,进入BootLoader模式
  3. 进入编译后产生的镜像的目录…/aosp/out/target/product/,执行以下命令。刷完会自动重启,系统刷入完成。
# fastboot device 电脑能识别到设备
# -w 代表清除/data分区,删除所有用户数据
fastboot flashall -w

6 优化编译环境(可选)

1. 设置 ccache

视需要指示编译过程使用ccache编译工具,ccache是适用于C和C++的编译器缓存,有助于提高编译速度。这对于编译服务器和其他高容量生产环境来说尤其有用,如果您是在执行增量编译(例如个人开发者而非编译服务器),ccache 可能会让您为缓存未命中埋单,从而减慢您的编译速度。

设置步骤:

  1. 打开bashrc配置文件
gedit ~/.bashrc

  1. 在文件末尾添加以下内容: 其中<path_of_your_choice>是要设置ccache缓存的目录,如果不设置,则默认缓存到~/.ccache中。建议的缓存大小为 50G 到 100G。
export USE_CCACHE=1
export CCACHE_DIR=/<path_of_your_choice>/.ccache
prebuilts/misc/linux-x86/ccache/ccache -M 50G

  1. 使 .bashrc 更改立即生效
source ~/.bashrc

后续可以通过以下命令查看 ccache 的使用情况:

watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s

2. 自定义输出目录 默认情况下,每次编译的输出都会存储在相应源代码树的out/子目录下,自定义目录如果构建多个目标(不同手机型号等)时能够更清晰地区分各个目标的输出结果

  • OUT_DIR:如果需要构建多个目标(不同的手机型号或构建类型),修改这个路径可以为每个目标输出到独立的目录。

  • OUT_DIR_COMMON_BASE:多个构建目标的共享的基础路径,如果有多个物理磁盘,如果将源文件和输出存储在单独的物理磁盘中,构建速度会更快(虚拟机一般用不到)。

操作步骤,修改.bashrc或者每次编译时直接在终端输入以下命令:

# 修改存储输出目录的基础位置
export OUT_DIR_COMMON_BASE=<path-to-your-out-directory>

# 指定当前构建目标的输出目录
export OUT_DIR=<out_target_1>

7 报错

1.下载源码404无法连接 科学上网或者使用镜像地址

# 如果repo如果更新失败报错404,将repo的git源替换成清华的景象
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'


**2.python 编码格式错误**

File “/home/zhg/桌面/aosp/out/host/linux-x86/bin/protoc-gen-nanopb/nanopb_gene rator.py”, line 1841, in UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe6 in position 10: ordinal not in range(128) --nanopb_out: protoc-gen-nanopb: Plugin failed with status code 1. 21:34:42 ninja failed with: exit status 1

failed to build some targets (06:30:15 (hh:mm:ss))
解决方法:

vim ~/.bashrc

在末尾添加

export LANG=en_US.UTF-8 export LC_CTYPE=en_US.UTF-8 export LC_ALL=en_US.UTF-8

保存退出后

source ~/.bashrc

<!--
#### AOSP  似乎另外一个 git 进程在这个仓库中运行...
* 重复init了,删除git的记录文件 .repo-->

<!--#### ninja: unknown target 'j8', did you mean 'r8'

[ 97% 579/595] including system/sepolicy/Android.mk … system/sepolicy/Android.mk:57: warning: BOARD_PLAT_PUBLIC_SEPOLICY_DIR has been deprecated. Use SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS instead. system/sepolicy/Android.mk:62: warning: BOARD_PLAT_PRIVATE_SEPOLICY_DIR has been deprecated. Use SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS instead. FAILED: ninja: unknown target ‘j8’, did you mean ‘r8’? 14:39:36 ninja failed with: exit status 1

* 参数是带-的,m -j8
-->
**3.ca证书错误**

server certificate verification failed. CAfile: none CRLfile: none

 解决方法:添加证书或者忽略证书

export GIT_SSL_NO_VERIFY=1

**4.Python版本不兼容**

File “device/generic/goldfish/tools/mk_combined_img.py”, line 48 print “‘%s’ cannot be converted to int” % (line[2]) ^ SyntaxError: invalid syntax

或者

User SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(…)? ninja: build stopped: subcommand failed. 20:02:20 ninja failed with: exit status 1 make: *** [build/core/main.mk:21:run_soong_ui] 错误 1


解决方法:编译低版本的aosp可能需要Python2而不是Python3

安装Python2

sudo apt install python2

移除原来的Python符号链接

sudo unlink /usr/bin/python

将 /usr/bin/python 链接指向 Python 2

sudo ln -sf /usr/bin/python2 /usr/bin/python


**5. 执行idegen.sh 脚本报错**

Error: A JNI error has occurred, please check your installation and try again Exception in thread “main” java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 53.0), this version of the Java Runtime only recognizes class file versions up to 52.0

解决方法: jdk版本太低,idegen.jar的编译java版本是 version 53.0即java 9,需要升级openjdk版本

## 参考链接
[1] [Android Open Source Project](https://source.android.com/docs/setup/start/requirements?hl=zh-cn)

如果你看到了这里,觉得文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料


在这里插入图片描述
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值