【Android FrameWork】延伸阅读:ActivityManagerService启动Activity

AMS 启动 Activity

在 Android 系统中,用户点击应用图标或调用startActivity()时,看似简单的 "界面跳转",实则是 AMS(运行于 SystemServer 进程)与应用进程、Zygote 进程、WMS(窗口管理服务)等多角色协同的复杂过程。

整个流程以 "跨进程通信(Binder)" 为纽带,围绕 "组件校验→栈管理→进程准备→Activity 创建→窗口显示" 展开。

本文将按时序拆解每个关键环节,还原 Activity 从 "启动请求" 到 "用户可见" 的全链路。

启动流程的核心角色与数据结构

在深入流程前,需明确参与方及关键数据结构(部分已在前文提及,此处聚焦启动场景):

角色 / 结构 归属进程 核心作用
AMS(ActivityManagerService) SystemServer 进程 统筹启动流程:校验权限、管理任务栈、调度进程、通知应用创建 Activity
ActivityManager 应用进程 AMS 的客户端代理,应用通过它发起startActivity()请求(封装 Binder 调用)
ApplicationThread 应用进程 应用进程的 Binder 服务端,接收 AMS 的指令(如 "创建 Activity""触发生命周期")
ActivityThread 应用进程 应用的主线程调度器,负责执行 Activity 生命周期、创建 Activity 实例
ActivityRecord SystemServer 进程 单 Activity 的状态载体:记录组件信息(如ComponentName)、生命周期状态、所属任务栈
TaskRecord SystemServer 进程 任务栈载体:管理同一任务下的所有 ActivityRecord,保证 "返回栈" 逻辑
ActivityStackSupervisor SystemServer 进程 任务栈的顶层管理者:决定 Activity 入哪个栈、是否创建新栈、调整栈内 Activity 顺序
Zygote 进程 独立进程 孵化器:接收 AMS 请求,创建新的应用进程(若目标进程未启动)
WMS(WindowManagerService) SystemServer 进程 窗口管理者:在 Activity resume 阶段,接收 AMS 指令,添加 Activity 窗口并显示

startActivity到 AMS 调用

应用进程(如当前运行的 Activity 所在进程)发起启动请求时,并非直接操作 Activity,而是通过 "代理→Binder 通信" 将请求传递给 AMS。

具体步骤如下:

1. 应用层调用:startActivity()的上层封装

无论是用户点击按钮调用startActivity(new Intent(this, TargetActivity.class)),还是系统发起的启动(如启动桌面 Launcher),最终都会进入ContextImpl的实现(应用的Context实际是ContextImpl实例),核心调用链为:

java 复制代码
// 应用层调用

Activity.startActivity(Intent);

→ ContextImpl.startActivity(Intent);

→ ActivityManager.startActivity(Intent) // 应用进程的AMS代理(ActivityManager)

此处的ActivityManager是应用进程的 "客户端代理",它不直接处理逻辑,而是将请求通过 Binder 发送给 SystemServer 进程的 AMS。

2. Instrumentation 拦截:启动前的应用层校验

ContextImpl.startActivity()中,会先经过Instrumentation(应用的 "工具类",负责监控组件生命周期)的拦截,执行基础校验:

  • 检查Intent是否为空、是否设置了目标组件(ComponentName);

  • 若为 "隐式 Intent",则通过PackageManager(PMS 的客户端代理)查询匹配的 Activity(避免无匹配组件导致启动失败)。

3. Binder 跨进程:请求传递至 AMS

Instrumentation校验通过后,会调用ActivityManager.getService().startActivityAsUser(...)------ 这里的getService()获取的是 AMS 的 Binder 代理(IActivityManager),通过 Binder 驱动,将启动请求从应用进程 "跨进程传递" 到 SystemServer 进程的 AMS。

AMS 校验、栈管理与进程判断

AMS 收到启动请求后,需完成 "合法性校验→任务栈调度→目标进程状态判断" 三大核心操作,这是决定启动能否继续的关键环节。

1. 合法性校验:权限与组件双重检查

AMS 首先执行严格校验,避免非法启动(若校验失败,直接抛出异常,如ActivityNotFoundException):

  • 组件校验 :通过 PMS 查询目标 Activity 是否在AndroidManifest.xml中注册(PMS 存储了所有应用的组件信息,AMS 与 PMS 同属 SystemServer 进程,可直接内存调用,无需 IPC);

  • 权限校验 :检查发起进程是否拥有启动目标 Activity 的权限(如目标 Activity 声明了android:permission,则需发起进程在 Manifest 中声明对应权限);

  • Intent 校验 :检查Intentflags是否合法(如FLAG_ACTIVITY_NEW_TASK是否符合栈管理规则)、目标 Activity 是否为 "导出状态"(android:exported="true",非本应用组件需导出才能被启动)。

2. 任务栈管理:创建 ActivityRecord 与调度 TaskRecord

校验通过后,AMS 会通过ActivityStackSupervisor(栈管理者)完成 "Activity 入栈" 逻辑,核心是创建ActivityRecord并分配到对应的TaskRecord

  1. 创建 ActivityRecord :AMS 为目标 Activity 创建ActivityRecord实例,记录关键信息(如发起进程 ID、目标组件名、生命周期状态初始化为INITIALIZING);

  2. 确定目标 TaskRecordActivityStackSupervisor根据Intentflags(如FLAG_ACTIVITY_NEW_TASK)和 "任务栈亲和性"(android:taskAffinity),决定 Activity 进入哪个栈:

  • IntentFLAG_ACTIVITY_NEW_TASK且无匹配亲和性的栈,则创建新的TaskRecord

  • 若有匹配的现有栈(如同应用的默认栈),则将ActivityRecord加入该栈的栈顶;

  1. 调整栈内顺序 :若存在 "栈内复用" 场景(如FLAG_ACTIVITY_SINGLE_TOP),则将目标ActivityRecord移至栈顶,同时销毁其上方的ActivityRecord(触发对应 Activity 的onDestroy())。

3. 进程判断:目标进程是否已启动

AMS 通过ActivityRecord关联的 "目标进程包名",查询系统中的ProcessRecord列表(记录所有进程状态),判断目标进程(即目标 Activity 所在的应用进程)是否已启动:

  • 情况 1:目标进程已启动:直接进入 "阶段 3",通知应用进程创建 Activity;

  • 情况 2:目标进程未启动:先触发 "进程创建流程",再进入后续步骤(这是冷启动与热启动的核心区别)。

AMS 请求 Zygote 创建进程

若目标进程未启动(如首次点击应用图标),AMS 需先请求 Zygote 创建新进程,流程如下:

  1. AMS 发起进程创建请求 :AMS 调用Process.start(),封装进程创建参数(如目标应用包名、进程名、uid/gid,这些信息从 PMS 获取),通过 Socket 通信(Zygote 监听特定 Socket 端口)将请求发送给 Zygote 进程;

  2. Zygote 创建进程 :Zygote 收到请求后,通过fork()系统调用复制自身进程(利用 Linux 写时复制机制,复用预加载的框架类和资源,加速进程创建),生成新的应用进程;

  3. 初始化应用进程 :新进程启动后,会执行ActivityThread.main()方法(应用进程的入口):

  • 创建ActivityThread实例(应用主线程管理器);

  • 初始化Looper(为主线程开启消息循环,处理 UI 和生命周期消息);

  • 创建ApplicationThread实例(应用的 Binder 服务端,用于接收 AMS 指令),并通过ActivityManager.getService().attachApplication(mAppThread)将其注册到 AMS;

  1. AMS 绑定进程与 ActivityRecord :AMS 收到attachApplication()请求后,将新进程的ProcessRecord与目标 Activity 的ActivityRecord关联,标记 "进程已就绪",进入下一步。

AMS 通过 Binder 触发 Activity 创建

无论目标进程是已启动还是新创建,AMS 最终都会通过ApplicationThread(应用的 Binder 服务端)向应用进程发送 "创建 Activity" 的指令,流程如下:

1. AMS 发起创建指令:scheduleLaunchActivity()

AMS 调用ApplicationThread.scheduleLaunchActivity(ActivityClientRecord)------ 此处的ActivityClientRecordActivityRecord的 "客户端副本",包含创建 Activity 所需的所有信息(如ActivityRecord引用、Intent、组件名),通过 Binder 传递到应用进程。

2. 应用进程接收指令:从 Binder 线程到主线程

应用进程的 Binder 线程池(负责接收 AMS 的 Binder 请求)收到scheduleLaunchActivity()后,会将任务封装为Message,通过Handler发送到应用主线程(ActivityThreadmH Handler)------ 因为 Android 要求 UI 操作和生命周期执行在主线程,Binder 线程不能直接操作。

3. 主线程处理:ActivityThread.handleLaunchActivity()

主线程的Looper处理Message时,调用ActivityThread.handleLaunchActivity(),这是应用进程创建 Activity 的核心入口,具体分两步:

  1. 创建 Activity 实例 :通过Instrumentation.newActivity(ClassLoader, className, intent)创建目标 Activity 实例(ClassLoader加载 Activity 类,避免类加载冲突);

  2. 初始化 Application(首次启动时) :若应用的Application未创建,会先通过Instrumentation.callApplicationOnCreate(app)创建Application并执行onCreate()(整个应用生命周期仅执行一次)。

Activity 生命周期执行与窗口显示

Activity实例创建后,ActivityThread会按顺序触发其生命周期方法,同时与 WMS 协同完成窗口显示,这是 Activity 从 "内存对象" 变为 "用户可见界面" 的关键环节。

1. 触发早期生命周期:onCreate()onStart()onPause()(当前栈顶 Activity)

  • onCreate()执行ActivityThread调用Instrumentation.callActivityOnCreate(activity, bundle),触发Activity.onCreate(savedInstanceState)------ 此时 Activity 完成布局加载(setContentView()),但窗口尚未显示;

  • onStart()执行 :紧接着调用callActivityOnStart(activity),触发onStart()------Activity 进入 "可见但不可交互" 状态;

  • 当前栈顶 Activity 暂停 :若启动新 Activity 前,已有 Activity 在栈顶(如从 A 启动 B),AMS 会先通知原 Activity 所在进程执行onPause()(通过ApplicationThread.schedulePauseActivity()),确保 "先暂停旧界面,再启动新界面"(避免界面重叠)。

2. AMS 与 WMS 协同:为新 Activity 准备窗口

在新 Activity 执行onStart()后,AMS 会向 WMS 发送 "添加窗口" 的请求:

  1. AMS 通知 WMS :AMS 调用WMS.addWindow(),传递ActivityRecord关联的窗口信息(如窗口大小、类型、所属进程);

  2. WMS 创建窗口对象 :WMS 为 Activity 创建WindowState实例(记录窗口状态),并分配窗口 Z 序(确保新 Activity 窗口在最上层);

  3. 应用进程创建 Window :应用进程的Activity通过PhoneWindowWindow的实现类)创建DecorView(窗口的根视图),并将setContentView()加载的布局添加到DecorView

3. 触发onResume():Activity 进入 "可交互" 状态

  • AMS 发起 resume 指令 :当 WMS 窗口准备就绪,AMS 调用ApplicationThread.scheduleResumeActivity(),通知应用进程触发onResume()

  • onResume()执行ActivityThread调用Instrumentation.callActivityOnResume(activity),触发Activity.onResume()------ 此时 Activity 的DecorView被添加到 WMS 的窗口体系中;

  • WMS 显示窗口 :WMS 通过SurfaceFlinger(图形渲染服务)将DecorView的内容渲染到屏幕,Activity 正式 "用户可见且可交互"。

总结

整个启动流程可概括为 "三进程协同、两重校验、一次窗口渲染"

  1. 三进程协同:应用进程(发起请求、创建 Activity)→ SystemServer 进程(AMS 统筹、WMS 管窗口)→ Zygote 进程(冷启动时创建应用进程);

  2. 两重校验 :应用层Instrumentation基础校验 → AMS 层权限 + 组件 + Intent 合法性校验;

  3. 一次窗口渲染 :从onCreate()加载布局到 WMS+SurfaceFlinger 渲染,完成 "内存对象→屏幕显示" 的转化。

关键设计思路:

  • 跨进程通信依赖 Binder :AMS 与应用进程的交互全靠IActivityManager(AMS 代理)和ApplicationThread(应用 Binder 服务端),确保指令高效传递;

  • 任务栈管理保证用户体验 :通过TaskRecordActivityStackSupervisor维护 "返回逻辑",让用户点击返回时能按启动顺序退出;

  • 多服务协同实现功能闭环:AMS 主导流程,PMS 提供组件信息,WMS 管理窗口,Zygote 负责进程创建,缺任一环节均无法完成启动。

相关推荐
用户41659673693552 小时前
Android 媒体库高效扫描器:基于协程与 `ContentObserver` 的 `FileScanner`
android
Arenaschi2 小时前
Android中的release下面的包有什么左右和debug 的包有什么区别
android
stevenzqzq2 小时前
android recyclerview缓存2_四级缓存机制
android·spring boot·缓存
用户69371750013842 小时前
Kotlin 函数详解:命名参数与默认参数值
android·后端·kotlin
卓修武K3 小时前
Android系统BUG:修改线程名目标错乱问题探究
android
二流小码农3 小时前
鸿蒙开发:支持自定义组件的跑马灯
android·ios·harmonyos
用户41659673693553 小时前
优化 WebView 图片长按体验:JS Bridge 实现原生与网页端分发机制
android
Jeled4 小时前
RecyclerView ViewHolder 复用机制详解(含常见错乱问题与优化方案)
android·学习·面试·kotlin
2501_915106325 小时前
iOS 抓包全流程指南,HTTPS 抓包、TCP 数据流分析与多工具协同的方法论
android·tcp/ip·ios·小程序·https·uni-app·iphone