Android 使用 Linux 内核实现调度、进程隔离、设备驱动、网络和文件系统,但提供自己的原生库、运行时、框架和应用模型。Bionic 是 Android 的 C 库。ART 执行 DEX 字节码,而 Binder 提供主要的跨进程 RPC 机制。
运行时和进程创建 #
构建工具将 Java 或 Kotlin 源代码编译为类文件,然后将其转换为 DEX 代码。APK 或应用包交付拆分会对 DEX、资源、原生库、签名元数据和清单进行打包。ART 会根据设备和配置文件状态,适当地编译或解释 DEX;APK 并不只是一个可执行 JAR。
init 是 Android 的 PID 1 进程。它挂载早期文件系统、应用策略、启动原生服务并启动 Zygote。Zygote 预加载常用的运行时类和资源,然后根据系统请求 fork 应用进程。fork 模型会在任一进程写入页面之前共享这些页面,从而降低应用启动成本。
应用隔离和 Binder #
安装软件包时通常会分配一个独立的 Linux UID。文件所有权和内核凭据隔离应用私有文件,而 SELinux 会对进程、文件、服务和 Binder 调用应用强制访问控制策略。除内核控制之外,框架和服务边界也会检查权限。
在另一个软件包中启动的应用组件会在目标软件包的进程中运行。Binder 会将事务传递到该进程,并携带调用方身份以进行权限检查。Binder 对象引用是具备生命周期和权限语义的能力;导出的组件或服务必须验证所有由调用方控制的参数。
系统分区和更新 #
现代设备会将操作系统映像划分为逻辑分区,这些分区通常为只读:
| Mount | Purpose |
|---|---|
/system | 核心框架、运行时和平台应用 |
/system_ext | 具有平台特定生命周期的系统扩展 |
/product | 产品和 OEM 定制 |
/vendor | 硬件供应商库、HAL 和配置 |
/odm | 设备特定的供应商覆盖层和配置 |
/vendor_dlkm, /system_dlkm | 可动态加载的内核模块 |
/data | 按设备和用户划分的可写应用数据 |
/metadata | 加密和启动服务所需的元数据 |
动态分区会将逻辑分区置于物理 super 分区中。dm-5 等 Device-mapper 名称表示这些逻辑块设备。报告容量接近满载的只读映像通常是不变的文件系统映像,并不表示用户数据存储空间已耗尽。
Verified Boot 为启动过程和已验证分区建立信任链。A/B 更新会写入非活动槽位,并在验证后选择该槽位;如果新槽位无法启动,则可以回滚。
APEX 和原生接口 #
APEX 软件包交付选定的底层平台模块,包括 ART 和 Conscrypt。Android 会在启动早期验证并将 APEX 映像挂载到 /apex 下;稳定路径会公开活动版本。供应商接口和硬件抽象层按照特定 Android 版本的兼容性规则,将框架版本与供应商实现分离。
可写存储和挂载命名空间 #
/data 是主要的可写分区。基于文件的加密会区分设备加密存储和凭据加密存储:前者在用户解锁前即可使用,后者在用户解锁后可用。每个用户的路径包括 /data/user/0 和 /data/user_de/0。
模拟共享存储通过 /storage/emulated/0 等路径公开,并由 /data/media 下的私有存储提供支持。FUSE 和挂载命名空间为每个应用和用户提供适当的视图,并强制执行分区存储访问规则。/storage/self/primary 会解析为进程的主共享存储视图;代码应使用平台存储 API,而不是硬编码实现路径。
proc、sysfs、binderfs、selinuxfs、cgroupfs 和 tracefs 等伪文件系统公开的是内核接口,而不是持久文件。mount 列表与设备、版本和进程命名空间相关,因此应视为诊断证据,而不是可移植的文件系统契约。
评论
在 GitHub 上阅读或评论(发表评论需要登录)