Android AOSP 定制常见概念:源码目录、系统镜像与刷机流程

刚接触 Android 系统定制时,最难的往往不是改代码,而是听懂同事说的话:"去 device 里看产品配置""这个 APK 落在 product 分区""刷 vendor_boot 试试""先确认是不是 A/B 设备"。这些词跨越了源码、构建、设备分区和启动流程四个层面,名字还经常相似。

本文把它们放到一张地图里。文中的 "ASOP" 按常见写法应为 AOSP(Android Open Source Project)。下文以现代 Android 设备为主;具体目录、镜像和刷写方式始终以目标设备的源码、分区表及厂商文档为准。

一、先记住四层:源码目录 ≠ 镜像文件 ≠ 设备分区

text 复制代码
源码树                    构建配置与工具                 编译输出                     设备
frameworks/               device/、vendor/             out/target/product/...       system 分区
packages/          ──→    Android.bp、*.mk     ──→     system.img、vendor.img  ──→ vendor 分区
system/                   Soong / Make / Ninja          boot.img、super.img         boot / super 等

例如 packages/apps/Settings/ 是源码目录;编译得到 Settings APK;构建系统依据产品配置把它安装到某个镜像的文件树;刷机或 OTA 再把镜像内容带到设备上。源码目录的名字不自动决定最终落在哪个分区。

以后遇到一个陌生路径,先问它属于哪层:是源码、构建脚本、out/ 下的临时安装目录,还是设备运行时的挂载路径?这个问题能省掉很多无效搜索。

二、AOSP、Repo、Product:先选"编什么设备"

AOSP 与厂商 BSP

AOSP 是 Android 的开源基础,包含 Framework、系统服务、应用、构建系统及大量通用代码。能编出某个 Android 版本,不等于它直接支持任意手机。具体设备通常还需要厂商提供的 BSP(Board Support Package,板级支持包)、内核、设备树、驱动、HAL 实现和专有二进制文件。

一个商业设备的代码常见组成是:

text 复制代码
AOSP 通用代码 + 芯片平台代码 + 设备配置 + 厂商私有组件 + 产品定制

因此,拿公开 AOSP 源码直接刷到陌生量产手机,通常既无法启动,也可能破坏现有系统。开发时要使用与设备型号、硬件版本及对应分支匹配的源码和镜像。

Repo、Manifest、Git 仓库

AOSP 由许多 Git 仓库组成,Repo 负责按 Manifest 清单把它们组织成一棵源码树。Manifest 描述仓库 URL、路径与修订版本;repo sync 同步的是一组仓库,而不是一个巨大的单仓库。.repo/ 保存 Repo 元数据和 Manifest,通常不手改其内部数据。

需要追查"这个目录来自哪个仓库"时,可先看 Manifest,再在目标目录执行 git remote -v、git log。项目内的 local_manifests/ 可能额外引入设备或厂商仓库。

Product、Device、Board、Variant

这几个词经常一起出现,但各管一件事:

名词 主要回答的问题 常见位置
Product(产品) 要把哪些模块、属性和资源打进系统? device/<厂商>/<设备>/*.mk、AndroidProducts.mk
Device(设备) 这台设备的具体配置是什么? device/<厂商>/<设备>/
Board(板级配置) 分区、架构、内核和底层构建参数是什么? BoardConfig.mk 及其包含文件
Variant(构建变体) 调试能力和安全限制如何选择? user、userdebug、eng

lunch 选中的通常是"产品 + 变体",具体语法与候选项取决于 Android 版本和项目配置。进入源码树后,可用以下命令查看当前工程实际提供的目标:

bash 复制代码
source build/envsetup.sh
lunch

不要从别人的文章直接复制产品名;产品名必须在当前源码树里存在。

user 面向正式交付;userdebug 更接近正式系统但保留部分调试能力;eng 更偏工程调试。调试版上的行为不能直接当成正式 user 版结论,例如 adb root 和分区可写性都可能不同。

三、源码树里常见目录是什么意思

下面是常见路径的"第一印象"。不同 Android 分支会移动代码,厂商源码树还可能增加自定义目录。

路径 常见内容 你一般什么时候看它
build/ 构建入口、产品配置、Make/Soong 相关逻辑 lunch、编译变量或打包行为异常
build/soong/ Soong 构建系统与 Blueprint 处理 Android.bp 模块解析、依赖问题
build/make/ Make 侧构建规则与产品规则 产品继承、镜像生成、传统 .mk 配置
device/ 具体设备的产品配置、板级配置、设备专属文件 新增产品、改预装、资源覆盖、分区配置
vendor/ 厂商实现、专有组件或厂商产品配置 HAL、驱动配套服务、私有库;公开源码树可能缺失
hardware/ 硬件接口与通用硬件相关代码 HAL 接口与硬件抽象层
frameworks/ Framework、系统服务、Java API 等 改系统行为、权限、窗口、资源管理
packages/apps/ Settings、Launcher 等系统 App 的源码 改系统 App 界面与逻辑
packages/modules/ 可模块化更新的系统组件源码 网络、权限等模块的定制与排查
system/ init、核心 native 组件、系统工具等源码 启动、属性、底层系统行为
external/ 引入的第三方开源库 依赖或第三方组件问题
prebuilts/ 预编译工具链和二进制依赖 编译器、JDK、工具版本排查
kernel/、设备内核目录 内核源码或构建配置,布局依厂商而异 驱动、内核镜像、设备树问题
bootable/ 启动和恢复相关代码 Recovery 等启动路径排查
out/ 中间文件与最终构建产物 找 APK、镜像、OTA 包、编译日志
.repo/ Repo 元数据和 Manifest 查仓库来源、分支与同步状态

这里最容易混淆的是源码树的 system/ 和设备上的 /system:前者是一组源码仓库,后者是文件系统挂载点或逻辑分区内容。源码树 vendor/ 与设备 /vendor 也不是简单的一一对应关系。

Android.bp、Android.mk 与产品配置文件

  • Android.bp :Soong 的模块描述文件,常见模块类型有 cc_binary、java_library、android_app。它定义"这个模块怎样编译"。
  • Android.mk:传统 Make 模块描述文件,很多老代码和厂商代码仍在使用。
  • device.mk / 产品 .mk :通过 PRODUCT_PACKAGES、PRODUCT_COPY_FILES 等变量选择"哪些模块或文件进入某个产品"。
  • BoardConfig.mk:板级参数,可能涉及架构、镜像、分区与内核构建。
  • AndroidProducts.mk :声明该目录提供哪些产品,并为 lunch 提供候选目标。
  • *.rc :init 配置,定义服务何时启动、执行动作及属性触发;它不是普通 shell 脚本。
  • *.te、file_contexts:SELinux 策略及文件安全上下文,系统服务新增文件或访问路径时经常需要配套修改。

可以把它理解为:Android.bp 说"模块怎么做",产品配置说"这个产品要不要它",BoardConfig.mk 说"这块板子怎么打包和启动"。

四、从修改源码到找到产物

一条典型的开发路径是:

text 复制代码
修改源码或产品配置
   ↓
选择 lunch 目标
   ↓
m <模块名> 或 m 构建目标
   ↓
构建系统把文件安装到 out/target/product/<产品>/ 下的分区文件树
   ↓
生成镜像 / OTA 包
   ↓
刷机或升级,验证设备运行结果

常见输出目录:

text 复制代码
out/target/product/<产品>/
├── system/            # system 的安装文件树
├── system_ext/        # 如设备配置包含此分区
├── product/           # 产品文件树
├── vendor/            # 厂商文件树
├── odm/               # 如设备配置包含此分区
├── boot.img
├── vendor_boot.img    # 视设备和 Android 版本而定
├── system.img
├── vendor.img
├── product.img
├── super.img          # 动态分区设备可能生成
└── ...

这些文件是否存在、叫什么名字,取决于设备的分区方案和构建目标。out/target/product/<产品>/system/ 是构建机上的安装文件树 ,不是设备已经挂载的 /system。

例如修改 Settings:源码可能在 packages/apps/Settings/,但打出的 APK 装进哪个分区,应检查模块属性和产品配置,或在设备上用 adb shell pm path com.android.settings 看实际安装路径。仅凭源码路径猜"要刷 system.img"并不可靠。

五、系统镜像和分区:最常见的名字

镜像(image) 是构建或发布得到的文件;分区(partition) 是设备存储上的逻辑区域。镜像通常用于填充相应分区,但 Android 设备的分区组织并不固定。

镜像或分区 作用 定制时常见变化
boot.img / boot 与内核和启动相关;具体内容因设备代际而异 内核、启动参数等
init_boot.img / init_boot 部分较新设备把通用 ramdisk 放在这里 init 启动相关内容;并非所有设备都有
vendor_boot.img / vendor_boot 厂商启动 ramdisk 等设备相关启动内容 厂商 init 配置与启动组件
dtbo.img / dtbo Device Tree Overlay,描述硬件差异 板级硬件配置;不是所有设备都有独立分区
vbmeta.img / vbmeta Android Verified Boot(AVB)校验元数据 镜像签名与验证链
system.img / system Android 通用系统内容 Framework、部分系统服务和 App
system_ext.img / system_ext 扩展系统内容,放系统相关但不属于通用 system 的组件 OEM/平台扩展
product.img / product 面向产品的应用、资源和配置 预装 App、产品资源、属性
vendor.img / vendor 芯片或设备厂商实现 HAL 实现、厂商服务与库
odm.img / odm 设备制造商的硬件定制内容 设备级硬件配置和实现
super.img / super 动态分区的物理容器 承载若干逻辑分区的布局和内容
userdata.img / userdata 用户数据初始化镜像;实际 /data 会持续写入 恢复出厂、开发测试;不能当系统代码分区
metadata 加密、检查点等元数据,依设备实现 通常不直接手工修改

这张表是理解职责的起点,不是"每台设备都必须刷这些镜像"的清单。特别是启动相关镜像,分工随设备首发 Android 版本、GKI 方案和厂商实现而变化;不能把某台设备的 boot.img 用在另一台设备上。

super、动态分区与 fastbootd

采用动态分区 的设备,system、vendor、product、system_ext、odm 等可以作为 super 中的逻辑分区,实际集合由设备配置决定。这样系统升级时可以调整逻辑分区的大小,而不必为每个分区永久划死空间。

super.img 并不意味着设备上只有一个可见的 /super 文件夹;系统仍会把逻辑分区挂载为 /system、/vendor 等路径。super.img 也不一定是开发中最合适的单刷对象,要按设备发布包和刷写脚本决定。

Bootloader fastboot 在 Android 启动前工作;fastbootd 是用户空间 fastboot,常用于刷写动态逻辑分区。某设备在 bootloader 模式下不能刷 system,并不一定是镜像有问题,可能是需要进入 fastbootd。设备是否支持、如何切换,应先查官方刷机说明。

A/B 槽位与 Virtual A/B

A/B 设备有两组可切换的启动槽位,分区名可能带 _a、_b。系统通常从当前活动槽位启动,并把 OTA 更新写到另一槽位,重启后切换。Virtual A/B 进一步通过快照机制减少物理分区重复;它仍保留"槽位与可回退更新"的概念,但内部布局不能只凭 _a、_b 推断。

刷错槽位、只更新某个启动镜像却没同步相配套的分区,可能造成启动失败。检查设备时先读出实际槽位,不要假定所有设备都是 A/B,也不要假定当前槽位永远是 a。

六、Treble、HAL、GKI、VINTF、AVB:它们解决什么问题

缩写 / 名词 一句话解释 排查关联
Project Treble 把 Android Framework 与厂商实现之间的边界规范化 升级系统时的接口兼容性
HAL(硬件抽象层) Framework/系统服务访问硬件功能的约定接口及其实现 相机、音频、传感器等功能异常
AIDL / HIDL 描述跨进程接口的技术;现代 HAL 越来越多采用 AIDL 接口版本、客户端和服务端兼容
VINTF 通过设备 Manifest 与兼容性矩阵声明 Framework 和厂商接口要求 启动兼容性校验、HAL 服务声明
GKI 通用内核镜像思路,减少 Android 内核与厂商模块的耦合 内核、模块、启动镜像配套
AVB Android Verified Boot,验证启动链与分区内容 改镜像后校验失败、无法启动
SELinux 对进程和文件访问实施强制访问控制 服务启动但被 avc: denied 拒绝
RRO Runtime Resource Overlay,运行时资源覆盖 改界面文案、布尔配置、尺寸等资源

这几个概念经常在同一个问题里同时出现。例如把一个相机 HAL 服务放进 vendor 后,仍可能需要 VINTF 声明、init 服务定义和 SELinux 策略;只把二进制编译出来不等于设备能正常使用它。

七、"烧录镜像"到底指哪种操作

在 Android 开发里,"烧录"通常是口头说法。实际操作至少有四类:

方式 写入对象 常见用途 要特别确认
Bootloader fastboot 启动链或设备支持的分区 工程机、官方工厂镜像 设备型号、解锁状态、槽位
fastbootd 动态分区中的逻辑分区 刷 system、vendor 等 当前是否处于用户空间 fastboot
Recovery / OTA sideload OTA 包,由升级程序决定写哪些分区 正式升级、整包验证 签名、版本与升级路径
厂商下载工具 芯片平台定义的完整固件包 量产、救砖、底层刷写 专用包、线材、权限、设备硬件版本

adb 主要与已启动的 Android 系统 通信;fastboot 与 bootloader 或 fastbootd 通信。它们是不同阶段的工具。adb push 一个文件到设备,也不等于把它做成了可持久、可验证的系统镜像。

刷写前的只读检查

下面的命令只用于识别设备状态,输出因设备而异:

bash 复制代码
adb devices
adb shell getprop ro.product.device
adb shell getprop ro.build.fingerprint
adb reboot bootloader
fastboot devices
fastboot getvar product
fastboot getvar current-slot
fastboot getvar is-userspace

adb reboot bootloader 会重启进入 bootloader;若设备还未启动,直接从 fastboot devices 开始。部分 getvar 在某些设备上会返回未知,不能仅靠一个变量下判断。

随后核对:

  1. 固件包与设备准确型号、硬件版本和分区方案匹配;
  2. 镜像来自同一套构建,启动镜像与 system/vendor 等相互兼容;
  3. 是否 A/B、当前槽位是什么、目标分区是物理还是 super 内的逻辑分区;
  4. Bootloader 解锁是否允许,以及解锁或刷机是否清除用户数据;
  5. 刷机包脚本是否包含清除 userdata、变更槽位或锁定 Bootloader 的操作;
  6. 是否有该设备官方的恢复包和数据备份。

概念上,单分区刷写是 fastboot flash <分区名> <匹配镜像>;动态逻辑分区可能需要先进入 fastbootd。这里不提供可直接执行的固定分区命令,因为同名分区在不同设备上的槽位、校验链和刷写阶段可能不同。实际操作应以该设备对应版本的工厂镜像脚本或厂商说明为准,并先读懂脚本内容。也不要把"关闭验证"或"重锁 Bootloader"当成通用修复方式。

OTA 与工厂镜像的区别

工厂镜像 通常面向初始化或维修,可包含多个分区镜像和刷写脚本,可能清除用户数据。OTA 包面向从一个已知版本升级到另一个版本,包含校验、签名、分区更新与版本约束,A/B 设备还可能使用快照。两者不能只看文件扩展名来互换使用。

在做产品发布时,应把"开发机临时刷通"与"用户设备能安全升级"分开验证。新增系统 App、修改分区大小、调整 HAL 或内核时,尤其需要完整的 OTA 路径测试。

八、三个常见定制需求,从哪里开始找

1. 修改系统设置界面或预装 App

先在 packages/apps/ 及厂商 App 仓库找到源码;再看其 Android.bp 或 Android.mk、产品 PRODUCT_PACKAGES,确认模块是否参与当前产品;编译后查看安装路径。若是系统特权 App,还要检查签名、权限白名单和对应分区。新 App 仅复制到 /system/priv-app 不保证能获得特权权限。

2. 修改开机默认配置或资源

先判断是系统属性、Framework 资源、产品资源还是 RRO。搜索配置定义与使用点,再查产品继承链、overlay 优先级和最终编译产物。运行时可用 adb shell getprop 或资源相关工具核对结果。多个 overlay 命中同一资源时,必须确认目标包、优先级和设备配置。

3. 增加一个硬件服务

从接口定义、厂商实现、init 服务、VINTF 声明、SELinux 策略及产品模块列表逐项确认。编译通过后,再看启动日志、服务注册状态和 avc: denied。这类功能常跨 hardware/、vendor/、device/,很少只改一个文件就完成。

九、常见报错如何反推所在层

现象 优先怀疑的层 先看什么
lunch 找不到目标 产品配置 AndroidProducts.mk、Manifest 是否同步齐全
m 报模块不存在 构建描述 Android.bp/Android.mk、模块名、Soong namespace
编译成功但设备没有文件 产品打包 PRODUCT_PACKAGES、安装分区、out/target/product/...
刷写提示 partition 不存在 分区/刷写阶段 设备分区表、A/B 槽位、是否需 fastbootd
启动卡在 Logo 或验证失败 启动链/校验 镜像是否同套、AVB、boot/vendor_boot/vbmeta 配套
服务在但调用失败 接口/权限 VINTF、HAL 版本、SELinux、服务日志
本地刷机正常但 OTA 失败 发布流程 签名、增量基线、分区变化、包版本与快照状态

排错时保持"从现象回到层次"的思路:文件没进镜像,就先查构建配置;文件进了镜像却没生效,再查挂载、属性、权限或服务启动;镜像甚至刷不进去,先查设备分区和刷写模式。

十、入门时最值得记住的六句话

  1. AOSP 源码不等于某台手机的完整固件。 设备还需要配套的内核、厂商组件和配置。
  2. 源码目录不等于设备分区。 要用模块配置和最终安装路径确认文件落点。
  3. out/target/product/<产品>/ 是构建产物入口。 从这里追到镜像与 OTA 包。
  4. super 是动态分区的容器,system 等逻辑分区仍各有职责。
  5. fastboot、fastbootd 与 OTA 服务于不同刷写阶段。 先认设备与包,再选工具。
  6. 镜像、签名、槽位和硬件版本必须匹配。 单刷某个文件成功,不代表整机可启动或可升级。

如果还没有搭好源码与构建环境,可以先读本项目的 AOSP 源码编译环境搭建指南。建立可重复的构建流程后,再用本文的"源码 → 配置 → 产物 → 分区 → 设备"路径定位每一次定制改动。

参考资料

相关推荐
传奇开心果编程1 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer
supabc1232 小时前
Celium:连接 Windows、Mac、Linux 与 Android,让远程访问和设备管理更简单
android·linux·windows·macos·远程访问·网络管理·celium
Dovis(誓平步青云)2 小时前
导览音频切换太快,旧讲解不能覆盖新展品
android·前端·javascript·ecmascript·音视频·宠物
五彩小白18 小时前
自回归和上下文
android
事圆则缓20 小时前
Android 多渠道打包实战:Product Flavors、签名、AAB 与发包校验
android
树下困觉眯1 天前
View绘制流程学习--获取WindowManager的三种方式
android·系统架构·view design
vilya1 天前
我怎么给手机 GUI Agent 做双通道感知:无障碍树为主,投屏像素兜底
android·人工智能
李子红了时1 天前
阿狸舞台APP(安卓端手机EncFS解密+压缩包解压+视频播放)
android·音视频
事圆则缓1 天前
Android 使用 Jenkins 实现 CI/CD,并用 SonarQube 建立质量门禁
android·ci/cd·jenkins