面試官:爲什麼應用出現異常會崩潰?

異常?崩潰?不是應該的嗎?這....

看到這個問題是不是這樣 ->

1、爲什麼發生Exception後應用會發生奔潰?

當我們的應用發生未捕獲異常後程序會回調到Thread 的dispatchUncaughtException方法,如下:


//Thread.javapublic final void dispatchUncaughtException(Throwable e) {        ...省略部分代碼        // END Android-added: uncaughtExceptionPreHandler for use by platform.        getUncaughtExceptionHandler().uncaughtException(this, e);}


然後通過getUncaughtExceptionHandler去獲取UncaughtExceptionHandler對象


//Thread.javapublic UncaughtExceptionHandler getUncaughtExceptionHandler() {    return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group;}


正常我們都沒有設置UncaughtExceptionHandler,所有最後會將異常交group(ThreadGroup)uncaughtException進行處理,如下:


//ThreadGroup.javapublic void uncaughtException(Thread t, Throwable e) {    if (parent != null) {        parent.uncaughtException(t, e);    } else {        Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler();        ...省略部分代碼    }}


uncaughtException中,父類不等於null,則交由父類處理,否則會通過Thread.getDefaultUncaughtExceptionHandler();獲取一個默認的UncaughtExceptionHandler來處理這個異常。


//Thread.javapublic static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){    return defaultUncaughtExceptionHandler;}


那麼Thread類的defaultUncaughtExceptionHandler是什麼時候被賦值的呢?

是在RuntimeInit類的入口函數main函數中的commonInit方法:


//RuntimeInit.javapublic static final void main(String[] argv) {   ...    commonInit();   ...}
//RuntimeInit.javaprotected static final void commonInit() {    ...    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));    ...}


這個給ThreadsetDefaultUncaughtExceptionHandler設置了一個KillApplicationHandlerhandler。KillApplicationHandleruncaughtException方法如下:


//KillApplicationHandler.java@Overridepublic void uncaughtException(Thread t, Throwable e) {    try {        // Bring up crash dialog, wait for it to be dismissed        ActivityManager.getService().handleApplicationCrash(                mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));    } catch (Throwable t2) {       ...    } finally {        // Try everything to make sure this process goes away.        Process.killProcess(Process.myPid());        System.exit(10);    }}


try代碼塊中調用了ActivityManagerServicehandleApplicationCrash方法,在這裏去寫本地日誌和彈出異常dialog。

最後在finally代碼塊中調用了Process.killProcess(Process.myPid()) System.exit(10) 殺掉進程。

至此,當應用發生未捕獲異常崩潰時的流程就結束了


上文中提到我們沒有設置UncaughtExceptionHandler,其實現在很多應用也會設置通過setUncaughtExceptionHandler來設置UncaughtExceptionHandler。用於捕獲異常,在回調裏可以將異常日誌進行整理,然後在合適的時機回傳到服務


那麼setUncaughtExceptionHandlersetDefaultUncaughtExceptionHandler有什麼區別呢?

  • setUncaughtExceptionHandler :設置上文中的UncaughtExceptionHandler,只有當前線程生效

  • setDefaultUncaughtExceptionHandler,設置defaultUncaughtExceptionHandler,對所有線程生效。


2、native_crash 奔潰怎麼監控?

這裏簡單提下native的崩潰。

通過NativeCrashListener線程去監控。NativeCrashListener繼承了Thread。

那麼NativeCrashListener是什麼時候開啓監控的?

通過ActivityManagerService中startObservingNativeCrashes方法開啓監控。

具體邏輯:通過socket去監聽文件描述符,之後進入阻塞狀態,直到發生native異常,會向文件描述符中寫入數據,此時,被喚醒,然後通過consumeNativeCrashData方法通過IO流去讀取奔潰信息。在通過NativeCrashReport方法進行數據包裝,包裝爲CrashInfo,然後又跳轉到了ActivityManagerService中的handleApplicationCrashInner函數中進行處理。和上文中邏輯一樣。


 



微信掃一掃,關注我的公衆號


如果您覺得有點用,希望可以隨手轉發或者“在看”,拜謝。

本文分享自微信公衆號 - Android開發之旅(AndroidDevTour)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章