Android ANR产生过程解析
Android2.2及此前,输入事件处理都在Java层,Android2.3及之后,为提高处理效率,输入事件处理移到了Native 层。
为了简化分析,本文的分析是基于Android2.2的源码。
1、ANR产生机制:
硬件收集到的输入事件都会插入到WindowManagerService.mQueue(KeyQ类)中,同时
WindowManagerService.InputDispatcherThread这个线程运行在系统进程中,它循环地处理
mQueue内的消息。InputDispatcherThread在处理事件的过程中,会不断的检测处理过程是否超时,一旦超时,会通过一
系列的回调通知AMS,由AMS控制弹出ANR对话框。
超时检测处理过程实际上是一个wait()/notify()的过程。首先,如果一个输入事件进入检测流程时,发现当前正在处理输入事件,就会调用
wait()阻塞输入事件处理线程,wait的时间为10s。在一个输入事件处理完成时,会调用notify()让输入事件处理线程继续执
行。继续执行时就会计算整个过程一共花了多长时间来判断是否是ANR。
2、流程解析:
a)输入事件1到达,发现KeyWaitter的mFinished(事件已经处理完成)为true,无需等待,直接异步将事件1移交 ViewRoot 进行处理,并把mFinished置为false。
b)ViewRoot处理事件1时,会同步地进行事件分发处理,分发完成后才执行KeyWaitter.finishKey()方法。
注:finishKey()方法会把mFinished置为false,并调用notify()唤醒
InputDispatcherThread线程。
c)在事件1的分发过程中发现它是点击事件,回调到View.onClick()方法,于是同步执行了耗时任务,导致ViewRoot卡在这
个分发流程。
d)事件2到达,发现KeyWaitter的mFinished是false,调用wait()方法将
InputDispatcherThread线程置为等待状态,且wait()的时间为10s。
e)10内,由于在c中没有执行KeyWaitter.finishKey()方法,所以InputDispatcherThread一直处
于等待状态。
f)10s后,InputDispatcherThread线程继续执行,计算时间后发现已经超时,随后通知AMS弹出ANR对话框。
3、时序图:

4、相关代码:
1、输入事件的检测流程:
WindowManagerService.java
.................KeyWaitter.waitForNextEventTarget()方 法.................
1 ................. 2 long startTime = SystemClock.uptimeMillis(); 3 long keyDispatchingTimeout = 5 * 1000; 4 ................. 5 while (true) { 6 ................. 7 long curTimeout = keyDispatchingTimeout; 8 ................. 9 try { 10 // after that continue 11 // processing keys, so we don't get stuck. 12 if (DEBUG_INPUT) Slog.v( 13 TAG, "Waiting for key dispatch: " + curTimeout); 14 wait(curTimeout); 15 if (DEBUG_INPUT) Slog.v(TAG, "Finished waiting @" 16 + SystemClock.uptimeMillis() + " startTime=" 17 + startTime + " switchTime=" + mTimeToSwitch 18 + " target=" + targetWin + " mLW=" + mLastWin 19 + " mLB=" + mLastBinder + " fin=" + mFinished 20 + " mCurrentFocus=" + mCurrentFocus); 21 } catch (InterruptedException e) { 22 } 23 ................. 24 if (mWasFrozen) { 25 waitedFor = 0; 26 mWasFrozen = false; 27 } else { 28 waitedFor = SystemClock.uptimeMillis() - startTime; 29 } 30 31 if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) { 32 ................. 33 if (at != null) { 34 try { 35 long timeout = at.getKeyDispatchingTimeout(); 36 if (timeout > waitedFor) { 37 // we did not wait the proper amount of time for this application. 38 // set the timeout to be the real timeout and wait again. 39 keyDispatchingTimeout = timeout - waitedFor; 40 continue; 41 } else { 42 abort = at.keyDispatchingTimedOut(); 43 } 44 } catch (RemoteException ex) { 45 } 46 } 47 ................. 48 ................. 49 .................
2、处理完输入事件时的操作:
ViewRoot.java
..........handleMessage()方法...........
1 ..................... 2 case DISPATCH_POINTER: { 3 try { 4 ..................... 5 handled = mView.dispatchTouchEvent(event); 6 ..................... 7 }finally { 8 if (callWhenDone) { 9 try { 10 sWindowSession.finishKey(mWindow); 11 } catch (RemoteException e) { 12 } 13 } 14 ..................... 15 }
WindowManagerService.java
..........KeyWaitter.finishedKey()方法..........
1 ..................... 2 notifyAll(); 3 .....................
3、弹出ANR对话框:
ActivityManagerService.java
1 ................. 2 final Handler mHandler = new Handler() { 3 public void handleMessage(Message msg) { 4 ................. 5 case SHOW_NOT_RESPONDING_MSG: { 6 synchronized (ActivityManagerService.this) { 7 HashMap data = (HashMap) msg.obj; 8 ProcessRecord proc = (ProcessRecord)data.get("app"); 9 if (proc != null && proc.anrDialog != null) { 10 Slog.e(TAG, "App already has anr dialog: " + proc); 11 return; 12 } 13 14 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"), 15 null, null, 0, null, null, null, 16 false, false, MY_PID, Process.SYSTEM_UID); 17 18 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, 19 mContext, proc, (HistoryRecord)data.get("activity")); 20 d.show(); 21 proc.anrDialog = d; 22 } 23 24 ensureBootCompleted(); 25 } 26 .........

浙公网安备 33010602011771号