Android 操作系统并不是从零开始构建的,而是建立在 Linux 内核之上的一个高度定制的软件栈。理解 Android 操作系统的整体架构,是深入理解任何一个子系统(Binder、SurfaceFlinger、AMS、Zygote 等)的前提。本文将系统性地介绍 Android 操作系统的四层架构、Linux 内核为 Android 所做的定制修改,以及 Android 选择 Linux + Binder IPC 架构的深层原因。
一、Android 操作系统的四层架构
1.1 经典分层模型
┌──────────────────────────────────────────────────────┐ |
1.2 各层职责详解
第一层:Linux Kernel(Linux 内核)
Linux 内核是 Android 平台的基石,负责:
- 进程管理:创建、调度、终止进程和线程
- 内存管理:虚拟内存、物理页面分配、进程间内存隔离
- 设备驱动:硬件设备的抽象和访问控制
- 文件系统:ext4 / erofs / f2fs / tmpfs 等文件系统支持
- 网络协议栈:TCP/IP、WiFi、蓝牙、NFC
- 安全模型:基于 UID/GID 的进程隔离、SELinux、Capabilities
第二层:HAL(硬件抽象层)
HAL 是 Android 架构中最重要的抽象之一。每个硬件组件都有一个 HAL 模块(通常以 .so 文件形式存在),框架层通过 HAL 接口调用硬件,而不直接与内核驱动交互。
App → Android Framework → HAL Interface → HAL Implementation → Kernel Driver → Hardware |
Android 8+ 引入了 HIDL(HAL Interface Definition Language)将 HAL 服务运行在独立进程中,进一步隔离了框架层和硬件实现层,这是 Treble 架构的核心。
第三层:Native Libraries + Android Runtime
Native C/C++ Libraries(原生库):
- Bionic:Android 定制的 C 标准库,替代 glibc
- SurfaceFlinger:显示合成引擎
- Media Framework:音视频编解码框架(Stagefright)
- SQLite:嵌入式关系型数据库
- OpenGL ES / Vulkan:3D 图形渲染 API
- Skia:2D 图形渲染引擎(同时也是 Flutter 的渲染引擎)
- libcrypto / libssl:OpenSSL 加密库
**Android Runtime (ART)**:
- AOT (Ahead-Of-Time) 编译:安装时把 DEX 字节码编译为 native 指令
- JIT (Just-In-Time) 编译:运行时对热点代码进行即时编译
- GC(垃圾回收):并发压缩回收、分代回收(Android 10+)
- Profile-guided 优化:基于应用使用模式优化编译
第四层:Java API Framework(Java 框架层)
这是 Android 应用开发的核心 API:
- ActivityManagerService — 四大组件管理
- WindowManagerService — 窗口管理
- PackageManagerService — 包管理
- ContentProvider — 数据共享
- View System — UI 组件体系
- TelephonyManager — 电话功能
- ResourceManager — 资源管理
第五层:System Apps(系统应用层)
预装的系统级应用,与第三方应用共享同一运行时:
- Launcher(桌面)
- Phone(拨号)
- Contacts(联系人)
- Settings(设置)
- Camera(相机)
- SystemUI(状态栏/导航栏)
二、Linux 内核为 Android 所做的关键修改
Android 并不是简单地拿一个标准 Linux 内核来用。Google 对 Linux 内核做了大量的定制修改,这些修改通过 Android Mainline Project 逐步合入 Linux 主线。
2.1 Binder IPC 驱动程序
Binder 是 Android 最核心的 IPC(进程间通信)机制,作为内核驱动实现:
// drivers/android/binder.c (Android 内核中的 Binder 驱动) |
Binder 驱动在 /dev/binder 上为用户空间提供接口。Android 10+ 引入了多 Binder 域:
/dev/binder— 系统服务通信/dev/hwbinder— HIDL HAL 服务通信/dev/vndbinder— Vendor 域 HAL 服务通信
2.2 ashmem(Android Shared Memory)
ashmem 是 Android 特有的共享内存机制,支持通过名称引用和引用计数自动回收:
// drivers/staging/android/ashmem.c (已被 memfd 逐步替代) |
在 Android 10+ 中,ashmem 正逐步被 Linux 标准的 memfd_create() 和 dmabuf 替代。
2.3 ION 内存分配器(Android 12 中已被 dma-buf heaps 替代)
ION 是 Android 的通用内存管理器,用于在 CPU、GPU、DSP、Camera 等设备之间共享内存:
// drivers/staging/android/ion/ (已废弃) |
2.4 Low Memory Killer (LMK) → lmkd
Android 最初在内核中实现了低内存杀手(LMK)驱动,在内存不足时选择性杀死进程。从 Android 9 开始,这个功能被迁移到用户空间的 lmkd 守护进程:
// system/memory/lmkd/lmkd.cpp |
2.5 Wakelocks 和电源管理
Android 的电源管理非常激进——设备默认进入 suspend 状态,由 wakelock 机制决定何时保持唤醒:
// drivers/power/wakelock.c (Android 内核修改) |
2.6 Alarmtimer
Android 修改了 Linux 的 alarm timer 系统,使设备可以在预定的时间从 suspend 状态中唤醒:
// kernel/time/alarmtimer.c |
2.7 Paranoid Network Security
Android 对网络访问施加了额外的安全限制:
// net/ipv4/af_inet.c 等 |
2.8 Android 内核与 Linux 主线的合入
从 Android 11 开始,Google 通过 Android Generic Kernel Image (GKI) 项目将 Android 内核修改逐步合入 Linux 主线或封装为独立模块。目标是:
- GKI 1.0 (Android 11):内核版本 5.4,厂商模块与内核解耦
- GKI 2.0 (Android 12+):内核版本 5.10+,更大的主线上游覆盖率
三、Android 的 Init 系统 vs 传统 Linux Init
3.1 Android init 与 systemd / sysvinit 的对比
| 特性 | Android init | systemd | sysvinit |
|---|---|---|---|
| 配置语言 | init.rc(自定义语言) | unit 文件 (.service, .target 等) | shell 脚本 |
| 依赖管理 | 触发器机制 (on property:) | 显式依赖 (Requires=, Wants=) | 脚本顺序(无依赖) |
| 服务监控 | 内置(SIGCHLD + epoll) | 内置(cgroups 监控) | 需要额外守护进程 |
| 并行启动 | 事件驱动并行 | Socket-based 并行 | 串行 |
| 属性存储 | 内置 Property Service | systemd 不支持 | N/A |
| 设备节点管理 | 内置 ueventd | udevd (systemd-udevd) | udev / mdev |
| 适用场景 | 嵌入式/移动设备 | 桌面/服务器 Linux | 传统 Unix/嵌入式 |
3.2 为什么 Android 不直接使用 systemd
- 资源开销:systemd 设计为功能完备的 init 系统,包含 journald、logind、networkd 等大量组件,这些对嵌入式移动设备是过度设计
- 启动性能:Android 的设备节点管理和服务启动优化极度精简,专注于亚秒级启动,systemd 的通用性引入了不可接受的延迟
- Android 特化需求:android init 深度集成了 property service、SELinux 上下文管理、USB gadget 配置等 Android 特有的功能
- 许可:Android 的用户空间多采用 Apache 2.0 和 BSD 许可,systemd 是 LGPL 2.1+
四、为什么 Android 选择 Linux 内核 + Binder IPC?
4.1 Android 之前的选择
实际上,Android 在早期设计阶段评估过多种方案:
- 纯 Java 在裸机上:缺少成熟的硬件驱动和管理层,需要从头实现所有驱动
- L4 等微内核:驱动生态薄弱,成熟硬件支持有限
- Linux + D-Bus IPC:D-Bus 设计为桌面应用 IPC,延迟高、不支持零拷贝
4.2 选择 Linux 的原因
- 成熟的驱动生态:Linux 已有大量 ARM 处理器和外设的优质驱动
- 活跃的开发社区:持续的 bug 修复、安全补丁、新硬件支持
- 经过验证的安全模型:UID/GID 隔离、SELinux、Capabilities
- 开源许可兼容:GPL v2 内核与 Apache 2.0 用户空间的组合在商业和法律上可行
- 可定制性:Android 团队可以根据需要裁剪内核,保留所需组件
4.3 选择 Binder 代替 D-Bus / Unix Socket 的原因
Binder 的设计由前 BeOS 工程师 Dianne Hackborn 主导,针对移动设备进行了深入优化:
Binder 相比 D-Bus 的优势:
- 零拷贝传输:通过 mmap 在内核空间映射接收缓冲区,传输大块数据时避免用户空间复制
- 调用者身份保证:内核驱动保证
sender_euid/sender_pid不被伪造,这是 Android 权限模型的基础 - 引用计数和死亡通知:自动管理跨进程对象引用,peer 崩溃时自动清理
- 线程池管理:Binder 驱动内建线程池,Binder 调用在服务端自动分配线程
Binder 的实现特点:
- 内核驱动实现(~4000 行 C 代码)轻量且经过高度优化
- 每个 Binder 事务通过 ioctl 发送,上下文切换次数少
- 支持 oneway(异步)和 twoway(同步-应答)两种事务模式
4.4 Binder 不适合的场景
- 大文件传输(> 1MB):Binder 的事务缓冲区有限(通常 1MB-8MB),大数据应使用 shared memory (ashmem/memfd) + Binder 传递 fd
- 流式数据传输:持续的高频数据传输应使用 Unix Domain Socket(Socket 本身就是面向流的)
五、Fuchsia:Android 的长期替代方案
5.1 Fuchsia 简介
Fuchsia 是 Google 自 2016 年开始开发的新一代操作系统,基于 Zircon 微内核(不是 Linux),目标是为各种形态的设备提供统一的操作系统基础。截至 2023 年,Fuchsia 已部署在部分 Nest Hub 设备上。
5.2 Zircon 与 Linux 的关键差异
| 特性 | Linux(Android 使用) | Zircon(Fuchsia 使用) |
|---|---|---|
| 内核架构 | 宏内核(Monolithic) | 微内核(Microkernel) |
| 驱动模型 | 内核空间驱动 | 用户空间驱动(部分) |
| IPC 机制 | Binder(内核模块) | Channel(原生内核对象) |
| 调度模型 | CFS (Completely Fair Scheduler) | 基于 deadline 的调度器(更可预测) |
| 编程语言 | C | C++(部分) |
| 能力模型 | UID/GID + Capabilities + SELinux | 基于 capability 的对象句柄 |
| 文件系统 | ext4 / erofs / f2fs | minfs / blobfs / memfs |
5.3 为什么 Android 短期内不会迁移到 Fuchsia
- 生态惯性:数十亿 Android 设备和数以百万计的 App 依赖 Linux 内核的特定行为
- 硬件驱动:Linux 的驱动覆盖范围远超 Zircon
- 工程成本:迁移整个 Android 运行时(ART)、框架层到新的内核 API 是天文数字的工程
- 商业考量:Android 生态由 OEM 和 SoC 供应商共同维护,迁移 Fuchsia 需要所有参与方的支持
- GKI 的战略:Google 最近的策略是简化 Linux 内核的维护(GKI),而不是替换它
六、Android 系统中的核心概念
6.1 进程隔离模型
Android 中每个 App 在其自己的 Linux 进程中运行(有例外,如 android:process 配置)。每个 App 进程被分配:
- 唯一的 UID
- 独立的内存地址空间
- 独立的 Dalvik/ART 虚拟机实例
- 独立的文件系统命名空间(通过
mount namespace隔离)
6.2 SELinux 强制访问控制
Android 从 4.3 开始引入 SELinux,4.4 起强制开启(Enforcing 模式)。SELinux 是 Android 安全模型的基石:
进程 (domain) → 操作 (class:permission) → 资源 (type) |
核心 type 定义:
# system/sepolicy/public/domain.te |
6.3 Android Init 的语言设计哲学
Android init 使用自定义的声明式配置语言 init.rc 而非 shell 脚本。这背后的设计考量:
- 性能:解析简单的 key-value 行远比启动 shell 进程执行脚本快
- 安全:声明式语法消除了 shell 注入风险
- 可维护性:语法受限保证了配置的可预测性
- 可观测性:init 可以监控所有 action 的执行状态
七、核心面试题
Q1:Android 为什么使用 Linux 内核而不是其他内核(如 BSD、L4)?
答:(1) Linux 在 ARM 平台上有最成熟的硬件驱动生态,而移动设备 SoC 种类繁多;(2) Linux 社区活跃,持续获得安全补丁和性能优化;(3) Linux 的 GPL v2 许可与 Android 用户空间的 Apache 2.0 许可兼容;(4) Linux 的 UID/GID 隔离模型天然适合 Android 的每个 App 一个 UID 的设计;(5) Linux 内核模块化设计允许 Android 灵活裁剪——Android 设备通常关闭大部分服务器级功能(如 NFS、XFS 等),以此减小内核体积和攻击面。
Q2:Binder 在 Android 中为什么比传统的 Unix Domain Socket 更适合做 IPC?
答:(1) 零拷贝:Binder 通过 mmap 在内核空间预分配接收缓冲区,发送方可以直接写入接收方的内存区域(通过内核中转),避免了一次用户空间拷贝。Unix socket 在 send/recv 时需要在用户空间和内核空间之间拷贝数据。(2) 身份认证:Binder 驱动在每次事务中携带 sender_euid 和 sender_pid,服务端可以信任这些信息(因为内核确保了它们的正确性)。Unix socket 虽然可以通过 SO_PEERCRED 获取对端凭证,但易被 forget。(3) 死亡通知:Binder 通过 linkToDeath 自动通知服务端客户端进程的退出,Unix socket 没有这种内建机制。(4) 对象引用计数:Binder 驱动自动管理跨进程的对象引用,确保对象在所有引用释放前不被销毁。
Q3:Android 的 HAL 层与标准 Linux 的驱动模型有什么不同?为什么需要 HAL?
答:标准 Linux 的驱动模型是:用户空间 → 系统调用 → 内核驱动 → 硬件。这个模型的问题是:不同厂商的硬件有不同的内核驱动接口,应用层需要针对不同驱动编写不同代码。Android HAL 在驱动之上增加了一层抽象:用户空间 → HAL 接口(标准 API 契约)→ HAL 实现(厂商提供 .so)→ 内核驱动 → 硬件。这使得:上层框架使用统一的 HAL 接口,厂商只需实现 HAL 接口而不需要修改框架代码。HIDL(Android 8+)进一步将 HAL 实现放入独立进程(Binderized HAL),使得 HAL 可以独立于 framework 更新,这是 Treble 架构的基础。
Q4:lmkd(用户空间 LMK)和内核 LMK 相比有什么优势?
答:传统内核 LMK 的问题:(1) 策略硬编码在内核中,更新策略需要重新编译/刷写内核;(2) 内核空间能使用的系统状态信息有限,无法读取进程的 importance 等 framework 层信息;(3) 内核 LMK 基于简单的内存阈值触发,无法结合系统的整体负载场景(如是否有前台 Service)做出更精细的决策。用户空间 lmkd 的优势:可以通过 AMS 获取进程的 OOM ADJ 值、通过 /proc/pressure/memory 获取内存压力事件、通过 cgroup 进行精细的内存限制、策略更新不需要动内核。
Q5:Fuchsia 的 Zircon 微内核架构相比 Linux 宏内核有什么优势?为什么 Google 在 Android 之外又开发 Fuchsia?
答:微内核架构的优势:(1) 故障隔离:驱动在独立的用户空间进程中运行,一个驱动 crash 不会导致整个系统崩溃,内核可以重启该驱动进程;(2) 安全:更小的 TCB(Trusted Computing Base),内核本身代码量远小于 Linux;(3) 可更新性:无需重启整个系统即可更新单个驱动。Google 开发 Fuchsia 的动机包括:(1) Linux 内核的开发流程和许可证模型不完全符合 Google 的利益;(2) GKI 虽然减小了碎片化但无法从根本上解决内核版本碎片化问题;(3) Google 希望在定义下一代操作系统的 IPC 模型、调度器、安全架构方面拥有完整的控制权。但短期来看,Android 在 Linux 上的投入和生态系统决定了迁移不会快速发生。
七、Android 安全架构概览
7.1 纵深防御模型
Android 的安全架构采用多层纵深防御(Defense in Depth)策略:
- 应用层沙箱:每个 App 在自己的 UID 下运行,互相隔离
- 权限系统:运行时权限 (Runtime Permissions) + 安装时权限
- SELinux:强制访问控制,限制所有进程(包括 root)的行为
- seccomp:系统调用过滤(seccomp-bpf),减少内核攻击面
- 应用签名:所有应用必须签名,签名一致的 App 可共享 UID
- Verified Boot:从硬件根信任到 system 的完整验证链
- 文件系统加密:FBE (File-Based Encryption) 和 FDE (Full-Disk Encryption)
- Keystore:硬件级别的密钥存储和管理
7.2 seccomp 在 Android 中的应用
Android 通过 seccomp-bpf 限制进程可用的系统调用集合:
// bionic/libc/seccomp/seccomp_policy.cpp |
seccomp 在 init 进程的第一阶段就启用:global_seccomp() 在系统启动早期全局安装 seccomp filter。
八、Android 与嵌入式 Linux 的对比
8.1 Android 不是传统 Linux 发行版
许多人误以为 Android 就是 “Linux + Java”。实际上 Android 在很多方面与传统 Linux 发行版有根本差异:
| 方面 | 传统 Linux (Debian/Ubuntu) | Android |
|---|---|---|
| C 库 | glibc | Bionic(更小、更快、BSD 许可) |
| init 系统 | systemd / sysvinit | 自定义 init(init.rc) |
| 进程间通信 | D-Bus / Unix Socket / Pipe | Binder(内核驱动实现) |
| 显示服务器 | X11 / Wayland | SurfaceFlinger + HWC |
| 音频系统 | PulseAudio / ALSA / PipeWire | AudioFlinger + Audio HAL |
| 包管理 | apt / dpkg / rpm | APK / PackageManager |
| 文件系统布局 | FHS (Filesystem Hierarchy Standard) | 自定义布局 (/system, /vendor, /data) |
| 桌面环境 | GNOME / KDE / XFCE | SystemUI + Launcher |
| 进程模型 | 传统 fork/exec | Zygote 预加载 + fork |
| 电源管理 | ACPI / systemd-logind | Wakelock + PowerManagerService |
| 系统升级 | apt upgrade / unattended-upgrades | A/B OTA / update_engine |
这些差异反映了 Android 团队的刻意设计选择——专为移动设备场景裁剪和优化。
AOSP 核心路径参考:
drivers/android/binder.c— Binder 驱动drivers/staging/android/ashmem.c— 匿名共享内存drivers/staging/android/ion/— ION 内存分配器(已废弃)drivers/power/wakelock.c— 电源管理system/core/init/— Android init 进程system/memory/lmkd/— 用户空间低内存杀手system/sepolicy/— SELinux 策略hardware/interfaces/— HIDL HAL 接口定义system/core/rootdir/init.rc— 系统启动配置frameworks/native/cmds/servicemanager/— Binder 服务管理器frameworks/native/services/surfaceflinger/— 显示合成引擎




