一.概述
??本文主要介紹Android平臺下bug類型和產生原因、崩潰捕獲和收集解決方案、以及bugly的使用方法。Android平臺下bug類型主要有Crash、ANR、卡頓、服務器異常等。要實現Android Bug捕獲和收集的困難主要有這么幾個:
??1、如何捕獲崩潰;
??2、如何獲取堆棧信息;
??3、將錯誤日志上傳到指定服務器。
??采用騰訊bugly的錯誤日志功能能捕獲應用Java Crash、C/C++ Native Crash 、 ANR和卡頓,能夠滿足日常需求,且不需要額外準備接收服務器。使用bugly可以收集到已發布應用的異常,以便測試和開發人員發現和修改bug,對于提高軟件質量有著極大的幫助。
二.Android 平臺bug類型及產生原因分析
??為了更好的理解后面的內容,首先讓我們來了解一下Android的系統架構,從上圖我們可以看到,Android分為四個層,從高層到低層分別是應用程序層、應用程序框架層、系統運行庫層和linux核心層。
??簡單來說Android系統本質上通過底層精簡的Linux系統來啟動Android的Dalvik虛擬機,然后在這個虛擬機上跑Java應用,同時它封裝了大量java和c++的API供外部調用。
??Android 平臺bug類型主要有:Crash、ANR、卡頓、服務器異常等。
1,常見的Android Crash有兩類:一類是Java Exception異常,一類是Native Signal異常。java代碼導致jvm退出,彈出“程序已經崩潰”的對話框,最終用戶點擊關閉后進程退出。通過NDK,使用C/C++開發,導致進程收到錯誤信號,發生Crash,Android 5.0之前進程直接退出(閃退) , Android 5.0之后會彈“程序已崩潰”的對話框。
2,ANR全稱是Application Not Responding,是指應用程序未響應。
??Android系統對于一些事件需要在一定的時間內完成,如果超過預定時間未響應或者響應時間過長,會造成ANR。一般這時系統會彈出一個ANR對話框,用戶可自行選擇繼續等待或者停止當前程序運行。
??那么哪些場景會造成ANR呢?
- 1)、Service Timeout:比如前臺服務在20秒內未執行完成;
- 2)、BroadcastQueue Timeout:比如前臺廣播在在10秒內未執行完成;
- 3)、ContentProvider Timeout:內容提供者,在punlish過超時10秒;
- 4)、InputDispatching Timeout:輸入事件分發超時5秒,如按鍵或者觸摸事件;
3,卡頓:16ms原則。Android系統每隔16ms會發出VSYNC信號重繪界面(Activity)。
??為什么是16ms,因為Android設定的刷新頻率是60FPS(Frame Per Second),也就是每秒60幀的刷新率,約合16ms刷新一次。
這就意味著,我們需要在16ms內完成下一次刷新的界面相關運算,以便界面更新。
哪些情況會導致卡頓?
- 1)、過于復雜的布局(使用Hierarchy Viewer工具分析,Hierarchy Viewer 不僅可以以圖形化樹狀結構的形式展示出UI層級,還對每個節點給出三個小圓點,以指示該元素Measure,Layout,Draw的耗時及性能);
- 2)、過度繪制(OverDraw),理想情況下,每屏每幀上,每個像素點應該只被繪制一次,如果有多次繪制,就是OverDraw,過度繪制了。
4,服務器異常:使用Fiddler抓包工具。
??Fiddler是位于客戶端和服務端的HTTP代理。它能夠記錄客戶端的服務器之間的所有HTTP請求,可以針對特定的HTTP請求,分析請求數據、設置斷點、調試web應用、修改請求的參數,甚至可以修改服務器返回的數據,功能非常強大。
引申——Android適配問題引起的bug
- 1),屏幕適配:分辨率、尺寸等。
- 2),機型適配:2015年統計1294家廠商生產出682000款Android手機。
- 3),Android版本適配:比如說,Android6.0加入運行時權限,7.0加入虛擬文件對相機拍照和選擇圖片有影響。
三.崩潰捕獲原理
系統的默認處理
很抱歉,”營銷管家”已停止運行。
1),Java崩潰捕獲方式
??java的Thread中有一個UncaughtExceptionHandler接口,該接口的作用主要是為了 當 Thread 因未捕獲的異常而突然終止時,調用處理程序。
??線程一旦崩潰,異常處理器的Thread.UncaughtExceptionHandler.uncaughtException(Thread t,Throwable e)方法被調用(該方法主要作用為設置當線程由于未捕獲到異常而突然終止,并且沒有為該線程定義其他處理程序時所調用的默認處理程序)。最后在uncaughtException方法中實現Java異常的捕獲及上報。2),Native崩潰捕獲方式
??通過上圖我們可以看到,當我們new Thread 然后start線程啟動,這時候線程的狀態是已經準備就緒但是并沒有執行的狀態。這時首先會在liunx C層面通過Pthread_Create()這個API創建一個線程,創建這個線程以后執行一遍interpThreadStart()方法,然后繼續執行到dvmcallMethod()方法,這個方法里面通過JNI調用我們new出來的Thread里面的run方法。可以看到這整個過程都是在一個Pthread線程里面,整個線程棧被劃分為兩個部分,一個是c層的native棧,一個是java層的java棧。假設這個時候執行的java線程突然崩潰了,它會一層一層的往上拋異常,直到整個java棧一層一層退出,java棧退出之后會生成一個Pending Exception這樣一個數據結構。接下來它就回到了dvmcallMethod里面,就結束了。結束之后理論上它就要把這個線程跟虛擬機解開來,解開以后這個線程就要退出了。當它解開的時候發現有一個Pending Exception存在,即有一個未捕獲的異常存在,那么這個線程退出之前會調用uncaughtExceptionHandler方法,所有我們可以在這個回調方法里處理未捕獲的異常情況。
四.移動端常用的bug收集方案
- 友盟
優點:Android和iOS可用,統計功能突出,能捕獲應用層Crash;
缺點:bug收集不及時。
- 友盟
- Bugly
優點:Android和iOS可用,bug收集及時,能捕獲應用Java Crash、C/C++ Native Crash和ANR并提供相應的bug修復建議,對bug進行了合并統計,目前是免費的;
缺點:bugly收集的信息較多。
- Bugly
- Bugtags
優點:一套完善的bug管理系統,Android和iOS可用。
缺點:免費版功能有限。
- Bugtags
- DIY(自己搭建bug收集平臺)
優點:可以根據自己的業務需求實現,不依賴第三方平臺;
缺點:需要編寫錯誤收集代碼,需要搭建錯誤日志收集服務器。
- DIY(自己搭建bug收集平臺)
五.使用Bugly
- 1),看懂bugly 的java 棧
- 2),看懂Bugly的Native棧
六.Bugly存在誤報和漏報嗎?
- 1)不存在誤報。
因為異常與否是由系統API直接回調,不存在Bugly誤判的空間。 - 2)存在漏報。
沒來的及處理,比如說虛擬機崩潰,直接dump了,虛擬機直接sigabrt ,此時調用任何jni ,程序直接退出了。
上報是在java層,第二次啟動時上報上去,有可能用戶卸載了,或者不再打開等。 - 3)對于try...catch住的異常,可使用高級功能中的CrashReport.postCatchedException(thr)主動上報開發者Catch的異常 。
參見:https://bugly.qq.com/docs/user-guide/advance-features-android/?v=20170912151050
七.關于移動應用Crash統計數據
八.Android常見bug及解決方案總結
參考:Android常見bug及解決方案總結.doc
九.服務器異常獲取
參考:Fiddler手機抓包工具使用詳解.doc
十.DIY Android和iOS平臺的崩潰捕獲和收集器
參考:經典好文:android和iOS平臺的崩潰捕獲和收集 - wx0123 - 博客園.htm