对ActivityManagerService的一些认识和学习

Android的三大核心功能是ActivityManagerService.java,WindowManagerService.java和View.java。ActivityManagerService简称AMS。

AMS所提供的主要功能包括以下几项:

1、统一调度个应用的程序的Activity。应用程序要运行Activity,会首先报告AMS,然后由AMS决定该Activity是否可以启动,如果可以,AMS再通知应用程序指定的Activity。换句话说说运行Activity时各应用程序的内政,AMS并不干预,但是AMS必须知道各应用程序都运行了哪些Activity。

2、内存管理。Android官方声称,Activity退出后,其所在的进程并不会被立即杀死,从而在下次启动该Activity时能够提高启动速度,这些Activity只有当系统内存紧张时,才会被自动杀死,应用程序并不关心这些问题,这些都是在AMS中完成的。

3、进程管理,AMS向外提供了查询系统正在运行的进程信息的API。


 启动一个Activity有一下几种方式:

   1、在应用程序中调用startActivity()启动指定的Activity

    2、在home程序中点击一个应用图标

    3、按Back键结束当前Activity,自动启动上一个Activity

    4、长按Home键显示出任务列表,从中选择一个启动

   这四种方式的主体处理方式都是按照第一种启动方式运行,后面三种只是在前端处理消息上各有不同。

在Android中,Activity调度的基本思路是这样的,各应用要想启动新的Activity或者停止当前的Activity,都要首先报告给Ams,Ams内部为所有应用做了记录,当它接受到启动或者停止的报告后,首先更新内部记录,然后在通知各应用启动或者停止指定的Activity,由于Ams有所有Activity的记录,所以能根据系统内存的状态自动杀死后台的Activity。


 Ams中定义了几个重要的数据类,分别用来保存进程(Process)活动(Activity)和任务(Task)。

    1、进程数据类(ProcessRecord)

         该类在Framework/base/services/java/com/android/server/am路径下,和Ams有关的重要的类都在改目录下。

         一个APK文件运行时会对应一个进程,当然多个APK文件也可以运行在同一个进程内,ProcessRecord正是记录一个进程中的相关信息。


    2、ActivityRecord数据类

         Ams中使用ActivityRecord数据类保存每个Activity的信息。ActivityRecord就是Ams为每个Activity建立的档案。

       

    3、TaskRecord

          Ams使用任务的概念确保Activity启动和退出的顺序。

        



  


<think>我们正在分析一个在InputDispatcher线程中出现的monitor contention(监视器竞争)问题。该问题的具体描述是: "monitor contention with owner binder:2123_18 (3841) at void com.android.server.am.ActivityManagerService.attachApplication(android.app.IApplicationThread, long)(ActivityManagerService.java:5503) waiters=6 blocking from void com.android.server.am.ActivityManagerService$LocalService.broadcastCloseSystemDialogs(java.lang.String)(ActivityManagerService.java:18880)" ### 1. **问题分解** - **关键元素**: - **竞争位置**:`ActivityManagerService.attachApplication`(拥有锁的代码位置) - **阻塞位置**:`ActivityManagerService$LocalService.broadcastCloseSystemDialogs`(尝试获取锁的位置) - **竞争细节**: - 锁的持有者:Binder线程 `binder:2123_18` (进程ID 3841) - 等待线程数:6(包括当前被阻塞的线程) - 阻塞来源:`broadcastCloseSystemDialogs` 方法 ### 2. **锁竞争机制** 在Android系统中,`monitor contention`表示多个线程尝试获取同一个对象锁时发生竞争。此处: - **锁持有线程**:执行`attachApplication`的Binder线程(`binder:2123_18`)持有`ActivityManagerService`(AMS)的锁。 - **阻塞线程**:InputDispatcher线程尝试在`broadcastCloseSystemDialogs`方法中获取同一个AMS锁,但因锁被占用而阻塞。 ### 3. **涉及代码分析** - **`attachApplication`方法**: - 位于`ActivityManagerService.java:5503`[^1] - 作用:应用进程启动时,通过Binder调用向AMS注册自身(传递`IApplicationThread`代理对象) - 执行线程:`binder:2123_18`(属于system_server进程) - **`broadcastCloseSystemDialogs`方法**: - 位于`ActivityManagerService.java:18880`[^2] - 作用:广播关闭系统级对话框(如权限请求框、全局菜单) - 触发场景:当系统需要清理UI层时(例如按下HOME键或返回键) ### 4. **InputDispatcher为何调用AMS** InputDispatcher在分发输入事件(如按键)时,可能触发系统级操作: - **按键行为触发**:例如用户按下`BACK`键时,系统可能要求关闭当前对话框 - **调用链示例**: ```plaintext InputDispatcher.dispatchKeyEvent() → PhoneWindowManager.interceptKeyBeforeDispatching() // 按键拦截判断 → ActivityManagerService.closeSystemDialogs() // 请求关闭对话框 → LocalService.broadcastCloseSystemDialogs() // 内部服务调用 ``` 在`broadcastCloseSystemDialogs()`内部需要获取AMS锁[^3]: ```java public void broadcastCloseSystemDialogs(String reason) { synchronized (mGlobalLock) { // 竞争点! ... } } ``` ### 5. **阻塞对输入响应的影响** - **ANR风险**:InputDispatcher线程被阻塞超过5秒将导致`Input dispatching timed out` ANR - **卡顿现象**:即使未ANR,阻塞期间用户操作(如点击、滑动)会延迟响应 - **Trace表现**: ```plaintext |--InputDispatcher (state: Blocked) |--monitor contention: waiting for lock held by binder:2123_18 ``` ### 6. **解决方案方向** #### (1) **减少AMS锁持有时间** 优化`attachApplication`方法: - 将非关键操作移出同步块(如文件IO、跨进程调用) - 使用细粒度锁替换全局锁(如拆分`mGlobalLock`) #### (2) **避免InputDispatcher调用AMS** 修改按键处理逻辑: - 在`interceptKeyBeforeDispatching`中避免直接调用AMS同步方法 - 改为异步请求(如通过`Handler`发送消息到系统线程) #### (3) **锁调度优化** 提升锁公平性: - 检查是否因线程优先级导致饥饿(提升InputDispatcher优先级) - 分析锁依赖链,避免嵌套锁 ### 示例:Trace中的锁竞争关系 ```plaintext ┌── "binder:2123_18" (持有锁) │ at com.android.server.am.ActivityManagerService.attachApplication(ActivityManagerService.java:5503) │ ... (长时间操作) │ └── "InputDispatcher" (等待锁,阻塞中) at com.android.server.am.ActivityManagerService$LocalService.broadcastCloseSystemDialogs(ActivityManagerService.java:18880) at com.android.server.input.InputDispatcher.notifySystemDialogClosing(InputDispatcher.java:XXX) at ... (按键事件处理) ``` ### 结论 此`monitor contention`表明**InputDispatcher线程因等待AMS锁而阻塞**,直接原因是: 1. Binder线程`binder:2123_18`在`attachApplication`方法中长时间持有AMS锁 2. InputDispatcher在处理按键事件时需调用`broadcastCloseSystemDialogs`,该方法需获取同一把锁 3. 等待线程数达6个,说明系统存在严重锁竞争 优化需聚焦于缩短`attachApplication`的临界区或异步化按键触发的系统调用[^4]。 §§相关问题§§ 1. 如何通过Systrace量化`monitor contention`对输入延迟的影响? 2. Android系统中哪些常见操作会触发`broadcastCloseSystemDialogs`? 3. 如何检测`ActivityManagerService`的锁竞争问题? </think>在 Android 系统 trace 的 `inputdispatcher` 线程中出现 `monitor contention with owner binder:2123_18 (3841)...` 的日志,表示**输入事件分发线程因系统锁竞争被阻塞**,这是影响输入响应的严重性能问题。以下是关键分析: --- ### 一、问题本质:跨进程锁竞争 该日志的核心结构为: ```plaintext monitor contention with owner [锁持有者] at [持有锁的代码位置] waiters=[等待线程数] blocking from [请求锁的代码位置] ``` 具体含义: 1. **锁持有者**:`binder:2123_18 (3841)` - `binder:2123_18`:System Server 进程的 Binder 线程(ID 2123_18) - `(3841)`:进程 PID(通常是 `system_server`) 2. **锁竞争位置**: - **持有锁**:`ActivityManagerService.attachApplication()`(AMS 注册应用)[^1] - **请求锁**:`broadcastCloseSystemDialogs()`(关闭系统对话框)[^2] 3. **阻塞规模**: `waiters=6` 表示当前有 **6 个线程在等待同一把锁**(包括 InputDispatcher) --- ### 二、对输入系统的影响 当 InputDispatcher 线程被阻塞时: 1. **输入事件延迟** 所有触摸/按键事件无法及时分发,导致用户感知卡顿 $$事件延迟时间 \geq \text{锁持有时间} + \text{线程切换开销}$$ 2. **ANR 风险** 若阻塞超过 5 秒,将触发 `Input dispatching timed out` ANR 3. **阻塞链示例**: ```plaintext InputDispatcher (分发按键事件) └→ 调用 broadcastCloseSystemDialogs() // 例如处理 BACK 键关闭对话框 └→ 请求 ActivityManagerService 锁 └→ 锁被 attachApplication() 占用 ◀ 阻塞点! ``` --- ### 三、根本原因分析 #### 1. **锁持有者:`attachApplication()`** - **作用**:应用进程启动时向 AMS 注册 - **风险操作**: - 同步调用 PackageManager、WindowManager 等服务 - 加载应用资源(可能触发磁盘 I/O) - 初始化跨进程对象(如 Binder 代理) #### 2. **锁请求者:`broadcastCloseSystemDialogs()`** - **触发场景**: - 按 BACK/HOME 键关闭系统级对话框(如权限请求框) - 系统主动清理弹窗(如应用切换到后台) - **关键逻辑**: ```java public void broadcastCloseSystemDialogs(String reason) { synchronized (mGlobalLock) { // 竞争的系统锁 // 向所有应用广播 Intent.CLOSE_SYSTEM_DIALOGS } } ``` #### 3. **竞争放大因素** - `waiters=6` 表明系统存在**锁饥饿**(lock starvation) - 可能由以下原因加剧: - 高频应用启动(如连续打开多个应用) - 系统负载过高(CPU 或 I/O 瓶颈) - 锁粒度设计不合理(AMS 的 `mGlobalLock` 覆盖范围过大) --- ### 四、解决方案方向 1. **优化锁持有时间** - 在 `attachApplication()` 中: - 将非关键操作移出同步块(如日志记录、状态更新) - 用 `synchronized(子锁)` 替代全局锁 `synchronized(mGlobalLock)` 2. **异步化调用** 修改 `broadcastCloseSystemDialogs()` 逻辑: ```java // 改为异步广播避免阻塞 mHandler.post(() -> { synchronized (mGlobalLock) { ... } }); ``` 3. **锁监控工具** 使用 `LockStateMonitor` 或 `JFR` 抓取锁竞争热点: ```shell adb shell am lockprofile [process] --sampling 100ms ``` --- ### 五、Trace 中的关联证据 检查 System Server 线程状态: - **锁持有线程**:`binder:2123_18` 应在 `RUNNING` 状态持续较长时间 - **InputDispatcher**:显示 `SLEEPING` 或 `MONITOR` 状态 - **其他等待线程**:可能有 `WindowManager`/`PowerManager` 线程同样阻塞 > ⚠️ 此问题需优先解决,否则会引发连锁性卡顿[^3][^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值