
很多做Android开发的同学不管是刚入行还是写了几年都容易被“系统层”这三个字搞糊涂领导说“这个改动要动Framework层”同事说“你去看AOSP源码”网上文章又冒出来一堆“AMS、WMS、PMS”缩写看着眼熟但说不清它们之间什么关系。说实话我当年也是从一堆碎片信息里自己拼出来的走了不少弯路。这篇文章我想把这些概念一次讲透AOSP到底是什么Framework在哪个位置AMS、WMS、PMS三个系统服务各自管哪摊事以及它们怎么配合着把一个App跑起来。适合所有想弄懂Android底层逻辑、面试前突击系统知识、或者工作中需要排查系统级问题的开发者读完之后至少能建立一张清晰的“系统地图”。1. AOSP 从来不是一个“系统”先把它看作一个巨型工程1.1 两个反直觉的事实先说第一个反直觉的事实AOSP不是一个可以下载安装的操作系统。市面上你找不到一个叫“AOSP”的镜像文件装到手机里就能开机。它让很多人困惑根源就在于名字里带了“Android Open Source Project”大家天然以为这是一个“开源的Android系统”。实际上AOSP是一个由Google发起并维护的超大型源码工程。这个工程里既有底层Linux内核的修改版也有运行时ART、各种系统库、Java框架层代码、系统UI和基础应用甚至还包括构建编译这套系统所必需的工具链和构建脚本。把它拉下来理论上你可以编出一个完整的、能运行的Android系统镜像然后烧录到Pixel等设备上开机使用——但那是“编译产物”AOSP本身是一堆源代码的集合。第二个反直觉的事实是你手机里的Android系统其实只是“长在AOSP上的一棵树”。Google把AOSP开源但厂商拿到的、给用户刷的系统都是基于某个AOSP版本深度改出来的东西换了内核驱动和HAL实现改了系统UI塞入了自己的各种服务和应用还加入了Google那套闭源的应用和服务框架如果出海的话。所以我们平时说“Android系统”往往包含了好几层含义底层是开源AOSP代码中间是厂商魔改部分上层还有各家自己的东西。1.2 源码目录里到底装了些什么想要理解AOSP最简单的方法是去看它的顶层目录结构。这是我从源码库里整理出的几个核心部分不用背看一遍有个印象就行frameworks/ Java框架层与系统服务也是本文后面要讲的Framework核心区 packages/ 系统应用与系统组件比如桌面Launcher、设置、电话、联系人等 system/ 底层核心服务包括init进程、SELinux策略、工具链等 art/ Android运行时负责编译执行Java字节码 hardware/ HAL硬件抽象层接口定义厂商的驱动实现一般不放进AOSP external/ 第三方开源库如sqlite、libc、zlib等 build/ 构建系统负责把上面所有东西编成最终的镜像文件这里有个容易忽略的细节packages/下的“应用”和我们自己写的App有本质区别。比如packages/apps/Launcher3这是系统桌面程序。它虽然也是Android应用但它被打包进系统镜像拥有系统权限并且在很多平台上不允许被用户卸载。从它开始就是个分界线在AOSP里改代码和你用Android Studio写App是两个不同层面的开发。App开发用的是SDK软件包里暴露给你的公共API而AOSP开发直接操作系统源码需要自己搭建编译环境改完之后把整个系统镜像重新编译、烧录到设备上才能看到效果。1.3 什么算“AOSP开发”什么不算很多人会说“我要去看AOSP源码”其实他可能只是想看某个类的实现比如ContextImpl怎么工作的。这种“看源码”不叫AOSP开发叫读源码门槛很低。真正的AOSP开发指的是往系统源码工程里提交代码、定制系统级行为。举个直观的例子如果你想改一个系统级策略比如“用户在通知栏点击某个应用的通知时默认不弹出悬浮窗”你在SDK层面是找不到入口的因为SDK把系统服务内部的实现都封装掉了。这时候你需要找到NotificationManagerService相关的源码改完然后重新编镜像。同样地如果你想在ActivityManagerService启动Activity时打一条日志也需要改AOSP。Android Studio 新建项目是SDK开发repo sync make 是AOSP开发这两件事的工具链、工作流、部署方式完全不同。如果你的目标是面试或者排查线上问题“读源码看懂源码”就够了如果你想定制系统比如做车机系统、定制ROM、做加固沙箱那才需要真正去搞AOSP编译环境。2. Framework 的确切位置夹在系统镜像与应用程序之间2.1 先给Framework画一个坐标弄清了AOSP是一堆源码工程之后我们就能把Framework放回它应该待的位置了。在整个Android系统分层里从上往下大概是这样应用层你写的App、系统自带的桌面和设置等运行在“自己的进程空间”里。Java API Framework层也就是平时常说的Framework提供Activity、Service、Context、View这些开发接口并承载系统服务AMS、WMS、PMS都跑在系统进程里也属于这一层。系统运行库层ART虚拟机、JNI库、libc、图形驱动等。Linux内核层进程管理、内存管理、驱动、Binder驱动的基础。这里的Framework在AOSP源码里对应的就是frameworks/base这个庞大的目录。frameworks/base下面有core/java基础类services/core/java系统服务libs供应用层调用的库还有packages/SystemUI这类系统界面。换句话说Framework层是AOSP的一部分而且是很关键的一部分但不是全部。AOSP还包括内核、ART和一堆应用Framework只是中间那一层Java世界。2.2 谁在跑FrameworkZygote 与 System Server理解“Framework”的另一个切入点是看进程。Android系统开机后大致流程是这样的init进程启动后会拉起一个叫Zygote的进程。Zygote本身预先加载了Framework层的常用类和资源是整个Java世界的孵化器。然后Zygote会fork出System Server进程——这个进程是系统服务的总舱。AMS、WMS、PMS全都由SystemServer.java的main方法里创建并注册到Binder上下文里。而你手机上每个普通App启动时也是Zygote fork出来的。fork之后子进程内跑的同样是Framework的代码ActivityThread、ContextImpl、ViewRootImpl这些类都被打进framework.jar之类的基础jar包里同时存在于system_server和每个App进程里。区别在于system_server是拥有最高权限、掌管所有服务的管理者普通App进程是只能通过Binder调用系统服务的被管理者。这就解释了一个常见疑惑“Framework代码为什么我在自己的App里也能走到”——因为Framework类是会被加载进App进程的只是App进程拿不到系统服务的核心权力它只能拿到那些通过AIDL对外暴露的接口。2.3 Framework 和 SDK 不是一回事这是我最常被问也最值得掰开的问题之一。SDK即软件开发工具包通常指Android SDK里提供给开发者的那些android.jar里面的公共API类。而Framework是系统源码里的完整实现。两者有交集但远不是一回事。举几个具体例子android.app.Activity在SDK里是一个公开类但在Framework源码里它有大量hide标注的方法和字段。你用SDK写的代码调用不到这些隐藏API但系统内部、system_server、系统应用可以。比如ActivityManager里很多接口都是隐藏的普通App编译时根本看不到。Framework里大量代码不在任何公开API里比如ActivityThread这个类它是App进程的入口负责创建Activity并回调生命周期但你在SDK里无法直接用。它不在SDK的android.jar中只存在于设备上开发环境下你甚至编译不过去。为了兼容Android在公开SDK层维护了一批稳定的公开API并不断把内部API隐藏起来。规矩是SystemApi表示系统应用可用、非SDK接口普通应用用反射去调也可能在目标版本直接被拦截。所以更准确的表述是SDK是Google从Framework层挑出来经过稳定化、对外公开的那部分API的映射Framework是在设备上真实运行的完整实现。你在Android Studio里import的androidx.appcompat.app.AppCompatActivity它再上层依赖的android.app.Activity就是Framework体系里的公开部分而这背后支撑它运转的AMS、WMS、PMS才是Framework层的全部家底。3. AMS / WMS / PMS三个最常被提起的系统服务内部到底管什么3.1 AMSActivity 与进程的双重管家先说知名度最高的ActivityManagerService习惯上叫AMS。它位于frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java。AMS是system_server里最核心的服务之一掌管两件大事。第一件事是Activity和任务栈的生命周期调度。你在桌面点击一个图标最终会通过Binder走到AMS的startActivity方法AMS会检查目标Activity有没有在系统里的记录ActivityRecord、当前属于哪个任务栈TaskRecord、是否需要把上一个Activity压入栈、要不要启动新进程等。Activity的onCreate、onResume等回调的“由系统主动调用”的能力就来自AMS。所以面试经常会问“Activity启动过程”其实问的就是AMS这条链路。第二件事是进程管理。Android手机内存不够时为什么有的App先被杀、有的App能坚持到最后决定这个优先级的是AMS给每个应用进程算出来的adj值前台App很高后台被暂停的App很低ats内存压力到了一定程度low memory killer就直接把这个值低的进程杀掉。你看到的“应用已停止”“已停止运行”对话框也是AMS体系里的AppErrors在管。AMS对外暴露的能力一部分被封装成了ActivityManager这个SDK类比如getRunningAppProcesses()、killBackgroundProcesses()另一部分以隐藏接口形式存在比如管理多任务切换、获取导航栏上的Recents信息。常见问题的定位思路BadTokenException这类异常往往与窗口管理有关往WMS查而“进程被系统杀死”“后台刚切过去回来就重启”这类问题多半先去AMS的进程优先级和LRU逻辑里找原因。3.2 WMS窗口世界的秩序维护员第二个核心服务是WindowManagerService源码在frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java简称WMS。如果说AMS管的是Activity的“生命周期剧本”那WMS管的是Activity在屏幕上“用一扇什么样的窗展示出来”。WMS核心职责有三个管理窗口层级Z-order。每个界面元素在屏幕上终究是一个窗口窗口之间谁盖谁由WMS根据窗口类型应用窗口、系统窗口、输入法窗口、Toast等和系统策略来排。比如你的Dialog显示在Activity之上靠的就是WMS把它放到更靠前的层级。你在代码里设置的WindowManager.LayoutParams.type会直接影响WMS怎么给它排高度。分配和协调Surface。在Android里你看到的每一个View树最终都会生成一个Surface这个Surface是真正用来画东西的画布。App进程里的ViewRootImpl通过Binder调用WMS的relayoutWindowWMS为它分配Surface然后把这些Surface交给系统服务SurfaceFlinger去合成最终画面。输入事件分发的窗口定位。触摸事件分发之前需要先知道屏幕上的坐标点“落到哪个窗口上”这一步是由WMS和Input系统协同完成的。所以悬浮窗抢焦点、触摸事件被系统窗口吃掉多半要在WMS的窗口层级里找原因。这也是为什么WindowManager这个SDK类虽然看起来是给App用的但真正的“窗口管理器”在系统进程里App拿到的只是它远端服务的一个代理。常见的BadTokenException本质就是你试图在已销毁窗口的token上加新窗口WMS查不到合法token就抛异常。很多新手查Dialog为什么崩溃翻来覆去找不到答案其实就是没“看见”WMS这一层。3.3 PMS包与权限的守门人第三个是PackageManagerService源码在frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java简称PMS。它的工作像系统的“档案管理员”。PMS负责的事情包括但不限于解析并缓存APK信息。系统里的每个App安装时PMS都会解析它的AndroidManifest.xml把包名、版本号、四大组件声明、权限请求、签名信息等等记录到系统数据库里。安装、卸载、更新、静默安装。你点“安装”按钮最后把关的就是PMSadb install走到底也会调它的安装流程它还会向下和installd守护进程协作处理Native世界的目录/数据设置。权限管理。运行时权限的授予与撤销、权限组策路、特殊权限比如悬浮窗的开关记录都保存在PMS状态里。因此你开发的App申请权限后反过来查“用户到底同意没有”调checkSelfPermission背后就是PMS在回答。组件查询。PackageManager.queryIntentActivities()查到哪些Activity能响应某个Intent正是PMS去读那个APK的组件表算出来的。一句话区分这三个服务PMS管“安装过来的App信息”AMS管“跑起来的Activity和进程”WMS管“窗口在屏幕上怎么显示”。三个服务都注册在system_server而且彼此有千丝万缕的联系启动Activity时AMS要问PMS要Activity信息窗口要显示时WMS要问AMS要Activity的状态。它们像一个三角关系谁缺了另两个都会直接崩。3.4 一张表快速对照三个服务我把最常用的对照信息放在一起方便你随时翻服务源码位置核心职责日常开发接触点常见故障方向AMSservices/core/java/com/android/server/am/Activity生命周期、任务栈、进程调度与优先级ActivityManager API、杀后台、RecentsANR、进程被杀、后台重启WMSservices/core/java/com/android/server/wm/窗口层级、Surface分配、输入分发目标WindowManager API、Dialog/悬浮窗BadTokenException、悬浮窗失效PMSservices/core/java/com/android/server/pm/APK解析、安装卸载、权限和组件信息管理PackageManager API、权限申请安装失败、权限判断异常需要说明一点从Android 10以后Activity的任务栈管理职责从AMS逐步拆分到了ActivityTaskManagerServiceATMS但日常讨论中大家还是会习惯把这部分职责叫“AMS的活”。理解功能边界比抠服务名重要得多。4. 从点击图标到界面出现三巨头怎样接力完成一次启动前面单独讲每个服务接下来把整个过程串起来。这个流程搞懂了系统层的框架感基本就建立起来了。我们拿一个最普通的场景来说用户在桌面上点了一个App图标app的界面最终显示到屏幕上中间发生了什么。4.1 第一棒PMS 查出可以启动的 Activity桌面Launcher本质上也是一个App它响应点击后会调用startActivity()。这个调用会跨进程经过Binder最终到达system_server里的Activity调度中枢。中枢需要先搞清楚用户想启动的这个Intent要对应哪个包里的哪个Activity这一步就要查PMS。系统会通过resolveActivity()之类的逻辑到PMS查这个Intent能匹配到哪些组件选出一个候选的ActivityInfo其中包括它的包名、类名、进程名、启动模式、权限要求等信息。PMS还会顺手校验一下调用方有没有权限比如有些Activity声明了exportedfalse那么外部App调它时就会在这里被打回。这一步结束系统得到目标Activity的“身份证”。4.2 第二棒AMS 安排进程与 Activity 生命周期拿到ActivityInfo之后AMS或者说ATMS那套体系开始接管。它要检查这个目标Activity属于哪一个进程——如果它所在的App进程还没起来AMS会通知Zygote fork一个新的应用进程出来。进程中入口执行ActivityThread.main()然后Application、Activity相关环境被一个个绑起来。进程有了之后AMS才正式启动Activity创建ActivityRecord、决定把它放到哪个TaskRecord里是新建栈、还是复用一个已有的栈要不要走singleTask之类的启动模式然后把启动命令派发给目标进程。目标进程里的ActivityThread收到消息在App侧顺序调用了Activity.onStart()、onResume()等生命周期方法。到这一步Activity的Java侧已经活了但屏幕上还什么都没有——因为窗口还没创建。4.3 第三棒WMS 接管窗口并完成“上屏”Activity内部通过setContentView()搭好View树之后真正把信息“送到屏幕”要经过WMS。流程大致是这样的Activity窗口启动时向WMS注册一个WindowTokenActivity创建之后WindowManager.addView()带着这个token去WMS请求真正创建一个窗口App侧的ViewRootImpl通过Binder向WMS执行addWindow和relayoutWindowWMS分配好窗口层级、给它一个用于绘制的SurfaceApp在自己的Surface上把View树绘制出来绘制好的数据被交给SurfaceFlinger合成。这一条链路上有一个很容易被误解的点你看到的界面其实是由好几个Surface合成的。Activity内容一个Surface、系统状态栏一个Surface、输入法一个Surface……SurfaceFlinger把它们按Z顺序混合后输出到屏幕。所以WMS说“窗口A在窗口B上面”最终是靠SurfaceFlinger的合成顺序落实的WMS是制定秩序的人SurfaceFlinger是实际画画的执行者。4.4 白屏黑屏其实发生在“假窗口”阶段之后很多人研究App冷启动优化会问为什么刚点开App会有短暂的白屏或黑屏。这个现象恰恰发生在WMS阶段你点击图标后系统为了给用户即时反馈会在真正的Activity窗口还没完成首帧绘制之前提前显示一个“StartingWindow”——就是一个只有纯色背景的窗口。它由WMS直接创建用于填补从启动到首帧之间的空档。如果主题背景是白色你看到的就是白屏背景是黑色看到的就是黑屏。这段“假窗口”什么时候消失当App首帧绘制完成、WMS把真正的内容窗口切换到前台时它才退场。所以冷启动优化里广为流传的“把启动背景设置成品牌色避免白屏突兀”本质是在跟WMS这个StartingWindow策略做配合而不是绕过WMS。5. 看懂系统层之后日常开发有哪几类问题能一眼定位说了半天架构最终还是要落到干活上。理解这些系统服务之后最大的收获不是面试能装而是排错的时候大脑里有地图不会再在App层的代码里瞎翻半天。5.1 异常名其实就是服务名先看最典型的一类android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy is not valid; is your activity running?看到这个异常直接去WMS那边找原因。最常见的场景就是你在某个Activity的协程/线程回调里异步弹了一个Dialog或PopupWindow结果弹起来的时候Activity已经销毁了。App打开Dialog时会尝试在Activity的window token下面添加一个子窗口而销毁之后WMS已经把这个token移掉了所以报BadToken。你再往下翻Dialog源码也只会看到它拿着从Activity拿来的token去调WindowManager真正判定token合法性的逻辑在WMS里。定位久了你会发现系统层服务名往往就写在异常类名里比如WindowManager对应WMSPackageManager.NameNotFoundException对应PMS的组件查询。5.2 ANR 与进程被杀先意识这是 AMS 的权限范围应用无响应ANR也是一种很典型的系统层事件。输入事件分发超时、广播处理超时、Service执行超时这些“超时观察者”散布在input系统、AMS和广播机制里但最后对话框的弹窗、日志上报、进程处置都汇集到AMS体系。你看Logcat里的ANR in ...接着往上一翻一定有一大段AMS打印的CPU、进程、Binder调用信息。如果App“想被系统杀死”而不是自己崩的先别急着改业务代码先用adb shell dumpsys activity processes看看那个进程的adj值是不是因为后台空闲被系统回收了。这是AMS的活不是业务bug。5.3 安装和权限问题大概率卡在PMSApp安装失败、解析包出问题、升级后签名冲突、跨用户安装失败——“安装了一个装了没反应”“adb install报INSTALL_FAILED_*”——这类基本都是PMS相关。还有运行时权限用户明明点了允许为什么checkPermission还是返回拒绝那很可能不是你的代码问题而是权限状态被PMS存储的数据库搞错或者你动态申请时传错了权限组名字。这时候查adb shell dumpsys package packageName里的runtime permissions段一眼就能看到这个包当前到底拿到了哪些权限。5.4 想读系统源码推荐从这个顺序切入如果看完文章想亲自去源码里验证我的建议是不要从头啃源码那太容易劝退。你可以按照“从外往里”的顺序先看SystemServer.java的main方法知道系统服务是怎么一个个被实例化的再看ActivityManagerService.java的构造函数和startActivity相关方法重点看它怎么处理ActivityRecord和TaskRecord接着看WindowManagerService.java的addWindow方法对应着Activity窗口创建的真正起点最后看PackageManagerService.java的installPackage相关方法了解APK安装的大致链路。搜源码别用Android Studio硬搜整个AOSP太慢用cs.android.com这种在线源码搜索服务或者把frameworks/base单独拉下来配个索引。看到哪一层卡住了就回到具体业务场景里去想“谁在这个环节做了决定”。比如你平时总为触摸事件分不到正确View而头疼那就去WMS看窗口命中的逻辑你总被后台进程回收困扰就去AMS看adj的计算表。我自己最开始读源码时其实犯过一个很蠢的错误试图把AMS的代码从头到尾通读一遍。后来才明白系统服务动辄上万行甚至几万行真正有营养的是理解它们彼此之间的调用边界和几个核心数据结构的流转。你不需要背代码你需要的是在遇到问题时能根据异常栈和现象“猜到”问题出在哪一个服务、哪一个环节然后再定点去翻源码验证。这套能力一旦建立起来很多看起来诡异的问题比如启动白屏、后台被杀、权限拿不到、窗口抢焦点基本都能在最早的几分钟内锁定方向。希望这篇能帮你把挂在嘴边的几个缩写真正变成脑子里的地图。