強大的測試組居然測出不少android架構級的bug,其中有一個現象如下:
故事是這樣發生的,當焦點放在地址欄時,會彈出SearchDialog,而在下方會有一個popup window用於顯示訪問曆史,這是IME也會冒出來,此時,如果隱藏掉IME(比如按IME的關閉按鈕,或者在listview處滑動)再按back鍵,重點來了,按back鍵之後快速滑動瀏覽器頁面,奇蹟發生了,瀏覽器居然被一大塊白板給遮蓋了!!!
起初發現該問題是還是偶發的,但任何一個偶發現象都有其必然規律,終於在不懈的嘗試與分析下,發現了上面的必現路徑。
有事解一個問題真的需要運氣,比如這次,我發現,當白板出現時,按menu退出瀏覽器,這是發現,瀏覽器再臨死前還是留下了兇手的一些蛛絲馬跡:
01-21 13:14:24.507: ERROR/WindowManager(3834): Activity com.android.browser.BrowserActivity has leaked window android.widget.PopupWindow$PopupViewContainer@48326088 that was originally added here<br />01-21 13:14:24.507: ERROR/WindowManager(3834): android.view.WindowLeaked: Activity com.android.browser.BrowserActivity has leaked window android.widget.PopupWindow$PopupViewContainer@48326088 that was originally added here<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.view.ViewRoot.<init>(ViewRoot.java:247)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.view.Window$LocalWindowManager.addView(Window.java:424)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.widget.PopupWindow.invokePopup(PopupWindow.java:828)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.widget.PopupWindow.showAsDropDown(PopupWindow.java:740)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1207)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.widget.AutoCompleteTextView$ResizePopupRunnable.run(AutoCompleteTextView.java:1452)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.os.Handler.handleCallback(Handler.java:587)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.os.Handler.dispatchMessage(Handler.java:92)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.os.Looper.loop(Looper.java:123)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at android.app.ActivityThread.main(ActivityThread.java:4627)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at java.lang.reflect.Method.invokeNative(Native Method)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at java.lang.reflect.Method.invoke(Method.java:521)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:876)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:634)<br />01-21 13:14:24.507: ERROR/WindowManager(3834): at dalvik.system.NativeStart.main(Native Method)
android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1207)
01-21 13:14:24.507: ERROR/WindowManager(3834): at android.widget.AutoCompleteTextView$ResizePopupRunnable.run(AutoCompleteTextView.java:1452)
AutoCompleteTextView!!
多麼可疑!
畢竟AutoCompleteTextView生活在SearchDialog的世界中,而死者致死的白板多麼像一個popupwindow啊,而且死者臨死前竟也指出了兇手的手段(AutoCompleteTextView.showDropDown)。
深入AutoCompleteTextView.showDropDown家中調查發現,他平日便是靠著剪裁各種大小的白板(mPopup.setWindowLayoutMode(widthSpec, heightSpec))為生 。在他家偷偷裝上網路攝影機,發現
(noInputMethod == true && !mPopup.isShowing())二者一起出現的時候,瀏覽器必死!看來是漏網之魚!
兇手出現了,漏洞找到了,亡羊補牢,為時不晚,於是,法規上增加一條:當mPopup沒有顯示,並且IME也不存在的時候,禁止AutoCompleteTextView製造高度大於0 的白板:
if (mPopup.isShowing()) {
……
}else{
if(noInputMethod == true)
heightSpec = 0;
else if(……){
}else{
}
}
這樣瀏覽器從此果然沒有再被害。
看來google的法規還有待完善啊,其實這種解法僅僅是解決了出口,源頭沒有封堵。
比如,看這個介面:
private class PopupTouchInterceptor implements OnTouchListener {<br /> public boolean onTouch(View v, MotionEvent event) {<br /> final int action = event.getAction();<br /> if (action == MotionEvent.ACTION_DOWN &&<br /> mPopup != null && mPopup.isShowing()) {<br /> postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);<br /> } else if (action == MotionEvent.ACTION_UP) {<br /> removeCallbacks(mResizePopupRunnable);<br /> }<br /> return false;<br /> }<br /> }
其實問題就出在這,當popupwindow還顯示的時候,你觸碰TP,他會收到ACTION_DOWN事件,並在250ms後執行showDropDown的動作,但問題就在於,ACTION_DOWN之後,AutoCompleteTextView已經不存在了,本來需要的ACTION_UP事件現在肯定收不到了,這就出現了無法在250ms內將發出去的事件收回,“刀下留人”也來不及了!