说起 Android,很多人第一反应是:
- Activity、Fragment、Service
- RecyclerView、Handler、Bitmap
- 各种 UI、各种库
但这都还是“楼上的东西”。
要真想搞懂 Android 为啥能跑、App 为啥能起来、进程为什么不会互相乱搞、Java/Kotlin 代码到底怎么跑在手机 CPU 上,就绕不开一个问题:
Android 操作系统的底层支持组件到底有哪几类?
它们是怎么配合起来撑起这整套系统的?
本篇就试图用大白话,把这套“底层班子”给你从整体到局部拆开讲清楚,主要包括:
- Android 的整体分层结构(从 Linux 到 Java/Kotlin 应用)
- 支撑一切的 Linux 内核级组件(进程、线程、内存、驱动、Binder、SELinux…)
- C/C++ 层的系统库和运行时(bionic、libc、图形/多媒体/数据库等)
- Runtime 层:ART 虚拟机、垃圾回收、JIT/AOT
- Framework 层的关键服务与系统进程(system_server、Zygote、AMS、WMS 等)
- Binder IPC 机制作为“胶水”的角色
- 以及,这些底层东西对我们日常开发有什么影响
不搞玄学、不堆术语,尽量用易懂的类比,把这套复杂系统讲得人话一点。
一、先从大局看:Android 这栋楼是怎么分层的?
先给你一个脑补图(文字版),方便后面定位:
从下往上看,Android 基本可以拆成四五层:
Linux 内核层(Linux Kernel)
- 真正跟硬件打交道的那层:CPU、内存、进程、文件系统、驱动、网络等
- 再加上 Android 自己的一些增强(Binder、wakelock、电源管理、SELinux 等)
系统库 + 原生层(Libraries & Native)
- 各种 C/C++ 库:bionic libc、OpenGL ES、Media、SQLite、WebKit、SSL…
- 还有一些 Native 守护进程(SurfaceFlinger、MediaServer、keystore 等)
运行时层(Android Runtime:ART)
- 专门跑 Java/Kotlin/字节码的虚拟机环境
- 包括核心类库(java.、android.)和垃圾回收、JIT/AOT 等
框架层(Framework)
- 对 App 暴露的各种 Java API:ActivityManager、PackageManager、WindowManager 等
- 再加一堆系统服务,主要集中在 system_server 进程里
应用层(Applications)
- 你写的 App,系统自带的拨号、短信、设置等
- 大多数是 Java/Kotlin + XML + 少量 Native
可以想象成一栋大楼:
- 地下室:Linux 内核,打地基、接电接水(CPU、内存、硬件)。
- 一层:系统库、Native 服务,准备各种工具、设备、管道。
- 二层:ART 虚拟机,给 Java/Kotlin 搭舞台。
- 三层:Framework 服务,搭各种“系统级服务柜台”和 API。
- 四层:App,小店铺、小摊位,使用楼下的供水供电做生意。
“底层支持组件”,本质就是前面这几层构成的整套设施。
下面我们就从最底层一路往上讲。
二、最底层:Linux 内核——Android 的“水电煤 + 物业”
2.1 为什么 Android 要用 Linux 内核?
很多人会问:
Android 为什么不用自己写内核,而要基于 Linux?
理由很现实:
- 成熟稳定:Linux 已经在服务器、桌面、嵌入式上跑了几十年,各种调度、文件系统、网络栈都很成熟。
- 开源:Android 想玩大规模生态,当然要选个开源的底座,方便各家手机厂魔改。
- 社区驱动力:Linux 内核不断优化,Android 跟着坐顺风车。
- 驱动生态:很多芯片厂、硬件厂的驱动本来就围绕 Linux 做。
所以 Android 干脆:
把 Linux 当底层地基,在上面搭自己的一栋“高层公寓”。
不过,Android 并不是直接拿 Linux 原样照搬,它做了很多定制增强:
- Binder IPC
- wakelock 和电源管理机制
- ashmem 共享内存
- 安全相关的 SELinux 策略集成
- 一些特定硬件(如手机电源、传感器等)对应的驱动和接口
2.2 Linux 内核提供了哪些关键能力?
我们说“底层支持”,内核主要提供几块:
进程与线程管理
- fork/exec 建进程
- 调度(哪个进程/线程先跑、谁抢 CPU)
- 线程其实也是“轻量进程”
内存管理
- 虚拟内存、物理内存映射
- 堆栈分配
- 内存页置换、OOM Kill(内存不够了杀进程)
- Android 基于此再做 LMK(Low Memory Killer)等扩展
文件系统与存储
- /system、/data、/sdcard 等挂载
- 文件读写权限
- 日志系统(logcat 底层其实有内核日志支持)
设备驱动(Drivers)
- 显卡、触摸屏、音频、摄像头、传感器、电池、WIFI/基带等
- 内核把这些硬件抽象成驱动,上一层通过文件或 ioctl 等方式访问
网络栈
- TCP/IP 协议栈、路由、防火墙
- Socket 通信、VPN、WiFi 热点等核心能力
安全机制
- 权限用户/用户组(UID/GID)
- 能力控制(capabilities)
- SELinux:基于标签的访问控制,更细粒度控制“谁能碰谁”
对 Android 而言,这些是“不动就不感知,动就离不开”的基础设施。
2.3 Android 特有的内核扩展:Binder / wakelock / ashmem / SELinux
几样非常“Android 味儿”的内核组件:
2.3.1 Binder:系统的超级“对讲机”
Binder 是 Android 独家的进程间通信(IPC)机制。
你可以把不同进程想象成不同房间:
- App A 是 101 房间
- App B 是 102 房间
- system_server 是物管办公室
平常你在 Activity 中调的各种系统服务,比如:
- 获取位置(LocationManager)
- 打开摄像头(CameraService)
- 获取剪贴板、包管理、通知等
其实很多都不是同一进程内调用,而是:
你给“物管办公室”打了个电话,对方帮你干,然后给你回话。
这个“打电话”的底层机制就是 Binder:
- 它是一个内核驱动:/dev/binder
- 上层通过 Binder 驱动把方法调用封装成“消息”,
- 投递给目标进程里的“Service”,
- Service 执行完,再把结果通过 Binder 回给你。
以后你看到:
- AIDL(Android Interface Definition Language)
- BinderProxy、IBinder
- 系统服务之间互相调用
背后都是 Binder 在跑。
2.3.2 wakelock:别让手机“自己睡死”
内核负责电源管理:CPU 什么时候降频、休眠;屏幕什么时候熄灭。
但网络、音乐、导航这些场景又要求:
屏幕可以灭,CPU 不能睡死;
或者下载没完成前不要休眠。
为此 Android 引入了 wakelock:
- 系统或 app 可以申请一个 wakelock,说“我还在干活呢先别睡”;
- 当没有任何 wakelock 时,系统才会大胆地让 CPU 休眠、省电。
底层实现也是内核里的一套机制,Framework 暴露 PowerManager 给我们用。
2.3.3 ashmem:匿名共享内存
Android 为了在不同进程之间传大块数据(比如 Bitmap、媒体缓冲),又不想到处复制,于是基于内核搞了个 ashmem:
- App 和系统进程可以共享一块内存区域
- 通过映射减少复制,提高性能
很多看似“轻松传大对象”的操作,背后都可能在用 ashmem。
2.3.4 SELinux:严防死守的门禁系统
SELinux 是 Linux 的安全扩展,Android 把它用得很狠:
- 每个进程、文件、对象都有一个安全上下文标签(如 u:r:system_server:s0)
- 每次访问都要过策略检查:这个 label 能不能访问那个 label?
好处:
- 即使有人拿到了 root 或者利用了某个进程漏洞,
- SELinux 策略也可能限制它能干的坏事范围。
从 Android 5.0 以后,SELinux 强制启用(enforcing),是底层安全的重要一环。
三、系统库和 Native 组件:C/C++ 打头阵
从内核往上走,就到了“系统库 + Native 服务”这层。
它们主要负责:
把内核提供的“粗糙接口”,打磨成更易用、性能更好的库函数和服务。
3.1 bionic libc:Android 自家的 C 标准库
在普通 Linux 上,我们常见的 C 标准库是 glibc。
Android 不用它,用的是自己写的 bionic。
为什么?
- 更轻量:面向移动设备,内存资源有限。
- 许可问题:bionic 使用 BSD/MIT 风格,方便闭源商业化。
- 可裁剪:可以针对不同设备需求进行删减。
bionic 提供:
- 标准 C 函数:malloc/free、printf、strcpy 等
- POSIX API:线程、文件操作、Socket 等
- 对 Linux 系统调用做封装
所有 Native 层的程序(包括 ART、system_server 的部分 C++ 模块)都要依靠 bionic。
3.2 常见系统库:图形、多媒体、数据库、安全
Android 自带了一堆功能库(通常在 /system/lib 或 /system/lib64 下):
图形相关
- OpenGL ES:给 2D/3D 渲染用
- Skia:2D 绘图库,Canvas、View 的底层
- SurfaceFlinger:负责把各个 Window/Surface 合成到屏幕上(严格说是一个 Native 服务进程)
多媒体
- libmedia / MediaPlayerService:音视频播放
- Stagefright(旧)、MediaCodec/MediaExtractor 等:编解码、封装解析
- AudioFlinger / AudioPolicy:音频混音、路由
数据库
- SQLite:轻量级关系型数据库,Android 的数据库 API 底层就是它
网络和安全
- OpenSSL / BoringSSL:HTTPS、加密
- libcrypto、libssl:各种加密算法、证书验证
- curl/http 库(或基于它们的封装)
这些 C/C++ 库是所有上层的“高性能工具”,
Java 层的 API(比如 MediaPlayer、SQLiteDatabase)只是对它们再包一层外壳。
3.3 一些关键 Native 服务进程
除了库,还有一些跑在 Native 层的“常驻服务”进程,例如:
SurfaceFlinger:图形合成服务
- 把每个 App 绘制的 Surface/Buffer 合成最终的屏幕画面
- 是显示系统的核心一环
MediaServer(或其他多媒体守护进程)
- 处理音视频编解码、录制、播放等
- 不让每个 App 直接拿硬件,集中管理
keystore
- 管理密钥,提供安全存储
- 配合硬件安全模块(TEE/SE 等)
这些服务通过 Binder 暴露接口给 framework 和 App。
四、Android Runtime(ART):Java/Kotlin 代码的“执行引擎”
上面说的是 C/C++ 世界,那我们的 Java/Kotlin 是在哪里跑的呢?
答案就是:ART(Android Runtime)。
4.1 ART 是干嘛的?
简单说:
ART 是 Android 上跑 Java 虚拟机字节码的一套运行时环境,
是以前 Dalvik 的进化版。
主要职责:
- 加载 .dex / .oat / .odex 等字节码文件
- 提供 Java 核心类库(java.,android.)环境
- 负责执行字节码(解释、JIT、AOT 编译)
- 管理堆内存、GC
你写的:
vals="hello"list.add(s)编译打包后变成 dex(Dalvik Executable),
ART 负责把这些指令翻译成 CPU 能执行的机器码。
4.2 Dalvik vs ART:从解释器到“先编译后执行”
早期 Android 用的是 Dalvik:
- 偏解释执行 + 一点 JIT,性能有限
- 安装时不用做太多编译工作
后来引入 ART:
- 支持 AOT(Ahead-Of-Time)编译:安装时就把一部分字节码编译为本地机器码
- 后期又加入 JIT + Profile 引导编译(根据实际使用情况决定哪些方法要编译)
这样:
- 冷启动时不需要每次都从解释器跑起
- 热路径能编译成高效机器码,性能比纯解释要好不少
4.3 ART 的堆和 GC:为 App 管内存的“垃圾清理工”
ART 负责管理 Java/Kotlin 对象的堆内存:
- new 出来的每个对象,都放在 ART 的托管堆上
- 定期通过 GC(垃圾回收)清理不再使用的对象
GC 机制多年来也不断进化:
- 从 Mark-Sweep、Mark-Compact 到并行、增量 GC
- 目标是在尽量减少“卡顿”的情况下回收内存
这和普通 JVM 很像,但针对移动设备(内存少、响应敏感)做了很多优化手段。
对我们普通开发者来说:
虽然不用手动 free 内存,但要理解:
- 频繁创建短生命周期大对象、Bitmap、String,会给 GC 增加压力
- GC 攒多了,UI 就会卡
这些都和 ART 内部的 GC 策略息息相关,属于“半底层”的影响。
五、Framework 层:system_server + 各种系统服务
再往上一层,就是我们最常打交道的 Java Framework。
但很多人不知道,它背后其实是一个叫system_server的大进程。
5.1 system_server:Android 的“中央管家”
system_server 里跑着一大票系统服务,这些服务负责:
- 启动 App、管理 Activity 栈(ActivityManagerService)
- 管理窗口和显示层级(WindowManagerService)
- 电源管理、电池策略(PowerManagerService)
- 包管理、权限控制(PackageManagerService)
- 通知栏、状态栏(NotificationManagerService 等)
- 位置、传感器、音频、输入法…… 统统都是各种 XXXService
每个服务通常:
- 用 Java 写逻辑
- 通过 JNI 调到 Native 层
- 再通过 Binder 与其他进程通信
我们日常用:
ActivityManageram=(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);拿到的其实是这些服务的一个 Proxy(代理),
真正干活的是 system_server 进程里的那个 Service 对象。
5.2 Zygote:所有 App 的“共同祖先”
整个 Android 系统里,还有一个非常关键的进程:Zygote。
- 启动时,Zygote 会提前加载常用类、资源、初始化虚拟机等。
- 当新 App 要启动时,系统不是从零创建一个新进程,而是:
让 Zygote fork 自己出一个“儿子”,
儿子再加载目标 App 的代码,跑 mainLooper。
这种套路的好处:
- 省时间:
- 不用每个 App 从头初始化 ART 和一堆类库。
- 省内存:
- 父进程(Zygote)与子进程可以共享不少只读内存页面(COW 机制),
- 例如:系统类库等。
你可以把 Zygote 想象成:
预先生好一个“模子”,
每个 App 进程都是在这个模子上快速克隆出来,再稍微个性化一下。
六、Binder 作为“系统胶水”:四处串联的通信大动脉
在讲完 Linux 内核、Native 库、ART、Framework 后,
你会发现一个问题:
这么多进程、这么多服务,它们怎么沟通?
App 怎么远程调用 system_server 的方法?
system_server 又怎么控制 MediaServer 或 SurfaceFlinger?
核心答案就是:Binder IPC。
6.1 Binder 的基本思路:远程调用像本地调用
想象一下,你在 App 进程里写:
LocationManagerlm=(LocationManager)getSystemService(LOCATION_SERVICE);Locationloc=lm.getLastKnownLocation(...);看起来只是普通方法调用,但实际上:
- lm 是一个 Binder Proxy
- getLastKnownLocation() 内部会把参数打包成 Parcel
- 通过 Binder 驱动发给 system_server 里的 LocationManagerService
- 后者处理后再把结果写入 Parcel 发回
- Proxy 把结果解包成 Location 返回给你
整个过程:
像打电话一样,但语法上像本地方法调用。
Binder 的设计目标就是:
让跨进程调用尽量像本地调用,
同时保证安全、稳定、高效。
6.2 AIDL:自动生成 Binder 桥接代码
Android 提供 AIDL(Android Interface Definition Language):
- 你写一个
.aidl文件定义接口方法 - 系统帮你生成 Stub 和 Proxy 类
- 你在 Service 端实现 Stub,在客户端拿 Proxy 调用
比如:
interface IRemoteService { int add(int a, int b); }底层就是在 Binder 上编/解码这些参数,搞跨进程 RPC。
系统的很多 Service 接口,内部就是用 AIDL 之类的机制实现的。
6.3 安全与性能:为什么不是用普通 Socket?
你可能会问:
为啥不用 Socket 或者普通管道,只要能通信不就好了?
Binder 的好处:
安全:
- 系统级别知道“谁在给谁发消息”,UID/PID 信息直接可见;
- 方便做权限和身份检查。
性能:
- 采用共享内存机制减少数据复制;
- 特别针对移动场景优化,减少一次调用的开销。
统一:
- 全系统框架围绕 Binder 设计,系统服务全都用它。
七、这些底层支持组件,对我们普通开发有什么影响?
讲了这么多底层,有人可能会想:
我平时写 App,基本没碰过这些东西啊?
知道这些有啥用?
其实影响非常多,只是你习惯了,感觉不到:
App 进程生命周期
- 由 AMS 在 system_server 控制,
- Android 内核的 LMK/内存管理也会参与“谁该被杀”。
多进程与 Remote Service
- 你一旦用到 remote Service,本质上就是在玩 Binder IPC。
- 大数据传输、多次调用时要注意性能。
性能调优
- 冷启动速度:与 Zygote 预加载、ART AOT/JIT 有关。
- 滑动卡顿:GC、Binder 延迟、主线程阻塞都有可能是幕后黑手。
安全与权限
- SELinux、权限检查、UID/GID 隔离,
- 决定你能不能访问某些系统能力。
NDK / Native 开发
- 使用 C/C++ 时直接对接到 bionic、系统库、Native 服务接口。
- 不理解底层,很容易搞出崩溃和内存泄漏。
系统定制 / ROM / 深度优化
- OEM 厂、ROM 制造者天天和这些底层组件打交道。
- 你若想走系统开发方向,这些就是“必须争取搞明白”的内容。
总体来说:
你可以不天天写内核代码、写 Binder 驱动,
但至少要知道这一整套“底层班子”是如何支撑你平时的一行行 Java/Kotlin 代码的。
八、收个尾:把 Android 底层支持组件想象成一个“城市系统”
最后把这篇长文用一个城市类比收尾,让你脑中留一个整体画面。
Linux 内核= 城市基础设施 + 物业公司
- 修路(进程调度)、供电供水(内存、I/O)、管理各种建筑(文件系统)、
还有一堆安全摄像头和门禁系统(权限、SELinux)。
- 修路(进程调度)、供电供水(内存、I/O)、管理各种建筑(文件系统)、
系统库 & Native 服务= 城市里的各种专业公司、工厂
- 自来水厂(媒体服务)、电力公司(图形渲染)、电信局(网络)、
银行金库(keystore)……
- 自来水厂(媒体服务)、电力公司(图形渲染)、电信局(网络)、
ART= 一个专门为“Java/Kotlin 族人”建的生活区
- 提供他们能读懂的语言环境(字节码)、生活设施(类库)、垃圾清理(GC)。
Framework & system_server= 市政府 + 各个职能部门
- 规划局(ActivityManagerService)、城管(PackageManagerService)、
交警(WindowManagerService)、公安(权限/安全服务)……
- 规划局(ActivityManagerService)、城管(PackageManagerService)、
Binder= 城市里的电话网 + 内部专线
- 各部门之间打电话协作,
- 市民(App)拨打市政府热线(getSystemService)办事情。
Zygote= 统一建房子的开发商
- 一栋栋住宅楼(App 进程)都从它的标准模子克隆,省成本、效率高。
应用 App= 城市里的各种商铺、公司
- 使用市政提供的电、水、网和政策服务(API),
- 给用户提供具体功能。
当你把这些关联起来后,就会发现:
Android 不是“一个大黑盒子”,
而是一整套层次分明、分工明确的城市系统。你写的每一行代码,都有对应的“底层工作人员”在帮你完成动作。
理解这套底层支持组件,不是为了装 X,
而是为了在你遇到「为什么这儿这么慢」「为什么这个调用会崩」「这个进程怎么就被杀了」「多进程怎么设计才靠谱」等问题时,
脑子里能浮现出一张“城市地图”,从底层结构上去分析、定位、解决。
这,就是掌握 Android 的“底层思维”的价值所在。