实战案例:从零开始编译 AOSP、添加新硬件支持、定制系统应用
说实话,很多初学者看到 AOSP 这三个字母就头大。我当年第一次编译 AOSP 时,也踩了不少坑。但你别怕,今天我就带你走一遍完整的流程——从拉代码到烧录,从添加硬件 HAL 到定制系统应用。
这一章,咱们不聊虚的。直接上手干。
1. 环境准备与源码下载
先说说环境。我建议你用 Ubuntu 20.04 LTS,这是目前最稳的选择。你想想看,Google 官方文档里推荐的也是这个版本。
硬件方面,至少 16GB 内存,250GB 以上硬盘。我吃过亏,用 8GB 内存编译到一半直接 OOM 了,白等两小时。
核心依赖安装:
sudo apt-get update
sudo apt-get install -y git-core gnupg flex bison build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev \
lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig
嗯,这里要注意。如果你用的是 Ubuntu 22.04,需要额外装 python2。因为 AOSP 的老版本构建系统还依赖它。
源码下载我推荐用清华的镜像站,速度快很多:
mkdir ~/aosp
cd ~/aosp
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-13.0.0_r41
repo sync -j4 -c
-j4 表示 4 个线程并行下载。我一般设成 CPU 核心数的一半,不然网络容易卡死。
2. 编译 AOSP 核心系统
源码拉下来后,先别急着改东西。咱们先编译一次原版,确保环境没问题。
source build/envsetup.sh
lunch aosp_arm64-eng
make -j8
这里 lunch 选的是 aosp_arm64-eng,意思是针对 ARM64 架构的工程版。为什么选 eng?因为 eng 版本带 root 权限和调试工具,开发阶段最方便。
我第一次编译时,等了大概 3 小时。中间还报了个错,原因是 Java 版本不对。AOSP 13 要求 OpenJDK 11,我装的是 17。
避坑指南: 我曾经因为没装 libncurses5 导致编译到 90% 突然报错。建议你先把所有依赖装全,别偷懒。
编译成功后,你会看到类似这样的输出:
#### build completed successfully (02:58:32 (hh:mm:ss)) ####
看到这个,说明你的环境没问题了。接下来,咱们开始动真格的。
3. 添加新硬件支持(HAL 层)
假设我们要添加一个虚拟的传感器——"温度传感器"。说白了,就是让系统能读取一个虚拟的温度值。
首先,创建 HAL 接口定义:
mkdir -p hardware/interfaces/temperature/1.0/default
然后写 ITemperature.hal:
package android.hardware.temperature@1.0;
interface ITemperature {
getTemperature() generates (float value);
};
接着用 hidl-gen 工具生成 C++ 代码。我个人习惯写个脚本来自动化这步:
#!/bin/bash
PACKAGE=android.hardware.temperature@1.0
LOC=hardware/interfaces/temperature/1.0/default
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport $PACKAGE
生成的 Temperature.cpp 里,实现核心方法:
Return<float> Temperature::getTemperature() {
// 模拟读取硬件温度
return 36.5;
}
最后注册服务。在 default/service.cpp 里加上:
int main() {
android::sp<ITemperature> service = new Temperature();
registerAsService("default");
return 0;
}
嗯,这里要注意。注册服务名要和 manifest.xml 里的一致,不然系统找不到你的 HAL。
4. 定制系统应用
硬件支持加好了,咱们再写个系统应用来读取温度值。
在 packages/apps/ 下创建 TemperatureMonitor 目录:
mkdir -p packages/apps/TemperatureMonitor/src/com/example/temperature
核心代码 MainActivity.java:
public class MainActivity extends Activity {
private ITemperature mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
mService = ITemperature.getService();
float temp = mService.getTemperature();
TextView tv = findViewById(R.id.temp_value);
tv.setText("当前温度: " + temp + "°C");
} catch (Exception e) {
Log.e("TempMonitor", "获取温度失败", e);
}
}
}
别忘了在 Android.mk 里声明它是系统应用:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TemperatureMonitor
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := TemperatureMonitor
LOCAL_PRIVILEGED_MODULE := true
include $(BUILD_PACKAGE)
LOCAL_PRIVILEGED_MODULE := true 这行很关键。不加的话,你的应用拿不到系统权限,调用不了 HAL。
5. 重新编译与烧录
改完代码后,重新编译:
source build/envsetup.sh
lunch aosp_arm64-eng
make -j8
这次编译会快很多,因为只编译改动的部分。我实测大概 20 分钟就能搞定。
编译完成后,生成镜像文件:
make -j8 systemimage
烧录到设备:
adb reboot bootloader
fastboot flash system out/target/product/generic_arm64/system.img
fastboot reboot
如果你用的是模拟器,直接:
emulator -writable-system
然后 adb remount 把新镜像推上去。
6. 验证与调试
设备启动后,打开 TemperatureMonitor 应用。如果一切正常,你会看到 "当前温度: 36.5°C"。
如果没显示,别慌。先检查 HAL 服务有没有注册成功:
adb shell lshal | grep temperature
如果没输出,说明 HAL 没跑起来。我曾经遇到过这个问题,原因是 manifest.xml 里忘了声明 transport 类型。
调试小技巧: 用 adb logcat -s TemperatureMonitor 只看你的应用日志。别被系统其他日志淹没了。
还有一个常见问题——SELinux 权限。如果 HAL 调用被拒绝,看 dmesg 里有没有 avc: denied 的日志。有的话,需要加对应的 SELinux policy。
7. 知识体系总览
下面这张图,帮你理清整个流程的脉络:
说白了,整个流程就是一个闭环。从环境搭建开始,到验证结束。中间任何一步出问题,都要回溯到上一步去排查。
我个人觉得,最难的部分其实是 HAL 层的注册。很多初学者在这里卡住,因为 manifest.xml、service.cpp、Android.bp 三个文件要配合好,少一个都不行。
好了,这一章的内容就到这。你跟着走一遍,应该就能跑通整个流程。下次遇到类似的需求,直接复用这套框架就行。
公众号:蓝海资料掘金营,微信deep3321