Android 与 Linux 对比

一、前言
1.1 Android 与 Linux 的内核渊源
Android 和 Linux 之间的关系,首先体现在内核层的直接继承与定制化改造上。
- 内核同源 :Android 操作系统的底层核心------Linux 内核,直接来源于 Linux 开源社区。Android 使用 Linux 内核提供的进程调度、内存管理、网络协议栈、设备驱动模型、安全框架(如 SELinux)等基础能力。可以说,没有 Linux 内核,就没有 Android。
- 并非原封不动 :Android 并没有直接使用主线 Linux 内核,而是基于某个长期支持版本(LTS,Long Term Support)进行大量修改和增强。这些修改主要集中在:
- 移动设备特性:增加低内存杀手(LowMemoryKiller)、唤醒锁(Wakelocks)等机制,以适应手机/平板的有限内存和电池供电场景。
- 新增驱动:Binder(跨进程通信驱动)、ashmem(匿名共享内存)、logger(日志驱动)等,这些在通用 Linux 内核中并不存在。
- 精简与移除:去除了部分对移动设备无用的功能(如许多旧式硬件驱动、某些文件系统等),以减小内核体积。
- 版本滞后:为了稳定性与兼容性,Android 通常使用比主线落后一到两年的 LTS 内核版本,并将安全补丁和必要的新特性回移植到自己的内核分支中。例如,Android 12 可能基于 Linux 4.14 或 4.19 内核,而当时主线可能已经更新到 5.x。
总结:Android 与 Linux 的关系是 "同根而生,枝干不同" ------ 根是 Linux 内核,但枝干(Android 内核分支)为移动设备做了专门的修剪与嫁接。
1.2 Linux 的设计目标:通用、稳定、可移植
Linux 从诞生之初就定位为一款通用操作系统,其设计目标贯穿始终:
- 通用性:Linux 能够运行在从超级计算机、大型服务器、桌面 PC,到嵌入式设备(路由器、智能家电)、物联网传感器等几乎所有的计算平台上。为了满足不同场景,Linux 内核支持数十种硬件架构(x86、ARM、RISC-V、MIPS、PowerPC 等),以及海量的驱动程序。
- 稳定性:在企业级服务器和关键任务环境中,Linux 以"数月甚至数年不重启"而著称。内核的模块化设计允许动态加载和卸载驱动,而不会影响系统整体运行。长期支持版本(LTS)提供长达数年的维护和安全更新。
- 可移植性:Linux 严格遵循 POSIX(可移植操作系统接口)标准,并提供了 glibc(GNU C 库)作为用户空间与内核的标准接口。这意味着为 Linux 编写的应用程序,只需少量修改甚至无需修改,就可以在其他 POSIX 兼容系统(如 BSD、macOS 的某些部分)上编译运行。
- 开放与自由:Linux 采用 GPL 许可证,源代码完全开放,任何人可以自由使用、修改、分发。这催生了数以千计的发行版(如 Ubuntu、Debian、Red Hat、Arch Linux),各自面向不同用户群体(桌面、服务器、安全、嵌入式等)。
典型的 Linux 应用场景:网站后端(Nginx/Apache 运行在 Linux 上)、云计算(AWS EC2 实例绝大多数是 Linux)、科学计算(TOP500 超算几乎全用 Linux)、嵌入式(OpenWrt 路由器)、开发环境(WSL 中的 Ubuntu)。
1.3 Android 的设计目标:移动设备、用户体验、应用生态
Android 是 Google 专门为移动设备(最初是智能手机)打造的完整操作系统软件栈,其设计目标与通用 Linux 截然不同:
- 移动优先:一切设计围绕触摸屏、低功耗、有限内存、移动网络、传感器(GPS、加速度计、陀螺仪)等移动硬件特性。Android 引入了电源管理框架(Wakelocks + Suspend blockers),使得设备在待机时进入深度休眠,同时又能被电话、闹钟等事件唤醒。
- 用户体验至上 :Android 强调流畅的动画、直观的手势、多任务切换、即时通知响应。为此,Android 在底层增加了进程优先级体系(前台、可见、服务、后台、空进程),并配合低内存杀手(LowMemoryKiller)在内存紧张时优先杀掉后台进程,以保证前台应用的响应速度。
- 应用生态为王 :Android 构建了完整的应用分发与运行模型 :
- Java/Kotlin 作为一等公民:应用运行在 Dalvik/ART 虚拟机中,开发者无需关心底层硬件差异。
- 四大组件(Activity、Service、Content Provider、Broadcast Receiver)规范了应用的行为和交互方式。
- 应用商店(Google Play) 提供集中分发、审核、更新、安全扫描。
- 沙盒隔离:每个应用以独立的 Linux 用户 ID 运行,默认无法访问其他应用的数据或系统核心文件。
- 碎片化控制 :通过硬件抽象层(HAL),设备厂商可以在不修改内核和上层框架的情况下,添加对特定硬件的支持。这大大减少了因厂商定制导致的系统分裂。
典型 Android 应用场景:智能手机、平板、智能电视(Android TV)、手表(Wear OS)、车载系统(Android Auto)、自助终端、收银机等。Android 从未试图进入传统服务器或桌面市场(尽管存在第三方项目如 Android-x86,但非官方目标)。
1.4 一个通俗而专业的视角:Android 是运行在 Linux 内核上的"重量级应用"
1.4.1 Android 作为 Linux 内核之上的特殊用户空间软件栈
从技术实现上看,当 Android 设备启动时:
- Linux 内核首先加载:Bootloader 加载 Linux 内核,内核完成硬件初始化、驱动加载、调度器启动等任务。
- 内核启动第一个用户空间进程
init:这与普通 Linux 系统完全一致。 init进程启动 Android 专属的守护进程和服务 :例如servicemanager、surfaceflinger、zygote(孵化器)等。这些进程完全是运行在用户空间的普通 Linux 进程 ,它们使用 Linux 的系统调用(如open、read、write、ioctl)来访问硬件和内核服务。- 最终,Android 系统服务和应用框架全部运行在用户空间:没有修改 Linux 内核的"操作系统"身份。
因此,从 Linux 内核的角度看,它并不关心自己上面跑的是传统的 GNU/Linux 发行版还是 Android ------ 它只是运行了一组用户空间进程而已 。这些进程中,有一个叫做 system_server 的进程(包含 ActivityManager、PackageManager 等),它管理着所有其他 App 进程。这就类似于在 Linux 上运行了一个 "进程管理大管家",而这个管家又管理着成百上千个"小进程"(即 App)。
1.4.2 虚拟机(ART/Dalvik)是其核心组件
与绝大多数 Linux 应用(如 bash、nginx、Firefox)不同,Android 的应用不是直接编译成机器码(ELF 格式)运行,而是编译成 DEX 字节码 ,然后在 ART(Android Runtime)虚拟机 中解释执行或 AOT(预编译)执行。
- 为什么需要虚拟机?
- 跨平台:同一份 APK 可以在 ARM、x86、RISC-V 等不同架构的设备上运行。
- 内存安全:虚拟机提供垃圾回收、数组越界检查等安全保障。
- 应用隔离:每个 App 在自己的虚拟机实例中运行,互不干扰。
- 虚拟机与 Linux 的关系 :ART 本身也是一个普通的 Linux 进程(通常由
zygote派生而来)。它使用 Linux 的内存分配、线程调度、文件 I/O 等系统调用来实现 Java/Kotlin 代码的执行。
1.4.3 专业表述
Android 是一个基于 Linux 内核构建的、面向移动设备的完整应用运行时与框架层,本质上可视为 Linux 内核之上的一个重量级、多进程的用户态中间件系统。其核心特征包括:
- 以 ART/Dalvik 虚拟机作为应用执行环境,提供跨平台和内存安全;
- 用 Bionic libc 和 Binder IPC 替代传统的 glibc 与 D-Bus,优化性能与安全性;
- 包含 ActivityManager、PackageManager 等系统服务,统一管理应用生命周期、权限、安装等;
- 通过 HAL(硬件抽象层)隔离内核驱动与上层框架,降低设备碎片化。
1.4.4 通俗总结
"Android 其实就是跑在 Linux 内核上面的一个 Linux 应用,只不过这个应用极其复杂,内部塞了一个虚拟机(ART),并管理着所有其他应用。"
- 这个"复杂应用"的名字可以叫做 "Android 用户空间软件栈"。
- 它启动后,会创建
system_server等进程,然后不断孵化出新的进程来运行微信、淘宝、抖音等 App。 - 从 Linux 内核的视角看,这些 App 进程与普通的
grep进程没有本质区别 ------ 它们都拥有 PID、内存映射、文件描述符,只是它们内部的执行逻辑是 DEX 字节码。
二、操作系统架构对比
操作系统架构决定了系统的组织方式、模块间的通信方式以及系统扩展的难易程度。Linux 和 Android 虽然共用同一个内核,但它们的整体架构设计体现了不同的设计哲学和应用场景。
2.1 Linux 的经典分层架构
Linux 操作系统采用经典的模块化单内核架构,从底层硬件到用户应用通常划分为以下几个层次:
2.1.1 硬件层
包括 CPU、内存、磁盘、网卡、显卡、USB 控制器等物理设备。Linux 通过设备驱动与这些硬件交互。
2.1.2 内核层(Kernel Space)
这是 Linux 的核心,运行在 CPU 的特权模式(Ring 0)下,拥有对硬件的完全访问权限。内核层包含以下主要子系统:
- 进程调度器(Scheduler):负责决定哪个进程何时使用 CPU,实现多任务。Linux 采用完全公平调度器(CFS)。
- 内存管理器(Memory Manager):管理虚拟内存、分页、交换(swap)、内存映射等。
- 虚拟文件系统(VFS):为多种具体文件系统(EXT4、XFS、Btrfs 等)提供统一接口。
- 网络协议栈:实现 TCP/IP、UDP、socket 等网络功能。
- 设备驱动模型:支持动态加载/卸载驱动,抽象出字符设备、块设备、网络设备等。
- 系统调用接口(System Call Interface) :内核与用户空间之间的唯一合法通道。用户进程通过
open()、read()、write()、ioctl()等系统调用请求内核服务。
内核层还包括一些可选的模块,如 SELinux 安全模块、各种文件系统模块等。Linux 内核支持动态加载内核模块(.ko 文件),使得驱动和功能可以在不重新编译内核的情况下添加或移除。
2.1.3 系统调用接口与 C 库(glibc)
系统调用接口是内核暴露给用户空间的一组固定 API(约 300-400 个),如 fork()、exec()、mmap()。但这些系统调用使用起来比较底层,通常由 C 标准库(glibc) 进行封装。glibc 提供了 POSIX 兼容的接口(如 printf()、malloc()、pthread_create()),应用程序通常通过 glibc 间接调用系统调用。
注意:glibc 运行在用户空间,但它是用户程序与内核之间的重要桥梁。
2.1.4 用户空间(User Space)
用户空间运行着所有用户态的进程,每个进程拥有独立的地址空间(由内核通过内存管理单元 MMU 保护)。典型的用户空间组件包括:
- Shell(如 bash、zsh):命令行解释器,用户通过它执行命令和脚本。
- 系统守护进程(如 systemd、sshd、cron):后台服务,管理系统启动、网络连接、定时任务等。
- 桌面环境(如 GNOME、KDE):提供图形用户界面(GUI),包括窗口管理器、面板、文件管理器等。桌面环境运行在 X11 或 Wayland 显示服务器之上。
- 应用程序:Firefox、GCC、Nginx、Vim 等,它们以 ELF(可执行与可链接格式)二进制文件形式存在,直接调用 glibc 或直接进行系统调用。
2.1.5 Linux 架构的特点
- 宏内核(Monolithic Kernel):所有核心功能(调度、内存、文件、网络、驱动)都运行在内核态,性能高,但一个驱动的 bug 可能导致整个系统崩溃。
- 模块化:虽然内核是宏内核,但支持动态加载模块,一定程度上缓解了宏内核的耦合问题。
- 分层但非严格 :Linux 的层次之间并非完全隔离,例如用户空间程序可以通过
ioctl()直接与设备驱动通信,而不经过 VFS 层。 - 高度可配置:从嵌入式设备(几百 KB 内核)到超级计算机(支持数千 CPU),可以通过编译时选项裁剪内核功能。
下图概括了 Linux 架构的典型视图:

2.2 Android 的分层架构(概述)
Android 的架构并非完全从零设计 ,而是在 Linux 内核之上构建了一套全新的、面向移动设备的用户空间软件栈。其分层结构比传统 Linux 更加复杂,通常划分为以下五层(从下往上):
2.2.1 Linux 内核层
Android 使用经过定制修改的 Linux 内核(详见第一部分 1.1)。这一层提供:
- 进程调度、内存管理、网络协议栈等基础功能。
- 设备驱动:显示、触摸、摄像头、WiFi、蓝牙、音频等。
- Android 特有的内核扩展 :
- Binder 驱动:用于高效跨进程通信(IPC)。
- LowMemoryKiller:主动回收内存,杀死优先级低的进程。
- Wakelocks:电源管理机制,防止系统进入深度休眠。
- ashmem(匿名共享内存):允许进程间高效共享内存块。
- logger :内核日志驱动,供
logcat读取。
与通用 Linux 不同,Android 内核不包含 X11 驱动、很多服务器硬件驱动(如 RAID 卡)、以及标准 Linux 发行版常用的某些文件系统(如 XFS、Btrfs 的支持可能是可选的,但 Android 主要使用 EXT4/F2FS)。
2.2.2 硬件抽象层(HAL,Hardware Abstraction Layer)
HAL 是 Android 特有的一个用户空间层,位于内核驱动之上、系统服务之下。其目的是:
- 隔离硬件差异:设备厂商可以在不修改 Android 框架和内核的情况下,实现自己的硬件驱动逻辑。例如,不同厂商的摄像头传感器有不同的内部接口,但通过实现标准的 Camera HAL,上层 Camera Service 无需改动。
- 避免 GPL 传染:Linux 内核驱动要求开源(GPL 许可证),而 HAL 运行在用户空间,可以采用闭源实现,保护厂商的私有 IP。
典型的 HAL 模块包括:camera、audio、gps、sensors、wifi、bluetooth 等。每个 HAL 模块定义了一组标准接口(通常是 C 头文件),厂商提供动态链接库(.so)实现这些接口。
2.2.3 Android 运行时(ART)与原生库(Libraries)
这一层提供 Android 应用运行所需的核心库和运行环境。
原生库(Native Libraries,C/C++)
采用 Bionic libc(Android 定制版 C 库),它比 glibc 更小、更快,且针对移动 CPU 优化。其他关键库包括:
- SurfaceFlinger:负责合成所有应用窗口的图形内容,并输出到显示屏。它替代了 Linux 的 X11/Wayland。
- Media Framework(Stagefright):音视频播放、录制、编解码。
- SQLite:轻量级嵌入式数据库,用于本地数据存储。
- OpenGL ES:3D 图形 API(移动版 OpenGL)。
- Skia:2D 图形引擎(用于绘制 UI 元素)。
- WebKit / Chromium:浏览器渲染引擎(早期 Android 用 WebKit,后来换成 Chromium 的 Blink)。
- FreeType:字体渲染。
- SSL(BoringSSL):加密协议实现。
这些原生库以 .so 文件形式存在,可以被系统服务或 NDK 开发的 App 调用。
Android 运行时(ART)
ART 是 Android 应用运行的核心环境,替代了早期的 Dalvik 虚拟机。主要特点:
- 执行 DEX 字节码 :Java/Kotlin 源码编译成
.dex文件(或压缩成 APK 中的classes.dex),ART 将其转换为本地机器码执行。 - AOT(Ahead-Of-Time)与 JIT(Just-In-Time)混合编译:Android 7 开始,ART 采用解释 + JIT + 配置文件引导的 AOT,平衡安装速度、启动速度和运行性能。
- 垃圾回收(GC):自动管理内存,减轻开发者负担。
- 核心 Java 类库 :提供
java.*、javax.*、android.*等 API。
ART 本身作为一个 Linux 进程运行(通常由 zygote 派生),每个 Android 应用都在自己的 ART 实例(即一个独立的进程)中执行。
2.2.4 应用框架层(Application Framework)
这是 Android 提供的Java API 框架 ,供应用开发者调用。框架中的核心服务由 system_server 进程统一管理,包括:
- Activity Manager:管理 Activity 的生命周期、任务栈、应用进程。
- Window Manager:管理窗口(即应用界面)的创建、布局、层级、动画。
- Package Manager:负责 APK 的安装、卸载、权限解析、组件查询。
- Content Providers:提供跨应用的数据共享机制(如联系人、媒体库)。
- View System:UI 控件的绘制、事件分发、布局管理。
- Telephony Manager:管理电话功能(通话、数据网络、SIM 卡信息)。
- Resource Manager:访问资源(字符串、图片、布局文件等)。
- Location Manager:获取 GPS 或网络定位。
- Notification Manager:管理状态栏通知。
- Power Manager:控制设备的电源状态(屏幕亮度、休眠、唤醒)。
- Input Manager:处理触摸、按键等输入事件。
应用框架层以 Java 接口形式暴露 ,底层实现通常是通过 Binder IPC 调用系统服务(这些服务运行在 system_server 进程中)。
2.2.5 应用层(Applications)
最上层是用户直接交互的应用程序,包括:
- 系统内置应用:Home(桌面)、Phone(拨号)、Contacts(联系人)、Browser(浏览器)、Settings(设置)、Camera(相机)等。
- 第三方应用:从 Google Play 或其他渠道安装的 APK,如微信、淘宝、抖音。
- 特殊应用:Launcher(其实是 Home 应用)、输入法(IME)、壁纸应用等。
这些应用全部运行在沙盒环境中(每个应用有独立的 Linux UID 和 SELinux 上下文),相互隔离。
2.2.6 Android 架构的特点总结
- 分层明确:从内核到应用,每一层都有清晰的职责和接口,层间通过 Binder、系统调用、JNI 等方式通信。
- 以移动设备为中心:增加了 HAL、电源管理、低内存杀手等移动专用组件。
- 虚拟机为核心:应用不直接运行在 Linux 上,而是运行在 ART/Dalvik 虚拟机中,这使得 Android 拥有跨架构(ARM、x86、RISC-V)的能力。
- 进程模型独特 :系统服务(
system_server)负责管理所有应用进程,而 Linux 内核只负责底层的进程调度和内存隔离。这与传统 Linux 中 init 进程只管启动、不干预应用进程的行为完全不同。
下图展示了 Android 架构的典型视图:

2.3 Linux 架构与 Android 架构的直观对比
| 对比维度 | Linux 架构 | Android 架构 |
|---|---|---|
| 内核 | 标准 Linux 内核 | 定制 Linux 内核(增加 Binder、LMK、Wakelocks 等) |
| C 库 | glibc | Bionic libc(更小、更节能) |
| 图形系统 | X11 / Wayland | SurfaceFlinger + Skia/OpenGL ES |
| 应用运行环境 | 原生 ELF 二进制(直接运行) | ART/Dalvik 虚拟机(执行 DEX 字节码) |
| 应用框架 | 无统一框架(依赖各种库) | 完整的 Java API 框架(Activity、Service 等) |
| 硬件访问 | 直接通过内核驱动或 libusb | 通过 HAL 层,隔离硬件差异 |
| IPC 机制 | 管道、FIFO、消息队列、共享内存、Socket、D-Bus | Binder(主导)、Socket、共享内存 |
| 启动流程 | BIOS → Bootloader → Kernel → init → systemd → 服务/Shell | Boot ROM → Bootloader → Kernel → init → zygote → system_server → 应用 |
| 典型用户 | 开发者、服务器管理员、桌面用户 | 普通消费者(移动设备用户) |
三、内核层详细对比
内核层是操作系统的核心,负责管理硬件资源并为上层提供基础服务。Android 虽然使用了 Linux 内核,但在内核层面进行了大量定制,使其更适合移动设备。本章将从内核版本与优化策略、驱动支持与硬件抽象层(HAL)、以及 Binder IPC 三个维度深入对比 Android 与 Linux 的异同。
3.1 内核版本与优化策略(LowMemoryKiller, Wakelocks)
3.1.1 内核版本策略
| 对比项 | Linux | Android |
|---|---|---|
| 版本选择 | 紧跟主线,新内核发布后即可使用 | 基于 LTS(长期支持)版本,通常滞后 1-2 年 |
| 更新频率 | 每 2-3 个月一个新稳定版本 | 每个 Android 大版本对应一个固定的内核分支,只回移安全补丁 |
| 兼容性维护 | 较短时间内停止对旧版本的支持 | 长期维护同一内核版本(例如 Android 12 使用 Linux 4.14 或 4.19,持续多年) |
| 定制程度 | 少量补丁,主要是 bug 修复和驱动更新 | 大量 Android 特有补丁(如 Binder、LMK、Wakelocks、ashmem 等) |
原因分析:
- Android 设备数量庞大、硬件碎片化严重,频繁升级内核成本极高(需要厂商重新验证驱动和 HAL)。
- 稳定性压倒一切:Android 更倾向于使用经过大规模验证的 LTS 内核,而不是追求最新的内核特性。
- Google 通过 Android Common Kernel 分支维护一组 Android 专用补丁,并将其逐步 upstream 到主线 Linux 内核(例如 Binder 驱动已经在 Linux 5.x 主线中可用)。
3.1.2 低内存杀手(LowMemoryKiller, LMK)
背景:移动设备内存(RAM)资源非常有限(早期 Android 设备只有 512MB 甚至更少),且没有像 PC 那样的交换分区(swap)------因为闪存读写寿命和性能问题,Android 默认不启用 swap。因此,当内存不足时,系统必须主动终止某些进程来释放内存。
Linux 传统做法 :使用 OOM Killer(Out-Of-Memory Killer)。当内核发现内存极度不足且无法回收时,OOM Killer 会根据一个简单的"badness"分数选择杀死一个进程。这个分数主要基于进程占用的内存量,而不考虑进程的重要性(比如用户正在交互的前台应用 vs 后台服务)。这可能导致系统杀死关键进程(如电话应用),造成糟糕的用户体验。
Android 的改进 :引入 LowMemoryKiller(LMK),作为 Linux OOM Killer 的替代/补充。LMK 的特点:
- 基于进程优先级(oom_adj):Android 为每个进程分配一个优先级值(从 -17 到 +15),数值越大越容易被杀死。前台进程(正在与用户交互)的优先级最高(-17),可见进程次之,服务进程再次,缓存进程(空应用)最低(+15)。
- 水位线机制:系统预先定义多级内存阈值(如 6MB、8MB、12MB...)。当空闲内存低于某个阈值时,LMK 会杀死所有优先级高于该阈值的进程。例如,当空闲内存低于 12MB 时,杀死所有空进程;低于 8MB 时,杀死后台服务;低于 6MB 时,杀死可见进程(但不杀前台)。
- 可配置性:不同设备可以调整阈值和优先级映射,以适应不同的内存大小和使用场景。
从 Linux 内核 4.12 开始,Google 将 LMK 重新实现为 PSI(Pressure Stall Information) 基础上的 Android Low Memory Killer Daemon(lmkd),部分逻辑移到了用户空间,但核心思想一致。
对比总结:
| 特性 | Linux OOM Killer | Android LowMemoryKiller |
|---|---|---|
| 触发时机 | 内存完全耗尽,无法分配 | 内存低于预设阈值(更早介入) |
| 选择依据 | 内存占用大小为主 | 进程优先级(oom_adj) |
| 可预测性 | 较低,可能杀死重要进程 | 高,优先杀死不重要进程 |
| 用户体验 | 可能卡死或关键进程被杀 | 前台应用保持流畅 |
3.1.3 电源管理:Wakelocks 与 Suspend Blockers
背景 :移动设备依赖电池供电,电源管理是重中之重。Linux 的通用电源管理框架(如 ACPI/APM)主要针对服务器和桌面设计,允许系统进入 S3(挂起到内存)或 S4(挂起到磁盘)睡眠状态,但唤醒源有限(如键盘、网络唤醒)。而手机需要能够随时被各种事件唤醒 (来电、闹钟、消息推送),同时在不使用时深度休眠以节省电量。
Linux 传统做法 :系统通过 /sys/power/state 写入 mem 进入睡眠。任何内核线程或驱动程序都可以阻止睡眠(通过 pm_stay_awake / pm_relax),但缺乏细粒度的用户空间控制。
Android 的改进 :引入 Wakelocks 机制,最初是作为内核补丁,后来被 Android 维护在自己的内核分支中(主线 Linux 拒绝合并,因为 Linus Torvalds 认为 wakelocks 鼓励糟糕的编程习惯;但后来 Android 改用 suspend blockers 实现类似功能)。
Wakelocks 工作原理:
- Wakelock 是一种锁:用户空间的进程(如音乐播放器、下载服务)可以申请一个 wakelock,告诉内核"我正在做重要的事情,请不要进入深度睡眠"。
- 超时机制:wakelock 可以设置超时时间,超时后自动释放,防止进程忘记释放导致设备无法休眠。
- 引用计数:系统维护所有 wakelock 的引用计数,只有当计数为 0 时,才允许 suspend。
典型场景:
- 用户按电源键关闭屏幕后,系统尝试进入休眠。但如果正在播放音乐,音乐播放器持有
AudioMixwakelock,内核会保持唤醒直到播放完成或用户暂停。 - 网络下载任务:DownloadManager 持有
Networkwakelock,保证下载过程中 WiFi 不会断开,下载完成后释放。
Android 的电源状态机(简化版):
text
Awake (屏幕亮) → Early Suspend (屏幕暗,但 CPU 运行) → Suspend (深度睡眠)
↑ ↓
└────────── Wakeup event ──────────────┘
对比总结:
| 特性 | Linux 电源管理 | Android 电源管理 |
|---|---|---|
| 睡眠模式 | S3(Suspend to RAM) | 深度睡眠 + 早期挂起(early suspend) |
| 唤醒源 | 键盘、网络、RTC | 触摸、按键、RTC、modem(电话) |
| 用户空间控制 | 有限(通过 sysfs) | Wakelocks / Suspend blockers |
| 目标场景 | 服务器/桌面,关注节能但不要求即时唤醒 | 移动设备,要求快速响应事件且省电 |
3.2 驱动支持与硬件抽象层(HAL)
3.2.1 Linux 传统驱动模型
在 Linux 中,设备驱动程序通常以内核模块(.ko)的形式存在,运行在内核态。硬件厂商提供驱动源码(或二进制闭源模块),用户通过 insmod 或 modprobe 加载。驱动直接调用内核 API,拥有对硬件的完全控制权。
优点:
- 性能高:驱动在内核态,没有用户态切换开销。
- 功能完整:可以直接访问中断、DMA、I/O 端口。
缺点:
- 驱动 bug 可能导致内核崩溃(kernel panic),整个系统宕机。
- 驱动必须遵循 GPL 协议(如果静态链接到内核,则必须开源),商业厂商不愿开源核心 IP。
- 驱动与内核版本强耦合:每次内核升级,驱动可能需要重新编译甚至修改代码。
3.2.2 Android 的硬件抽象层(HAL)
Android 为了解决上述问题,引入了 硬件抽象层(HAL,Hardware Abstraction Layer)。HAL 位于用户空间,介于 Android 系统服务和 Linux 内核驱动之间。
HAL 的架构(以 Android 8.0 之后的 Treble 架构为例,但核心概念相同):
text
Android Framework (Java)
↓
System Service (e.g., CameraService, AudioService)
↓
HAL Interface (defined in .hal, using HIDL or AIDL)
↓
HAL Implementation (.so shared library, provided by vendor)
↓
Linux Kernel Driver (optional, can be simple or even bypassed)
↓
Hardware
HAL 的设计目标:
- 隔离硬件差异:上层系统服务不需要关心底层是哪个厂商的传感器、摄像头或音频 codec,只需要调用标准 HAL 接口。
- 允许闭源:HAL 运行在用户空间,不受 GPL 约束,厂商可以闭源实现,保护商业机密。
- 减少内核崩溃风险:HAL 中的 bug 只会导致该服务进程崩溃(如 camera server),可以被 watchdog 重启,不会导致整个系统 kernel panic。
- 简化内核驱动:内核驱动可以变得非常薄,只做最基本的数据传输和中断处理,复杂的逻辑上移到 HAL。
典型的 HAL 模块(每个模块对应一个硬件类型):
camera:相机 HAL,负责图像采集、参数设置、HDR 等。audio:音频 HAL,负责播放、录音、音效处理。sensors:加速度计、陀螺仪、磁力计等传感器。gps:GPS 定位。wifi:WiFi 芯片控制(部分功能在 wpa_supplicant 中)。bluetooth:蓝牙协议栈与硬件接口。power:电池电量、充电控制。light:背光、LED 指示灯。
Android 8.0 引入的 Treble 架构进一步将 HAL 与系统框架解耦,使得厂商可以独立更新 Android 系统而不需要重新适配 HAL(通过稳定的 HIDL / AIDL 接口)。
对比总结:
| 特性 | Linux 驱动模型 | Android HAL |
|---|---|---|
| 运行空间 | 内核态 | 用户态 |
| 崩溃影响 | 可能导致 kernel panic | 仅导致该服务进程崩溃 |
| 开源要求 | GPL(内核模块) | 可闭源 |
| 与内核版本耦合 | 强耦合 | 弱耦合(通过稳定接口) |
| 性能 | 高 | 略低(需跨用户态边界) |
| 维护成本 | 高(每次内核升级需适配) | 低(只要 HAL 接口不变) |
3.3 Binder IPC:Android 的"血管"
3.3.1 IPC 的背景需求
在操作系统中,不同进程之间需要交换数据,这就是进程间通信(IPC,Inter-Process Communication)。Linux 提供了多种 IPC 机制:管道(pipe)、FIFO、消息队列、信号量、共享内存、Socket、D-Bus 等。但这些机制在移动设备场景下存在不足:
- 性能问题:管道和 Socket 需要两次数据拷贝(用户 → 内核 → 用户);共享内存虽然快但需要同步机制(如信号量),使用复杂。
- 安全性不足:传统的 IPC 无法有效验证调用者的身份(PID/UID 可伪造或丢失)。
- 缺乏面向服务的模型 :Android 有大量系统服务(ActivityManager、WindowManager 等),需要一种客户端-服务器模型,并支持服务发现、线程池管理、异步调用等特性。
3.3.2 Binder 的设计与优势
Binder 是 Android 专门开发的一种 IPC 机制,从 Android 诞生之初就被广泛使用(甚至在早期版本中被称为 "OpenBinder",最初由 BeOS 开发,后被 Google 采用并大幅改进)。Binder 在 Android 系统中无处不在:应用调用系统服务、Activity 启动、Broadcast 发送、服务绑定等,底层都通过 Binder 通信。
核心特点:
- 基于 C/S 架构 :
- Client:发起 IPC 请求的进程(如应用进程)。
- Server :提供服务响应的进程(如
system_server中的 ActivityManagerService)。 - Service Manager :一个特殊的服务(
servicemanager进程),负责注册和查找服务(类似于 DNS)。所有服务在启动时向 Service Manager 注册一个名称,Client 通过名称获取服务的 Binder 引用。
- 一次数据拷贝 :
- Binder 利用内存映射(mmap) 技术,在进程间传递数据时,只需要一次拷贝(从 Client 用户空间拷贝到内核空间,然后映射到 Server 用户空间),而传统 Socket/管道需要两次拷贝。
- 具体实现:Binder 驱动在内核中维护一个数据缓冲区,Client 调用
ioctl(BINDER_WRITE_READ)将数据写入缓冲区,然后 Binder 驱动将缓冲区的内存区域映射到 Server 进程的地址空间(通过mmap设置),Server 可以直接读取,无需再拷贝。
- 安全性增强 :
- 每次 Binder 调用,内核驱动的 Binder 模块会自动记录调用者的 PID(进程ID) 和 UID(用户ID) ,并将这些信息传递给 Server。Server 可以根据这些信息做权限校验(如检查调用者是否拥有
android.permission.INTERNET)。 - 调用者身份无法伪造,因为 PID/UID 是由内核填写的,用户空间无法修改。
- 每次 Binder 调用,内核驱动的 Binder 模块会自动记录调用者的 PID(进程ID) 和 UID(用户ID) ,并将这些信息传递给 Server。Server 可以根据这些信息做权限校验(如检查调用者是否拥有
- 同步与异步 :
- 支持同步调用(Client 等待 Server 返回结果)和异步调用(Client 不等待,也称"oneway")。
- Binder 驱动内部维护线程池,可以并行处理多个请求。
- 对象引用传递 :
- Binder 支持传递Binder 对象引用,使得一个 Server 可以将另一个 Binder 服务的句柄传递给 Client,实现服务链。
3.3.3 Binder 在 Android 系统中的角色
Binder 被称为 "Android 系统的血管",这是非常形象的比喻。几乎所有系统服务和应用之间的跨进程交互都依赖 Binder:
- 应用启动 :Launcher 进程通过 Binder 调用 ActivityManagerService 的
startActivity()方法。 - 窗口管理:应用通过 Binder 调用 WindowManagerService 来添加、更新视图。
- 剪贴板:应用通过 Binder 调用 ClipboardService 读写剪贴板内容。
- 传感器:应用通过 Binder 调用 SensorService 注册传感器监听。
- 包管理:PackageManagerService 响应应用的查询、安装请求。
Binder 的通信流程(以应用启动为例):
text
[Launcher 进程] [system_server 进程]
| |
|---(1) Binder 调用 startActivity() --------->|
| (数据写入 Binder 驱动) |
| |
| |--(2) ActivityManagerService 处理请求
| |--(3) 创建新进程(通过 zygote fork)
| |
|<--(4) Binder 返回结果 ----------------------|
| (新进程的 Binder 引用) |
3.3.4 Binder 与 Linux 传统 IPC 的对比
| 特性 | 管道/FIFO | Socket | D-Bus | 共享内存 | Binder |
|---|---|---|---|---|---|
| 数据拷贝次数 | 2 | 2 | 2 | 0(需同步) | 1 |
| 面向服务模型 | 否 | 部分(RPC 需自建) | 是 | 否 | 是 |
| 身份验证 | 无 | 有(需额外实现) | 弱(可伪造) | 无 | 强(内核提供) |
| 异步支持 | 需自行实现 | 有 | 有 | 无 | 内置 |
| 性能 | 低 | 中 | 中 | 高(但复杂) | 高 |
| 典型用途 | 父子进程简单通信 | 网络通信、本地 | 桌面 Linux 服务 | 大数据块传递 | Android 所有系统服务 |
3.3.5 Binder 在主线 Linux 中的现状
由于 Binder 的优秀设计,Google 已经将其提交到主线 Linux 内核 。从 Linux 内核 3.19 开始,Binder 驱动成为内核的一部分(drivers/staging/android/binder.c),并在后续版本中不断改进。这使得其他操作系统(如 Linux 发行版)也可以使用 Binder 作为高性能 IPC 方案。
四、应用层与运行环境对比
应用层是用户直接感知的部分,运行环境则决定了应用程序如何执行、如何与系统交互。Linux 和 Android 在这一层的差异最为显著:Linux 运行传统的 ELF 二进制文件,依赖 glibc 和 X11;而 Android 运行 DEX 字节码于 ART 虚拟机之上,使用 Bionic libc 和 SurfaceFlinger,并采用独特的 APK 打包与沙盒机制。
4.1 Linux 应用层特征
4.1.1 应用程序格式:ELF 二进制
Linux 上的可执行文件采用 ELF(Executable and Linkable Format) 格式。一个典型的 Linux 应用程序(如 bash、nginx、firefox)是直接编译成机器码的二进制文件,与具体的 CPU 架构(x86、ARM、RISC-V 等)绑定。
- 编译与链接:开发者用 C/C++/Rust/Go 等语言编写源码,通过编译器(如 GCC、Clang)生成目标文件,再链接系统库(如 glibc)最终得到 ELF 文件。
- 执行方式 :用户在 Shell 中输入命令,Shell 调用
fork()创建新进程,然后调用execve()系统调用加载 ELF 文件到内存,并跳转到入口点开始执行。 - 动态链接 :大多数 ELF 程序动态链接共享库(
.so文件)。程序启动时,动态链接器(ld-linux.so)解析依赖,将需要的共享库加载到进程地址空间,并解析符号。 - 位置无关代码(PIC):共享库通常编译为 PIC,以便在内存中任意地址加载,支持地址空间布局随机化(ASLR)等安全机制。
4.1.2 C 库:glibc
glibc(GNU C Library) 是 Linux 上最常用的 C 标准库实现,它提供了:
- POSIX API :
open()、read()、write()、fork()、pthread_create()等系统调用的封装。 - 标准 C 函数 :
printf()、malloc()、strlen()、memcpy()等。 - 国际化支持 :
locale、宽字符、gettext。 - 网络功能 :
socket()、gethostbyname()等。
glibc 的特点:
- 重量级:功能全面,体积较大(几 MB),包含大量针对服务器和桌面优化的代码。
- 完全开源:LGPL 许可证,允许商业软件动态链接。
- 高度兼容:保证向后兼容,几十年前编译的 ELF 程序通常仍能在新系统上运行。
注意:某些轻量级 Linux 发行版(如 Alpine Linux)使用 musl libc 代替 glibc,以减小体积和提高安全性。但绝大多数桌面和服务器发行版使用 glibc。
4.1.3 图形系统:X11 / Wayland
Linux 桌面环境的图形系统经历了从 X11 到 Wayland 的演进。
X11(X Window System):
- 经典的 C/S 架构:X Server 管理显示硬件和输入设备,X Client(应用程序)通过 socket 与 X Server 通信,发送绘图请求。
- 网络透明:应用程序可以运行在远程机器上,显示在本地屏幕(但现代应用很少使用此特性)。
- 缺点:设计古老(1980 年代),代码臃肿,安全模型弱(任何客户端可以监听其他客户端的事件),渲染性能受限于多次上下文切换。
Wayland:
- 新一代显示服务器协议,设计更简单、更现代。
- 直接渲染:客户端直接通过 EGL/OpenGL 渲染到屏幕缓冲区,合成器(Compositor)负责合成窗口。
- 无网络透明:默认不支持远程显示(可通过第三方工具实现)。
- 逐渐取代 X11:Ubuntu、Fedora 等主流发行版已默认使用 Wayland。
无论 X11 还是 Wayland,桌面环境(如 GNOME、KDE)提供窗口管理器、面板、文件管理器、应用菜单等组件,共同构成用户界面。
4.1.4 软件包管理
Linux 发行版通过包管理器来安装、更新、卸载软件。常见的包管理器包括:
- Debian 系 :
apt(底层dpkg),使用.deb包。 - Red Hat 系 :
yum/dnf(底层rpm),使用.rpm包。 - Arch 系 :
pacman,使用.pkg.tar.zst包。 - 通用打包格式:Snap、Flatpak、AppImage(跨发行版)。
包管理器自动处理依赖关系:安装 A 时,如果 A 需要 B 库,包管理器会从仓库中下载并安装 B。仓库中的软件包经过发行版维护者的测试和签名,保证安全性和兼容性。
4.1.5 用户空间典型组件
一个典型的 Linux 系统(桌面版)包含以下用户空间组件:
- Init 系统 :通常是
systemd(或OpenRC、runit),负责启动守护进程、管理系统服务。 - Shell :
bash、zsh、fish等,用户通过终端与系统交互。 - 核心工具集 :GNU Coreutils(
ls、cp、mv、rm、cat、grep等)。 - 网络服务 :
sshd(远程登录)、cron(定时任务)、NetworkManager(网络管理)。 - 桌面环境 :
GNOME、KDE Plasma、XFCE等,提供图形登录管理器(如 GDM)、窗口管理器、系统设置等。
4.2 Android 应用层特征(ART/Dalvik, Bionic libc, SurfaceFlinger, APK)
Android 的应用层与运行环境与 Linux 截然不同,可以说是 "披着 Linux 内核外衣的另一个世界"。
4.2.1 应用程序格式:APK 与 DEX 字节码
Android 应用程序打包为 APK(Android Package Kit) 文件,本质上是一个 ZIP 压缩包,包含以下内容:
classes.dex:Java/Kotlin 源码编译成的 Dalvik Executable 字节码(一个或多个 DEX 文件)。AndroidManifest.xml:应用清单文件,声明包名、权限、组件(Activity、Service、Content Provider、Broadcast Receiver)、所需系统版本等。- 资源文件 :布局 XML、图片、字符串等(
res/目录)。 - 原生库 :可选的
lib/armeabi-v7a/、lib/arm64-v8a/、lib/x86/等子目录,包含供 NDK 调用的.so文件。 - META-INF:签名和校验信息。
DEX 字节码 vs ELF 机器码:
- DEX 是面向虚拟机的中间表示,不直接与 CPU 架构绑定。同一个 APK 可以在 ARM、x86、RISC-V 设备上运行(只要该平台有 ART 实现)。
- ELF 机器码是直接针对特定 CPU 架构的二进制指令,无法跨架构运行(除非通过模拟器或二进制翻译)。
4.2.2 运行时环境:Dalvik → ART
Dalvik 虚拟机(Android 4.4 及之前):
- 采用 JIT(Just-In-Time)编译:应用启动时,Dalvik 解释执行 DEX 字节码;当某段代码被频繁执行时,JIT 将其编译成本地机器码并缓存,以提高后续执行速度。
- 缺点:应用首次启动较慢(因为要解释执行),占用更多内存(JIT 缓存)。
ART(Android Runtime)(Android 5.0 引入,逐步取代 Dalvik):
- AOT(Ahead-Of-Time)预编译 :在应用安装时,ART 将 DEX 字节码编译成本地机器码(ELF 格式的
.oat文件)。运行时直接执行本地码,启动速度快。 - 缺点:安装时间变长,占用更多存储空间(预编译后的代码体积增大)。
- 混合模式 (Android 7.0 引入):结合 JIT 和 AOT。应用首次安装时不预编译,运行时 JIT 编译;设备空闲时,后台守护进程
dex2oat根据 JIT 收集的热点信息进行 AOT 编译,平衡启动速度、安装时间和存储空间。 - 垃圾回收(GC)改进 :ART 的 GC 从 Dalvik 的
mark-sweep改为 并发复制(CC,Concurrent Copying),减少了 GC 停顿时间。
ART 与 Linux 进程的关系:
- ART 本身作为
zygote进程的一部分启动。zygote是一个特殊的 Android 进程,预加载了常用的类库和资源,然后进入休眠。当需要启动一个新应用时,system_server通过 socket 通知zygote,zygote调用fork()创建自身副本,然后在子进程中加载应用的 APK 并执行ActivityThread.main()。 - 每个 Android 应用进程都包含一个 ART 虚拟机实例,负责执行该应用的 DEX 代码。
4.2.3 C 库:Bionic libc
Bionic libc 是 Google 专门为 Android 开发的 C 标准库,与 glibc 相比有以下特点:
- 体积小 :Bionic 被设计为尽可能精简,以适应移动设备有限的存储空间(早期 Android 设备 ROM 只有几百 MB)。例如,Bionic 的
libc.so大小约为 500KB,而 glibc 的libc.so.6约为 2MB。 - 轻量级线程实现:Bionic 的 pthread 实现更轻量,创建线程的开销更小。
- 不支持完整 POSIX:Bionic 省略了一些移动设备不需要的 POSIX 特性(如某些 locale 功能、老旧的信号处理函数)。
- 许可证:BSD 许可证(部分代码来自 BSD 的 libc),允许闭源链接,商业友好。
- 与 glibc 不兼容:为 Linux 编译的 glibc 程序无法直接在 Android 上运行(除非通过 libhybris 等兼容层)。
- 内置 Android 特有扩展 :如
android_get_control_socket()、property_get()等。
为什么不用 glibc?
- 许可证:glibc 是 LGPL,虽然允许动态链接,但 Google 希望避免任何可能的许可证争议。
- 体积:glibc 太大,不适合早期移动设备。
- 性能:Bionic 针对 ARM 和移动场景做了优化,某些函数比 glibc 更快。
- 控制:Google 希望拥有对底层库的完全控制权,以便快速修复 bug 和添加新特性。
4.2.4 图形系统:SurfaceFlinger
Android 不使用 X11 或 Wayland,而是采用自己的 SurfaceFlinger 作为图形合成服务。
SurfaceFlinger 的职责:
- 接收来自多个应用程序的表面(Surface),每个 Surface 对应一个应用窗口的缓冲区(包含像素数据)。
- 根据 Z 轴顺序、透明度、动画等参数,将所有 Surface 合成为一个最终的帧缓冲区。
- 将合成后的帧发送到显示硬件(通过
framebuffer或DRM/KMS)。
与 X11/Wayland 的主要区别:
| 特性 | X11 / Wayland | SurfaceFlinger |
|---|---|---|
| 客户端渲染 | 客户端自己绘制到窗口,Server 合成 | 客户端通过 Canvas 或 OpenGL ES 绘制到 Surface |
| 缓冲区管理 | 通常由窗口管理器或合成器管理 | 通过 BufferQueue 机制,生产-消费模型 |
| 跨进程通信 | Socket(X11)或 Wayland 协议 | Binder + 共享内存 |
| 硬件加速 | 支持(通过 DRI/DRM) | 深度集成 OpenGL ES / Vulkan 和硬件合成器(HWC) |
| 网络透明 | X11 支持,Wayland 不支持 | 不支持(移动设备不需要) |
BufferQueue 是 SurfaceFlinger 的核心机制:
- 应用(生产者)通过
dequeueBuffer()获取一个空闲缓冲区,绘制内容,然后queueBuffer()将其放入队列。 - SurfaceFlinger(消费者)通过
acquireBuffer()取出缓冲区,合成后releaseBuffer()放回。 - 这种模型允许应用以最高 60fps(或 90/120fps)的速度连续提交帧,SurfaceFlinger 在垂直同步(VSYNC)信号触发时进行合成。
4.2.5 应用沙盒与权限模型
Android 每个应用运行在独立的 Linux 用户 ID(UID)下,并拥有自己的私有目录(/data/data/<package>/)。这提供了操作系统级别的隔离:
- 文件隔离:应用 A 无法直接读取应用 B 的私有目录(权限拒绝)。
- 进程隔离 :不同 UID 的进程之间默认不能通过
ptrace或信号互相干扰(受 Linux 权限控制)。 - SELinux 强化 :每个应用被分配一个独特的 SELinux 上下文(
untrusted_app或isolated_app),即使进程拥有 root 权限(实际上 Android 应用不以 root 运行),SELinux 策略也会阻止其访问非授权资源。
权限声明与运行时授权:
- 应用在
AndroidManifest.xml中声明所需权限(如android.permission.CAMERA)。 - Android 6.0(API 23)开始引入运行时权限:敏感权限(相机、位置、存储等)必须在应用运行时动态请求,用户可以选择允许或拒绝。
- 权限检查由
PackageManager和PermissionController服务在 Binder 调用时进行(利用 Binder 自动传递的 UID)。
4.2.6 应用组件模型
Android 应用由四大组件构成,这与传统 Linux 应用的单一入口完全不同:
| 组件 | 描述 | 类似概念 |
|---|---|---|
| Activity | 用户界面屏幕,负责与用户交互 | 窗口 + 逻辑 |
| Service | 后台运行任务(无界面),如音乐播放、下载 | 守护进程(但轻量) |
| Content Provider | 管理结构化数据,支持跨应用访问 | 数据库服务器 |
| Broadcast Receiver | 接收系统或应用广播(如电池低电、网络变化) | 事件监听器 |
这些组件在 AndroidManifest.xml 中声明,并由 ActivityManager 统一管理生命周期。组件之间的调用通过 Intent(意图)完成,底层经由 Binder 跨进程通信。
4.2.7 应用分发与安装
- 分发渠道:Google Play 商店是主要渠道,厂商也可能有自己的应用商店(如华为 AppGallery、小米应用商店)。用户也可以侧载(sideload)APK 文件。
- 安装过程 :
- 用户触发安装(商店下载或打开 APK 文件)。
PackageManager解析 APK,校验签名(确保未被篡改且来源可信)。- 将 DEX 代码优化/编译(通过
dex2oat)。 - 将 APK 复制到
/data/app/,解压 native 库到/data/app/<package>/lib/。 - 在
/data/data/<package>/创建应用的私有数据目录。 - 在系统中注册组件信息,以便
ActivityManager等可以启动该应用。
- 更新与卸载:更新时下载新版 APK,签名必须与旧版一致(否则拒绝安装)。卸载时删除对应目录和系统注册信息。
4.3 Linux 与 Android 应用层对比总结表
| 特性 | Linux | Android |
|---|---|---|
| 可执行格式 | ELF(机器码) | APK(包含 DEX 字节码) |
| 运行时 | 直接执行机器码 | ART / Dalvik 虚拟机 |
| C 库 | glibc(或 musl) | Bionic libc |
| 图形系统 | X11 / Wayland + 桌面环境 | SurfaceFlinger + 无传统桌面 |
| 应用模型 | 单一入口(main 函数) | 四大组件(Activity、Service 等) |
| 进程隔离 | 传统 Linux UID/GID 权限 | UID + SELinux 沙盒 |
| 权限模型 | 用户级(安装时决定,无动态) | 运行时权限(用户可动态授予/撤销) |
| 包管理 | 包管理器(apt、yum 等) | PackageManager + 应用商店 |
| 典型应用语言 | C/C++、Python、Go、Rust 等 | Java、Kotlin(也可用 C++ 通过 NDK) |
| 用户界面 | 窗口化、多任务桌面 | 触摸屏、全屏应用为主,多任务卡片 |
五、文件系统与存储管理对比
文件系统负责组织、存储和检索数据,是操作系统中至关重要的组成部分。Linux 和 Android 在文件系统的选择、分区布局、存储管理策略以及安全隔离方面存在显著差异,这些差异反映了它们各自的应用场景和设计目标。
5.1 Linux 文件系统
5.1.1 支持多种文件系统类型
Linux 以其对多种文件系统的广泛支持而著称,这得益于其虚拟文件系统(VFS,Virtual File System) 抽象层。VFS 为用户空间提供了统一的 open()、read()、write() 等系统调用接口,而底层可以挂载不同的具体文件系统。Linux 支持的文件系统包括但不限于:
- EXT 家族:EXT2、EXT3、EXT4。EXT4 是目前大多数 Linux 发行版的默认文件系统,支持大文件(最大 16TB)、区段(extents)、延迟分配、纳秒时间戳等特性。
- XFS:高性能的 64 位日志文件系统,特别适合大文件和大容量存储(最大支持 8EB),常用于服务器和高端工作站。
- Btrfs(B-tree 文件系统):支持写时复制(CoW)、快照、压缩、子卷、校验和等先进特性,被视为 EXT4 的潜在替代者。
- ZFS:最初由 Sun 开发,支持海量存储、数据完整性校验、快照、克隆、RAID-Z 等,但因其许可证与 Linux 内核不兼容(CDDL vs GPL),通常需要通过外部模块加载。
- F2FS(Flash Friendly File System):专门为 NAND 闪存设计,优化了随机写入性能,减少写放大,常用于嵌入式设备和部分 Android 设备(见 5.2.1)。
- 其他 :FAT32、exFAT、NTFS(通过
ntfs-3g)、ISO 9660(光盘)、网络文件系统(NFS、CIFS)等。
5.1.2 文件系统层次结构(FHS)
Linux 遵循文件系统层次结构标准(FHS,Filesystem Hierarchy Standard),规定了目录的用途和布局。典型的 Linux 目录结构如下:
| 目录 | 用途 |
|---|---|
/ |
根目录,所有文件和目录的起点 |
/bin |
基本用户命令(如 ls、cp),在单用户模式下可用 |
/boot |
启动加载器文件(内核、initrd) |
/dev |
设备文件(如 /dev/sda、/dev/tty) |
/etc |
系统配置文件 |
/home |
普通用户的家目录 |
/lib |
共享库和内核模块 |
/media |
可移动介质挂载点(如 USB 盘) |
/mnt |
临时挂载点 |
/opt |
可选的应用软件包 |
/proc |
虚拟文件系统,提供进程和内核信息 |
/root |
root 用户的家目录 |
/run |
运行时变量数据(如 PID 文件) |
/sbin |
系统管理命令(如 fdisk、mount) |
/sys |
虚拟文件系统,导出内核对象和设备信息 |
/tmp |
临时文件(重启后可能被清空) |
/usr |
用户级软件和共享数据(类似 / 的子层次) |
/var |
可变数据(日志、缓存、邮件、打印队列) |
5.1.3 挂载与磁盘管理
Linux 采用挂载(mount) 的方式将文件系统附加到根目录树的某个节点。管理员可以灵活地将不同分区、磁盘、网络共享挂载到任意目录。
- 分区表:传统使用 MBR(主引导记录),现代系统使用 GPT(GUID 分区表)。
- 常见分区方案 :
- 简单方案:一个
/分区 + 一个swap分区(或 swap 文件)。 - 服务器方案:
/boot、/、/home、/var、/tmp等分开,以便隔离日志和用户数据,防止某个分区写满导致系统故障。
- 简单方案:一个
- 挂载命令 :
mount /dev/sda2 /mnt/data,卸载使用umount。 - 自动挂载 :通过
/etc/fstab配置文件,系统启动时自动挂载指定分区。 - 逻辑卷管理(LVM):提供动态调整分区大小、快照等高级功能。
5.1.4 权限模型
Linux 使用传统的UGO(User-Group-Other)权限模型,每个文件或目录关联以下属性:
- 拥有者(User):通常是创建文件的用户。
- 组(Group):文件所属的组。
- 其他(Other):除拥有者和组成员之外的其他用户。
权限位包括:
- 读(r):查看文件内容或列出目录。
- 写(w):修改文件或在目录中创建/删除文件。
- 执行(x):执行文件(或进入目录)。
此外还有特殊权限 :SUID(设置用户 ID)、SGID(设置组 ID)、Sticky Bit(粘滞位,如 /tmp 目录防止用户删除他人文件)。
访问控制列表(ACL) 扩展了 UGO 模型,允许为多个用户或组设置精细权限。SELinux 或 AppArmor 提供强制访问控制(MAC),进一步限制进程的权限(见第六部分安全机制)。
5.1.5 存储管理与性能优化
- 交换空间(swap):Linux 允许使用磁盘分区或文件作为虚拟内存的扩展。当物理内存不足时,内核将不常用的页面换出到 swap。但 swap 会增加磁盘 I/O,影响性能。
- 缓存与缓冲:Linux 会利用空闲内存作为页面缓存(page cache)和缓冲区(buffer cache),加速文件 I/O。内存紧张时会自动回收。
- 日志(journaling):EXT4、XFS 等文件系统使用日志记录元数据变更,以在意外断电后快速恢复一致性。
- 磁盘调度器:CFQ、Deadline、Noop、BFQ 等,用于优化 I/O 请求排序,适应不同负载(机械硬盘 vs SSD)。
5.2 Android 文件系统(EXT4/F2FS,分区,沙盒)
Android 基于 Linux 内核,但其文件系统布局和存储管理策略针对移动闪存设备进行了深度定制。
5.2.1 文件系统选择:EXT4 与 F2FS
Android 主要使用两种文件系统:
EXT4:
- Android 早期版本(2.x 至 6.x 左右)默认使用 EXT4 作为
/system、/data、/cache等分区的主要文件系统。 - 成熟稳定,广泛支持,但在随机写入(小文件、大量并发 I/O)场景下对 NAND 闪存不够友好,容易产生写放大(write amplification)和垃圾回收开销。
F2FS(Flash Friendly File System):
- 由三星开发,专门为 NAND 闪存设计,从 Linux 内核 3.8 开始进入主线。
- Android 从 4.4(KitKat)开始尝试支持 F2FS,近年来成为许多设备(尤其是中高端)的首选,特别是用于
/data分区。 - 设计特点 :
- 日志结构化(Log-structured):将数据顺序写入空闲区域,减少随机写入。
- 多头部日志(Multi-head logging):提高并发写入性能。
- 自适应擦除块管理:减少写放大,延长闪存寿命。
- 快速 mount:检查点(checkpoint)机制使得挂载几乎瞬间完成。
- 压缩支持(F2FS 压缩):节省存储空间。
- 实际性能:在随机写入、小文件操作上,F2FS 通常优于 EXT4,更适合应用安装、数据库操作、应用缓存等 Android 典型场景。
注意:并非所有 Android 设备都使用 F2FS。厂商根据芯片平台和测试结果选择。许多设备采用混合策略:
/system(只读)使用 EXT4,/data(用户数据)使用 F2FS。
5.2.2 固定分区布局
与 Linux 灵活的挂载点不同,Android 采用固定的分区布局,这些分区在设备出厂时由厂商划分,普通用户无法修改。常见的分区(以 ARM 设备为例):
| 分区名称 | 挂载点 | 文件系统 | 内容描述 |
|---|---|---|---|
boot |
不挂载 | 原始镜像 | 内核 + 内存盘(initramfs),用于启动 |
system |
/system |
EXT4 / F2FS / erofs | 操作系统只读文件(框架、系统应用、库)。Android 10 以后可支持动态分区 |
system_ext |
/system_ext |
EXT4 / erofs | 系统扩展分区(存放厂商定制系统组件) |
product |
/product |
EXT4 / erofs | 产品特定系统组件 |
vendor |
/vendor |
EXT4 / erofs | 厂商提供的专有二进制(HAL 库、固件、驱动) |
odm |
/odm |
EXT4 / erofs | 设备制造商定制覆盖 |
data |
/data |
F2FS / EXT4 | 用户数据分区:应用、设置、媒体、数据库 |
cache |
/cache |
EXT4 / F2FS | 缓存分区(OTA 更新包、临时文件),可被系统清除 |
recovery |
不挂载 | 原始镜像 | 恢复模式内核和工具 |
misc |
不挂载 | 原始 | 杂项信息(如启动指示标志) |
persist |
/persist |
EXT4 | 持久化数据(如校准信息、WiFi MAC),恢复出厂设置不清除 |
metadata |
不挂载 | EXT4 | 存储加密元数据(用于文件级加密) |
userdata(旧称) |
同 /data |
- | 同 data |
动态分区(Android 10+):
- 传统分区大小固定,浪费空间或导致空间不足。动态分区允许将
system、vendor、product等分区合并为一个超级分区(super),使用逻辑卷管理,可以在 OTA 更新时调整大小。 - 在设备上,超级分区由
dm-linear设备映射,对用户透明。
5.2.3 只读分区与系统保护
/system、/vendor等系统分区通常以**只读(ro)**方式挂载,防止用户或恶意软件篡改系统文件。- 验证启动(Verified Boot):设备启动时,引导加载程序逐级验证内核、系统分区的完整性(通过哈希树和签名),如果检测到篡改,设备可能拒绝启动或以只读模式进入恢复模式。
- 系统更新:OTA 更新时,系统会使用新的系统镜像覆盖只读分区(或通过动态分区重写逻辑卷),然后重启。
5.2.4 应用沙盒与存储隔离
Android 的核心安全特性之一是应用沙盒,基于 Linux 的 UID 机制和 SELinux 实现:
- 每个应用唯一的 UID:安装时,系统分配一个独特的 Linux 用户 ID(从 10000 开始)。该应用的所有进程都以该 UID 运行。
- 私有数据目录 :每个应用在
/data/data/<package_name>/下拥有一个私有目录,权限设置为rwx------(仅所有者可读/写/执行)。其他 UID 的进程(包括其他应用)无法访问该目录。 - 原生代码库目录 :
/data/app/<package_name>/lib/存放应用的原生 .so 文件,同样受 UID 保护。 - 外部存储的"假隔离" :早期 Android 使用
sdcard(FAT32 格式,无权限)导致应用可任意访问外部存储文件。Android 4.4 引入存储访问框架(SAF,Storage Access Framework) ,并通过每应用目录 (/sdcard/Android/data/<package>/)提供逻辑隔离。Android 10 进一步引入分区存储(Scoped Storage) :应用只能直接访问自己的外部存储目录(/sdcard/Android/data/<package>/)和公共媒体目录(通过MediaStoreAPI 访问照片、音乐等),不能直接遍历整个外部存储。
沙盒的好处:
- 恶意应用无法窃取其他应用的私有数据(如聊天记录、游戏存档)。
- 即使系统服务(如
system_server)也无法随意读取应用私有数据(受 SELinux 限制)。 - 卸载应用时,系统自动删除
/data/data/<package>和/sdcard/Android/data/<package>下的所有数据。
5.2.5 存储性能优化
由于移动设备使用 eMMC 或 UFS 闪存,且没有传统交换分区(swap),Android 采取了以下优化措施:
- 不使用 swap:闪存的随机写入寿命有限且速度相对慢,Android 默认不启用 swap。当内存不足时,依赖 LowMemoryKiller 杀死进程而非换出页面。
- Trim / Discard :Android 定期对闪存发送 TRIM 命令(通过
fstrim工具),通知闪存控制器哪些块已不再使用,以便提前擦除,提高后续写入性能。 - 异步 I/O :框架层使用
AsyncTask、IntentService等避免阻塞 UI 线程;底层使用 Linux 的aio或 libc 的缓冲。 - 数据库优化 :SQLite 是 Android 广泛使用的嵌入式数据库,针对闪存优化了
PRAGMA设置(如journal_mode=WAL)。 - 分区缓存 :
/cache分区用于存储 OTA 包、日志、下载的临时文件,避免消耗/data空间。 - 文件加密 :Android 支持全盘加密(FBE,File-Based Encryption) 和文件级加密(FBE,File-Based Encryption)(Android 7.0+),每个文件使用不同密钥加密,对性能有影响但提供了安全性。现代设备使用内联加密硬件(inline encryption)加速。
5.2.6 外部存储(SD 卡)的处理
- 可移除存储:Android 支持 microSD 卡(但许多设备已取消)。SD 卡通常格式化为 exFAT 或 FAT32,以便在 PC 上读取。
- 适配存储(Adoptable Storage) (Android 6.0+):允许将 SD 卡格式化为内部存储的一部分(加密,使用 EXT4 或 F2FS),与
/data合并。但这样 SD 卡无法在其他设备上读取,且取出会导致应用崩溃。 - 便携存储(Portable Storage) :传统模式,SD 卡作为外部共享存储,应用通过
MediaStore或 SAF 访问。
5.3 Linux 与 Android 文件系统对比总结表
| 特性 | Linux | Android |
|---|---|---|
| 主要文件系统 | EXT4、XFS、Btrfs 等 | EXT4、F2FS(/data 常用)、erofs(系统只读分区) |
| 目录标准 | FHS(灵活挂载点) | 固定分区布局(system, data, vendor 等) |
| 只读系统分区 | 可选(通常 / 可写) | 强制(/system, /vendor 只读,验证启动) |
| 应用数据隔离 | 传统 UGO 权限,依赖用户家目录 | 基于 UID 的沙盒 + SELinux,每应用私有目录 |
| 外部存储 | 任意挂载,全局可访问(需权限) | 分区存储(Scoped Storage),应用间隔离 |
| 交换分区/文件 | 常用(swap) | 不使用(依赖 LMK) |
| TRIM 支持 | 手动或定期(fstrim) | 自动定期执行 |
| 加密 | 可选(LUKS、dm-crypt) | 全盘加密(FDE)或文件级加密(FBE),默认启用 |
| 日志与性能 | 日志文件系统(EXT4 journal 等) | F2FS 优化随机写入,ext4 也可用,禁用 swap |
| 存储空间管理 | 分区灵活,LVM 可动态调整 | 动态分区(Android 10+),但传统分区固定 |
六、安全机制对比
安全性是操作系统的基石。Linux 作为多用户服务器和桌面系统,拥有完善的权限管理和强制访问控制机制;Android 则在继承 Linux 安全特性的基础上,针对移动设备的特点进行了大量强化,形成了多层防御体系。
6.1 Linux 安全模型(DAC, SELinux)
6.1.1 自主访问控制(DAC,Discretionary Access Control)
DAC 是 Linux 传统的权限模型,其核心思想是:文件或资源的拥有者可以自主决定谁可以访问它。
基本要素:
- 用户(User):每个进程和文件都关联一个用户 ID(UID)。超级用户 root 拥有最高权限(UID=0)。
- 组(Group):用户可以属于一个或多个组(GID),用于批量授权。
- 权限位(Permission Bits):每个文件有 9 个基本权限位(读 r、写 w、执行 x),分别对应拥有者(user)、组(group)、其他(other)。
例如,-rw-r--r-- 表示:拥有者可读可写,同组用户只读,其他用户只读。
特殊权限:
- SUID(Set User ID) :当可执行文件设置了 SUID 位,任何用户运行该文件时,进程的有效 UID 变为文件拥有者的 UID(通常是 root)。例如
/bin/passwd允许普通用户修改密码文件。 - SGID(Set Group ID):类似,但针对组。
- Sticky Bit :作用于目录时,只有文件拥有者才能删除目录中的文件(例如
/tmp目录的drwxrwxrwt中的t位)。
DAC 的局限性:
- root 权力过大:一旦攻击者获得 root 权限,可以绕过所有 DAC 检查,任意访问系统资源。
- 程序漏洞的扩散:一个有漏洞的进程(如 Web 服务器)如果以 root 运行,攻击者可以完全控制系统;即使以普通用户运行,也可能读取该用户拥有的所有文件。
- 细粒度不足:DAC 只能基于 UID/GID 和三个基本权限,无法对单个操作(如只读某个文件但不可写)做更精细的控制。
6.1.2 强制访问控制(MAC,Mandatory Access Control)------ SELinux
为了弥补 DAC 的不足,Linux 引入了 MAC 机制。其中最著名的是 SELinux(Security-Enhanced Linux),由美国国家安全局(NSA)开发,自 Linux 2.6 起集成到主线内核。
核心思想 :系统管理员定义全局的安全策略,即使是文件拥有者也无法绕过 。每个进程和对象(文件、套接字、IPC 等)都有一个安全上下文(security context),内核在每次访问请求(如 open、read、write)时都会检查策略,决定是否允许。
SELinux 的基本概念:
| 概念 | 说明 | 示例 |
|---|---|---|
| 主体(Subject) | 发起访问的进程 | httpd_t |
| 对象(Object) | 被访问的资源 | /var/www/html/index.html(类型 httpd_sys_content_t) |
| 类型(Type) | 主体或对象的标签 | httpd_t, shadow_t |
| 域(Domain) | 进程的类型 | 同上 |
| 角色(Role) | 进程或用户的角色(用于 RBAC) | user_r, sysadm_r |
| 用户(SELinux User) | SELinux 用户身份 | system_u, user_u |
策略规则格式:
text
allow source_type target_type : class { permissions };
例如:
text
allow httpd_t httpd_sys_content_t : file { read getattr };
这条规则允许类型为 httpd_t 的进程对类型为 httpd_sys_content_t 的文件执行 read 和 getattr 操作。
SELinux 工作模式:
- Enforcing(强制):策略生效,违规操作被拒绝并记录日志。
- Permissive(宽容):策略不生效,只记录违规日志(用于调试)。
- Disabled:完全关闭。
典型应用 :在 CentOS/RHEL 等发行版中,SELinux 默认启用。例如,即使 httpd 进程以 root 运行(实际上通常以 apache 用户运行),SELinux 也会限制其只能访问 /var/www/html/ 下特定类型的文件,无法读取 /etc/shadow 或执行某些危险系统调用。
6.1.3 其他 Linux 安全机制
- AppArmor:另一种 MAC 实现,与 SELinux 竞争。它基于路径(path-based)而非类型标签,配置更简单,被 Ubuntu、Debian 等发行版采用。
- Namespaces 与 Cgroups:用于容器隔离(Docker、LXC),限制进程的资源视图。
- Capabilities :将 root 的超级权限拆分为独立的小能力(如
CAP_NET_ADMIN、CAP_SYS_ADMIN),进程可以只拥有部分能力,无需完全 root。 - seccomp(Secure Computing Mode):限制进程只能调用少量系统调用,常用于沙盒化(如 Chrome 浏览器)。
- 内核地址空间布局随机化(KASLR) 、内核页表隔离(KPTI) 等防御漏洞利用的技术。
6.2 Android 安全强化(SEAndroid,沙盒,运行时权限)
Android 在 Linux 内核之上构建了多层次的安全体系,其设计目标包括:保护用户数据、隔离应用、防止恶意软件、确保系统完整性。主要强化措施如下。
6.2.1 SEAndroid:SELinux 在 Android 中的移植与强化
SEAndroid 是将 SELinux 移植到 Android 平台的项目。从 Android 4.3(Jelly Bean)开始引入,Android 5.0(Lollipop)起强制启用为 Enforcing 模式。
SEAndroid 的特殊之处:
- 细粒度的应用隔离 :每个第三方应用都被分配独特的类型(如
untrusted_app_25、untrusted_app_27),策略文件为每个应用单独定义允许的权限。即使两个应用拥有相同的 Linux UID(不可能,因为 UID 唯一),SELinux 也能区分。 - 限制系统服务 :即使是
system_server这样的核心进程,也被严格限制。例如,system_server不能直接访问应用的私有文件,只能通过 Binder 调用应用提供的接口。 - 限制 root 权限 :即使攻击者通过漏洞获取了 root 权限(例如通过 adb root 或漏洞提权),SELinux 策略依然可以阻止其访问敏感数据(例如其他应用的
/data/data目录)。因为 SELinux 策略在 root 之上生效------root 并不自动拥有所有类型。 - 属性(property)保护 :Android 系统属性(如
ro.secure、persist.sys.timezone)通过 SELinux 策略限制访问,防止恶意篡改。
SEAndroid 策略文件 :位于 /sepolicy 或编译进内核的 sepolicy 二进制,由 init 进程加载。
典型策略示例(实际策略更复杂):
text
# 允许 untrusted_app 读取 /dev/input/event* 但不可写入
allow untrusted_app input_device_t:chr_file { read open getattr };
6.2.2 应用沙盒:基于 UID 的进程隔离
Android 将 Linux 的多用户机制改造为应用沙盒:
- 每个应用独立 UID:安装时,系统从 10000 开始分配一个唯一的 Linux UID。不同应用的 UID 不同,因此内核级的 DAC 自动阻止它们访问彼此的私有文件。
- 私有目录保护 :每个应用的
/data/data/<package>/目录的权限为rwx------(0700),只有该 UID 的进程可以访问。 - 原生代码隔离 :应用的原生库(
.so)位于/data/app/<package>/lib/,同样受 UID 保护。 - 进程间通信限制:应用之间不能通过传统的 Linux 信号、ptrace 等方式相互干扰,因为 UID 不同且 SELinux 进一步限制。
zygote 与进程派生:
- 所有应用进程都由
zygote进程fork()而来。zygote以 root 运行,但在fork()后、执行应用代码前,会通过setuid()切换到应用的 UID,并设置 SELinux 上下文。因此应用进程以非特权用户运行。
与 Linux 传统多用户的区别:
- Linux 的多用户场景是多个人 共用一台机器,每个用户有自己的家目录。Android 的应用沙盒是为每个应用(而不是每个人)创建一个虚拟用户,且应用之间默认完全隔离。
- Linux 用户可以登录、执行 shell、安装软件;Android 应用只能执行预设的四大组件操作,无法任意运行 shell 命令(除非有漏洞或 root)。
6.2.3 权限系统:从安装时到运行时
Android 应用需要声明权限才能访问敏感资源(相机、位置、联系人、存储等)。权限系统经历了重大演进。
早期(Android 5.1 及之前):
- 安装时权限:用户在安装应用时看到所有权限列表,只能选择"全部接受"或"取消安装"。一旦安装,应用拥有所有声明的权限,用户无法事后撤销。
- 问题:用户往往不看权限列表,或者因为需要应用的核心功能而被迫接受不必要的权限。
运行时权限(Android 6.0,API 23 引入):
- 权限分组 :将权限分为正常权限 (如网络访问,安装时自动授予)和危险权限(如读取联系人、相机、位置,需要在运行时申请)。
- 动态申请 :应用在需要某个危险权限时,调用
requestPermissions(),系统弹窗询问用户是否允许。用户可以同意或拒绝,也可以在系统设置中事后撤销。 - 权限组:属于同一组的权限(如 READ_CONTACTS 和 WRITE_CONTACTS)只要其中一项被授权,整组即被授权(减少弹窗次数)。
- 仅这次允许(Android 11+):对于位置、麦克风、相机等敏感权限,用户可以选择"仅这次允许",下次应用使用时需再次申请。
权限检查机制:
- 当应用尝试调用需要权限的 API(如
Camera.open())时,系统会在 Binder 调用中检查调用者的 UID 和包名,查询PackageManager中记录的授权状态。 - 由于 Binder 自动传递调用者的 PID/UID(不可伪造),应用无法绕过权限检查。
权限管理组件:
PackageManager:存储应用安装时声明的权限列表。PermissionController(系统应用):处理运行时权限弹窗和设置界面。ActivityManager和AppOps:跟踪权限使用情况,提供"权限使用记录"给用户查看。
6.2.4 其他 Android 安全机制
1. 验证启动(Verified Boot)
- 设备启动时,从 Boot ROM 开始,逐级验证 Bootloader、内核、系统分区(
system、vendor等)的数字签名。 - 使用哈希树(dm-verity)确保系统分区只读且完整。如果系统被篡改(如 root 后修改了
/system/build.prop),设备可能拒绝启动或进入恢复模式。 - 保护用户免受恶意固件和持久化 rootkit 的威胁。
2. 应用签名
- 每个 APK 必须使用开发者的私钥签名。系统在安装时会检查签名,并确保升级包与已安装版本的签名一致。
- 签名也用于建立应用间的信任关系(如共享 UID 的应用必须具有相同签名)。
3. Google Play Protect
- 内置在 Google Play 服务中的安全套件,定期扫描设备上的应用(包括侧载应用)是否包含恶意代码。
- 提供"查找我的设备"、远程锁定/擦除功能。
4. 加密
- 全盘加密(FDE,Full Disk Encryption) (Android 5.0-9):使用 dm-crypt 加密整个
/data分区,开机时需要输入密码/图案解锁。 - 文件级加密(FBE,File-Based Encryption)(Android 7.0+):每个文件使用独立密钥加密,支持直接启动(Direct Boot,在用户解锁前运行部分服务)。使用内核的 fscrypt 框架。
- 元数据加密(Android 9+):加密存储加密元数据的分区,防止攻击者从加密分区中推断文件结构。
5. 密钥库(KeyStore)
- 系统级安全存储,用于保存密钥和证书。硬件支持(如 TrustZone)时,密钥可以永不离开安全硬件。
6. 地址空间布局随机化(ASLR)与堆栈保护
- 内核和所有用户空间进程(包括应用)默认启用 ASLR,使缓冲区溢出等攻击更难定位函数地址。
- 编译器选项(如
-fstack-protector-strong)防止栈溢出。
7. 无执行(NX,No-eXecute)内存
- 数据页(如栈、堆)不可执行,防止 shellcode 注入执行。
8. 受限的 shell 访问
- 普通用户(包括开发者模式下的 adb)没有 root 权限,且
adb shell运行在受限的shell用户下,无法访问大多数系统目录和应用数据。生产设备通常关闭 adb root。
6.3 Linux 与 Android 安全机制对比总结表
| 特性 | Linux | Android |
|---|---|---|
| 基础权限模型 | DAC(用户/组/其他) | DAC + 应用沙盒(每应用独立 UID) |
| 强制访问控制 | SELinux(可选,部分发行版启用) | SEAndroid(强制 Enforcing,不可关闭) |
| 权限授予方式 | 用户级(安装时决定,无动态) | 运行时权限(用户可动态授予/撤销危险权限) |
| root 权限 | 存在,拥有最高权限 | 默认无 root,且 SELinux 限制 root 行为 |
| 应用隔离 | 进程以用户身份运行,共享家目录需自行配置 | 每个应用独立 UID + 私有目录 + SELinux 类型 |
| 系统完整性 | 无默认验证(可配置 dm-verity 等) | 验证启动(Verified Boot)+ dm-verity |
| 加密 | 可选(LUKS、dm-crypt) | 全盘加密或文件级加密(默认启用) |
| 应用签名 | 无统一要求(包管理器信任仓库签名) | 强制 APK 签名,升级必须签名一致 |
| 安全更新 | 各发行版独立提供(数月到数年) | Google 每月安全补丁 + 厂商适配(生命周期有限) |
| 安全审计 | 日志(syslog)、auditd 等 | logcat、dmesg、bugreport 工具 |
| 典型目标 | 防止非授权用户访问;服务器防入侵 | 保护用户隐私;防止恶意应用;设备防盗 |
6.4 总结:继承与超越
Android 继承了 Linux 内核的 DAC 和 SELinux 框架,但将其强制化、细粒度化,并与移动设备特有的应用模型深度集成。在 Linux 上,SELinux 通常是可选的高级安全功能(许多桌面用户甚至关闭它);而在 Android 上,SEAndroid 是强制运行的,构成了防御恶意应用和系统漏洞的最后一道防线。
同时,Android 引入了运行时权限 和应用沙盒,将安全决策权部分移交给用户,使隐私保护更加透明可控。这些设计使得 Android 能够在开放的应用生态中,依然保持较高的安全水准。
七、总结
Android 操作系统以 Linux 内核为基础,复用了其进程调度、内存管理和网络协议栈等核心底层功能。针对移动设备特性,Android 在内核侧引入了 Binder IPC 通信、Wakelocks 电源管理机制以及基于进程优先级的 LowMemoryKiller 内存回收策略,并通过硬件抽象层(HAL)解耦了内核驱动与上层框架。在用户空间,Android 采用轻量级的 Bionic C 库、SurfaceFlinger 图形合成服务以及 ART 虚拟机,取代了传统 Linux 的 glibc、X11/Wayland 及 ELF 机器码直行模式,确立了跨架构的应用程序运行基础。在安全与存储机制上,Android 摒弃了传统 Linux 的多用户模型与灵活的文件层级标准,转而采用固定分区布局,并通过强制执行的 SEAndroid、基于独立 UID 的应用沙盒及动态权限机制,实现了细粒度的资源访问隔离。从技术架构本质来看,Android 是一个运行在定制化 Linux 内核之上、面向移动设备优化的重量级用户态中间件系统。
八、Android 系统启动与组件分层图
