舆情网站直接打开,海口网站运营托管咨询,平安银行官方网站,网站的功能和特色0. 参考#xff1a;
ANR分析 深入理解 Android ANR 触发原理以及信息收集过程
1.ANR的触发分类:
ANR分为4类#xff1a;
InputDispatchTimeout#xff1a;输入事件分发超时5s,包括按键和触摸事件。BroadcastTimeout#xff1a;比如前台广播在10s内未执行完成#xff0…0. 参考
ANR分析 深入理解 Android ANR 触发原理以及信息收集过程
1.ANR的触发分类:
ANR分为4类
InputDispatchTimeout输入事件分发超时5s,包括按键和触摸事件。BroadcastTimeout比如前台广播在10s内未执行完成后台60sServiceTimeout前台服务在20s内未执行完成后台服务未在200s内完成。ContentProviderTimeoutcontenProvider在publish后超时10s
2.ANR的触发机制
2.1基本概念
ANR 的检测和处理逻辑主要写在 AMSActivity Manager Service 进程中当超时事件触发后AMS 会记录下应用主线程的状态并调用 ActivityManagerService.appNotResponding() 方法来启动 ANR 处理流程。当应用程序在UI线程阻塞太长时间就会弹出系统弹框询问我们继续等待还是关闭应用程序此时发生了ANR。
3.Service,BroadCast,Provider触发ANR:
3.1 ANR是在发生这些调用的时候就启用定时炸弹。
1.APP侧 在Activity中调用startService后调用链ContextImpl.startService()-ContextImpl.startServiceCommon() AMS侧 ActivityManagerService.startService() -ActiveServices.startServiceLocked() -ActiveServices.startServiceInnerLocked() -ActiveServices.bringUpServiceLocked() -ActivieServices.realStartServiceLocked() -ActivieServices.realStartServiceLocked 2.1 其中realStartServiceLocked主要通过向AMS发送一个Handler的延迟消息告诉AMS这个调用超时了。 private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,boolean enqueueOomAdj) throws RemoteException { // 2
...............// 记录此调用的开始---原因是 create// 从此处开始倒计时--发送handler消息到AMSbumpServiceExecutingLocked(r, execInFg, create, null /* oomAdjReason */);
................// 通知APP启动Service,执行 handleCreateService// 调用到 ApplicationThread.scheduleCreateServicethread.scheduleCreateService(r, r.serviceInfo,mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),app.mState.getReportedProcState());
..........2.2 ActivieServices.bumpServiceExecutingLocked----ActivieServices.scheduleServiceTimeoutLocked 这个延迟时间就是1中说到的超时20s, 对应ActiveService的SERVICE_TIMEOUT变量; void scheduleServiceTimeoutLocked(ProcessRecord proc) { // 2
...................Message msg mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_TIMEOUT_MSG);msg.obj proc;mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT); // 发送延迟消息给AMS的Handler}2.3 scheduleCreateService 会通过Binder调用回APP侧最终会调用到ApplicationThread.scheduleCreateService public final void scheduleCreateService(IBinder token,ServiceInfo info, CompatibilityInfo compatInfo, int processState) {updateProcessState(processState, false);CreateServiceData s new CreateServiceData();s.token token;s.info info;s.compatInfo compatInfo;sendMessage(H.CREATE_SERVICE, s); // 发送Handler消息}// 找到处理Handler消息的地方handleCreateService最终会调用到这个Service的onCreate方法上。case CREATE_SERVICE:if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,(serviceCreate: String.valueOf(msg.obj)));}handleCreateService((CreateServiceData)msg.obj); // 执行Service的回调onCreateTrace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;3 小结 1最开始调用了startService来触发AMS发送一个延迟为SERVICE_TIMEOUT20s的Handler事件 2并最终回调到实现了这个Service的onCreate函数。 3如果超过了20s这个Handler消息还是没被取消那么就会去触发AMS的ANR机制。
3.2 取消延迟发送的Handler消息, “取消炸弹”
在上面描述的正常流程中会调用到handleCreateService最终会调用removeMessages取消3.1中的延迟发送的Handler消息 private void handleCreateService(CreateServiceData data) {
.....service.onCreate(); // 进入service的onCreate回调
....// Service启动完成需要通知AMSActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
.....}public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {synchronized(this) {if (!(token instanceof ServiceRecord)) {Slog.e(TAG, serviceDoneExecuting: Invalid service token token);throw new IllegalArgumentException(Invalid service token);}// 执行到ActivityManagerService的 serviceDoneExecuting方法mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false);}}// ActivityManagerService的 serviceDoneExecuting方法private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,boolean finishing, boolean enqueueOomAdj) {
......// 将Handler消息取消mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
..........}3.3 ANR的触发, “炸弹引爆”
就是延迟发送的Handler消息处理 在ActivityManagerService.java可看到处理SERVICE_TIMEOUT_MSG的代码 case SERVICE_TIMEOUT_MSG: {// 调用到ActiveServices的serviceTimeout方法mServices.serviceTimeout((ProcessRecord) msg.obj);} break;//com.android.server.am.ActiveServices.javavoid serviceTimeout(ProcessRecord proc) {................// 计算是否超时if (anrMessage ! null) { // 超时// 触发超时机制mAm是AMSmAnrHelper是AnrHelpermAm.mAnrHelper.appNotResponding(proc, anrMessage); }}调用到AnrHelper的appNotResponding方法最终是调用到AmrConsumerThread().start方法来处理ANR void appNotResponding(ProcessRecord anrProcess, String annotation) {appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,null /* parentShortComponentName */, null /* parentProcess */,false /* aboveSystem */, annotation);}void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,ApplicationInfo aInfo, String parentShortComponentName,WindowProcessController parentProcess, boolean aboveSystem, String annotation) {synchronized (mAnrRecords) {mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,parentShortComponentName, parentProcess, aboveSystem, annotation));}startAnrConsumerIfNeeded();}private void startAnrConsumerIfNeeded() {if (mRunning.compareAndSet(false, true)) {new AnrConsumerThread().start(); // 启动AnrConsumerThread线程处理ANR}}
private class AnrConsumerThread extends Thread {Overridepublic void run() {AnrRecord r;while ((r next()) ! null) {......//这里的r就是AnrRecordr.appNotResponding(onlyDumpSelf);......}}
}
private static class AnrRecord {void appNotResponding(boolean onlyDumpSelf) {//mApp是ProcessRecordmErrorState是ProcessErrorStateRecordmApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,onlyDumpSelf);}
}
调用到ProcessErrorStateRecord.appNotResponding来弹出无响应弹出。或者dump操作啥的就是平时见到的ANR
3.4 ANR做了哪些事情
主要就是记录ANR错误的相关信息 弹出ANR的弹窗最终会调用到ProcessErrorStateRecord的appNotResponding下面来研究ProcessErrorStateRecord.java的这个函数 void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,String parentShortComponentName, WindowProcessController parentProcess,boolean aboveSystem, String annotation, boolean onlyDumpSelf) { //
........// 将ANR的相关信息记录到anr文件中StringBuilder info new StringBuilder();
.....StringBuilder report new StringBuilder();....................// 弹出ANR的Dialogif (mService.mUiHandler ! null) {// Bring up the infamous App Not Responding dialogMessage msg Message.obtain();msg.what ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;msg.obj new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);}}}
小结 1)在调用得时候发送了延迟HANDLER消息SERVICE_TIMEOUT_MSG 2)到了延时时间还未remove掉此handler消息那么就会触发SERVICE_TIMEOUT_MSG的处理。 3)最终调用到AnrHelper的appNotResponding来处理ANR
4.Input触发ANR:
4.1 从linux侧获取input事件
如inputFlinger 讲解的内容InputReader线程通过EventHub监听/dev/input读取输入事件监听到事件则把消息传到InputDispatcher即InputReader把消息写入mInBoundQueue队列InputDispatcher负责把输入事件分发给 目标应用窗口。
4.2 ANR相关
InputDispatcher的流程
4.3 ANR触发 代码流程梳理
InputDispatcher中的方法调用 1.有等待获取焦点的应用当前时间超过Timeout调用processNoFocusedWindowAnrLocked() 进一步确认 2.存在window当前时间超过事件响应的超时时间。调用onAnrLocked() 进一步确认。 frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp// 检查是否有任何连接的等待队列具有太旧的事件。如果我们等待事件被确认的时间超过窗口超时
// 请引发 ANR。返回我们下次应该醒来的时间。
nsecs_t InputDispatcher::processAnrsLocked() {const nsecs_t currentTime now();nsecs_t nextAnrCheck LONG_LONG_MAX; // 下一次检查anr的时间// 检查我们是否正在等待一个聚焦窗口出现。如果等待时间过长就报 ANRif (mNoFocusedWindowTimeoutTime.has_value() mAwaitedFocusedApplication ! nullptr) {if (currentTime *mNoFocusedWindowTimeoutTime) {// 场景1: 触发noFocusedWindow的anrprocessNoFocusedWindowAnrLocked();mAwaitedFocusedApplication.reset();mNoFocusedWindowTimeoutTime std::nullopt;return LONG_LONG_MIN;} else {// 请继续等待。我们将在mNoFocusedWindowTimeoutTime到来时放弃该事件。nextAnrCheck *mNoFocusedWindowTimeoutTime;}}// 检查是否有任何连接 ANR 到期mAnrTracker 中保存所有已分发事件未被确认消费的事件的超时时间nextAnrCheck std::min(nextAnrCheck, mAnrTracker.firstTimeout());if (currentTime nextAnrCheck) { // 最有可能的情况// 一切正常在 nextAnrCheck 再检查一次return nextAnrCheck;}// 如果我们到达这里则连接无响应。spConnection connection getConnectionLocked(mAnrTracker.firstToken());// 停止为此无响应的连接唤醒mAnrTracker.eraseToken(connection-inputChannel-getConnectionToken());// 场景2: 触发ANRonAnrLocked(connection);return LONG_LONG_MIN;
}
4.4 ANR在InputDispatcher的调用栈 #mermaid-svg-N4avwh0BIJWNEu7I {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-N4avwh0BIJWNEu7I .error-icon{fill:#552222;}#mermaid-svg-N4avwh0BIJWNEu7I .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-N4avwh0BIJWNEu7I .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-N4avwh0BIJWNEu7I .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-N4avwh0BIJWNEu7I .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-N4avwh0BIJWNEu7I .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-N4avwh0BIJWNEu7I .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-N4avwh0BIJWNEu7I .marker{fill:#333333;stroke:#333333;}#mermaid-svg-N4avwh0BIJWNEu7I .marker.cross{stroke:#333333;}#mermaid-svg-N4avwh0BIJWNEu7I svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-N4avwh0BIJWNEu7I .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-N4avwh0BIJWNEu7I text.actortspan{fill:black;stroke:none;}#mermaid-svg-N4avwh0BIJWNEu7I .actor-line{stroke:grey;}#mermaid-svg-N4avwh0BIJWNEu7I .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-N4avwh0BIJWNEu7I .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-N4avwh0BIJWNEu7I #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-N4avwh0BIJWNEu7I .sequenceNumber{fill:white;}#mermaid-svg-N4avwh0BIJWNEu7I #sequencenumber{fill:#333;}#mermaid-svg-N4avwh0BIJWNEu7I #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-N4avwh0BIJWNEu7I .messageText{fill:#333;stroke:#333;}#mermaid-svg-N4avwh0BIJWNEu7I .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-N4avwh0BIJWNEu7I .labelText,#mermaid-svg-N4avwh0BIJWNEu7I .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-N4avwh0BIJWNEu7I .loopText,#mermaid-svg-N4avwh0BIJWNEu7I .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-N4avwh0BIJWNEu7I .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-N4avwh0BIJWNEu7I .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-N4avwh0BIJWNEu7I .noteText,#mermaid-svg-N4avwh0BIJWNEu7I .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-N4avwh0BIJWNEu7I .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-N4avwh0BIJWNEu7I .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-N4avwh0BIJWNEu7I .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-N4avwh0BIJWNEu7I .actorPopupMenu{position:absolute;}#mermaid-svg-N4avwh0BIJWNEu7I .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-N4avwh0BIJWNEu7I .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-N4avwh0BIJWNEu7I .actor-man circle,#mermaid-svg-N4avwh0BIJWNEu7I line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-N4avwh0BIJWNEu7I :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} dispatchOnce findFocusedWindowTargetsLocked processAnrsLocked processNoFocusedWindowAnrLocked onAnrLocked postCommandLocked updateLastAnrStateLocked processConnectionUnresponsiveLocked sendMonitorUnresponsiveCommandLocked sendWindowUnresponsiveCommandLocked runCommandsLockedInterruptible command 赋值mNoFocusedWindowTimeoutTime return 触发ANR检查 case 1: 失去焦点时间mNoFocusedWindowTimeoutTime过长 onAnrLocked(application) 向mCommandQueue中写入数据 return case 2: 连接过期触发ANR, onAnrLocked(connection) onAnrLocked(connection) return 记录ANR相关 case 1 case 2 return 捕获 ANR 时 InputDispatcher 状态的记录。 处理postCommandLocked写入的 mCommandQueue 调用command处理 dispatchOnce findFocusedWindowTargetsLocked processAnrsLocked processNoFocusedWindowAnrLocked onAnrLocked postCommandLocked updateLastAnrStateLocked processConnectionUnresponsiveLocked sendMonitorUnresponsiveCommandLocked sendWindowUnresponsiveCommandLocked runCommandsLockedInterruptible command 6.排查思路
adb shell getevent后点击屏幕如果有打印代表驱动是可以拿到点击事件的。如果没有则需要内核的同事查看。如果有则代表是Android的问题。