android anr input 流程分析


我这里将input anr分两大部分,一个是焦点窗口相关,一个是焦点事件相关

1 焦点窗口

在每次监测anr的时候,最先检查的是焦点窗口的获取情况
在监测事件是否超时之前有一个方法监测焦点窗口的,findFocuseWindowTargetsLocked()
这个主要处理无焦点的情况。
比如 有焦点app无焦点window的情况
比如 无焦点app无焦点window的情况
比如 焦点窗口paused状态的情况,代码里都打印了对应的log说明,这些都可以归为无焦点问题
而这些问题往往出现在monkey,后台冻结,快速切换页面等情况下产生,有些问题是不需要解决的(用户不会在快速切换的时候,还能快速的点击
这里简单概况下这类anr问题,切换或启动app时候,当前进程被杀死,被freeze,被降频(或cpu被低内存交换操作占用,大量文件读写)导致变慢等都会引起anr
还有一种是焦点窗口快速的切换,导致事件卡在了一个已经进入pause状态的页面,也会导致anr
这种的情况主要排查event log及 进程状态及进程号是否,这里要注意的是 页面更新的流程是surfaceflinger那边发来的消息。

2 焦点事件


整个输入事件流是一个生产者消费者的waitQueue,而且这个queue只能有一个成员,多的就要等待
超过等待时间就会报anr。这类问题比较常见,总之就是整条链路依次排查卡住的地方。
这里由于没有关于surfacefinger的一环,流程大概就是
开始于:inputdispater.cpp类里dispatchOnceInnerLocked-
结束于:(viewrootimpl里面的finishinputevent流程)app进程的InputTransport.cpp sendFinishedSignal到inputdispater.cpp进行消除

3 最后列下两种流程对应的system_server端调用流程

1 页面切换(sf通过binder的方式发过来)

mystack : #00 pc 00000000000359cc  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::setInputWindowsLocked(std::__1::vector<android::sp<android::InputWindowHandle>, std::__1::allocator<android::sp<android::InputWindowHandle> > > const&, int)+88)
01-01 14:12:42.490  1079  1995 D mystack : #01 pc 0000000000035920  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::setInputWindows(std::__1::unordered_map<int, std::__1::vector<android::sp<android::InputWindowHandle>, std::__1::allocator<android::sp<android::InputWindowHandle> > >, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, std::__1::vector<android::sp<android::InputWindowHandle>, std::__1::allocator<android::sp<android::InputWindowHandle> > > > > > const&)+64)
01-01 14:12:42.490  1079  1995 D mystack : #02 pc 000000000002675c  /system/lib64/libinputflinger.so (android::InputManager::setInputWindows(std::__1::vector<android::InputWindowInfo, std::__1::allocator<android::InputWindowInfo> > const&, android::sp<android::ISetInputWindowsListener> const&)+408)
01-01 14:12:42.490  1079  1995 D mystack : #03 pc 0000000000026a08  /system/lib64/libinput.so (android::BnInputFlinger::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+804)
01-01 14:12:42.490  1079  1995 D mystack : #04 pc 000000000004982c  /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+232)
01-01 14:12:42.490  1079  1995 D mystack : #05 pc 0000000000052210  /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+1032)
01-01 14:12:42.490  1079  1995 D mystack : #06 pc 0000000000051d58  /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+156)
01-01 14:12:42.490  1079  1995 D mystack : #07 pc 0000000000052590  /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+60)
01-01 14:12:42.490  1079  1995 D mystack : #08 pc 0000000000078618  /system/lib64/libbinder.so (android::PoolThread::threadLoop()+24)
01-01 14:12:42.490  1079  1995 D mystack : #09 pc 00000000000154d0  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+260)
01-01 14:12:42.490  1079  1995 D mystack : #10 pc 00000000000a1be0  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)
01-01 14:12:42.490  1079  1995 D mystack : #11 pc 0000000000014d94  /system/lib64/libutils.so (thread_data_t::trampoline(thread_data_t const*)+412)
01-01 14:12:42.490  1079  1995 D mystack : #12 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64)
01-01 14:12:42.490  1079  1995 D mystack : #13 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)


2 发送消息的调用流程(inputchannal的sorctpair方式)
01-01 14:16:11.753  1079  1149 D mystack2: #00 pc 0000000000032994  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::handleReceiveCallback(int, int, void*)+80)
01-01 14:16:11.753  1079  1149 D mystack2: #01 pc 0000000000019dac  /system/lib64/libutils.so (android::Looper::pollInner(int)+916)
01-01 14:16:11.753  1079  1149 D mystack2: #02 pc 00000000000199b0  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
01-01 14:16:11.753  1079  1149 D mystack2: #03 pc 00000000000286d4  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::dispatchOnce()+200)
01-01 14:16:11.753  1079  1149 D mystack2: #04 pc 0000000000006718  /system/lib64/libinputflinger_base.so (android::(anonymous namespace)::InputThreadImpl::threadLoop()+24)
01-01 14:16:11.753  1079  1149 D mystack2: #05 pc 0000000000015598  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+460)
01-01 14:16:11.753  1079  1149 D mystack2: #06 pc 00000000000a1be0  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)
01-01 14:16:11.753  1079  1149 D mystack2: #07 pc 0000000000014d94  /system/lib64/libutils.so (thread_data_t::trampoline(thread_data_t const*)+412)
01-01 14:16:11.753  1079  1149 D mystack2: #08 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64)
01-01 14:16:11.753  1079  1149 D mystack2: #09 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
01-01 14:16:11.781  1079  1149 D mystack2: #00 pc 0000000000032994  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::handleReceiveCallback(int, int, void*)+80)
01-01 14:16:11.781  1079  1149 D mystack2: #01 pc 0000000000019dac  /system/lib64/libutils.so (android::Looper::pollInner(int)+916)
01-01 14:16:11.781  1079  1149 D mystack2: #02 pc 00000000000199b0  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
01-01 14:16:11.781  1079  1149 D mystack2: #03 pc 00000000000286d4  /system/lib64/libinputflinger.so (android::inputdispatcher::InputDispatcher::dispatchOnce()+200)
01-01 14:16:11.781  1079  1149 D mystack2: #04 pc 0000000000006718  /system/lib64/libinputflinger_base.so (android::(anonymous namespace)::InputThreadImpl::threadLoop()+24)
01-01 14:16:11.781  1079  1149 D mystack2: #05 pc 0000000000015598  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+460)
01-01 14:16:11.781  1079  1149 D mystack2: #06 pc 00000000000a1be0  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)
01-01 14:16:11.781  1079  1149 D mystack2: #07 pc 0000000000014d94  /system/lib64/libutils.so (thread_data_t::trampoline(thread_data_t const*)+412)
01-01 14:16:11.781  1079  1149 D mystack2: #08 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64)
01-01 14:16:11.782  1079  1149 D mystack2: #09 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)

### ANR 原理 ANR(Application Not Responding)是指当 Android 应用程序由于某些原因无法及时响应用户的交互或系统请求时,系统弹出的一个对话框提示用户当前应用无响应。这种现象通常是由于主线程被长时间占用而引起的。 在 Android 中,ANR 主要有以下几种触发条件: 1. **Input Dispatching Timeout (输入事件分发超时)**:如果主线程超过 5 秒未处理任何用户输入事件(如点击、滑动等),则会触发 ANR[^3]。 2. **BroadcastReceiver 超时**:如果 `BroadcastReceiver` 的回调函数 `onReceive()` 执行时间超过了 10 秒,则会触发 ANR[^4]。 3. **Service 启动超时**:如果某个 Service 在启动过程中花费了过长时间(默认为 20 秒),也会导致 ANR 发生。 这些超时行为的根本原因是主线程被阻塞或者过度负载,从而无法及时完成必要的任务。 --- ### ANR 处理流程 #### 1. 确定问题根源 为了有效解决 ANR 问题,首先需要明确引发该问题的具体原因。这可以通过分析日志文件来实现。常见的做法是从 `/data/anr/traces.txt` 文件中提取堆栈跟踪信息并定位到具体的代码位置。 #### 2. 使用异步线程优化性能 为了避免主线程因执行耗时操作而导致卡顿,可以采用多线程技术将繁重的工作转移到后台线程中运行。例如,通过创建子线程或利用现有的并发工具库(如 `AsyncTask`, `HandlerThread`, 或者更现代的 `Kotlin Coroutines` 和 `Java Executor Frameworks` 来管理复杂的计算任务[^5]。 以下是基于 Java 的简单示例展示如何使用 Handler 将工作移至背景线程: ```java new Thread(new Runnable() { @Override public void run() { // 这里放置耗时的操作 performLongRunningOperation(); // 更新UI需切换回主线程 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { updateUiAfterCompletion(); } }); } }).start(); ``` 对于广播接收器中的情况,推荐的做法是不直接在此处做大量数据处理而是交由 IntentService 完成进一步的任务调度。 #### 3. 减少不必要的资源消耗 除了合理分配线程外,还应关注减少内存泄漏和频繁GC带来的影响。比如关闭不再使用的连接池实例;释放Bitmap对象所占空间等等措施均有助于提升整体流畅度[^1]。 #### 4. 测试与监控 最后,在开发周期内持续进行压力测试以验证改进效果,并借助第三方平台实施线上实时监测以便快速发现潜在隐患[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值