Android啓動保護模式實踐

一般初始化app的第三方類庫或者so庫操作都會放在Application的onCreate()方法裏,因爲此時Application纔算創建完成,在這裏初始化是自然而然的。由於我們的應用是直播類,音視頻操作和接口調用是在jni層處理,初始化這兩個so庫也是放在Application的onCreate裏,但前段時間發生了一次偶發性但非常嚴重的bug。當時是服務端接口升級出現問題,導致處理接口的so庫一初始化就崩潰。正式發佈的應用出現這種問題可以說是致命的,用戶打開你的應用,連首頁都沒見到就crash,影響特別不好。且由於檢測App升級是在首頁初始化才調用,導致後臺配置接口讓用戶強制升級解決問題都沒辦法,束手無此。

通常來講,再爛的應用在正常的條件下都能保證正常打開,但在一些特殊條件下是有可能導致應用重複崩潰的,例如:

  • 數據庫損壞:在日常使用如異常退出、斷電,或者錯誤的操作
  • 文件損壞:處理文件時如果沒有 @try…catch,損壞文件會拋出 IOException導致crash
  • 網絡返回數據處理異常:比如預期返回數組,但實際返回了字典,java.lang.ClassCastException
  • 代碼 bug:當必 crash 的代碼出現在啓動關鍵路徑中,就會導致連續閃退。

以上這些條件如果測試到位,能大大減少出現的概率,只不過程序的世界並不存在100%的情況,我們要做的事是當出現異常時,我們能及時甚至無感的將bug修復掉。

經分析,由於我們app使用數據庫及文件的地方不多,媒體和接口的so庫導致問題的概率比較大,我們重點考慮修復這種情況,當多次初始化so庫崩潰時,能讓app去下載新的so庫並加載新的so庫。

想要做到以上這點,涉及到兩個問題,檢測及更新。

檢測

檢測有兩種辦法:

1、 崩潰記錄法:使用bugly之類的檢測奔潰的sdk,在特定時間裏(比如5s),檢測到崩潰後就記錄一次,連續三次都在5s內崩潰就延遲所有初始化,走修復流程;期間有一次正常運行超過5s計數清0;

2、時間記錄法:在特定的時間內(比如5s),如果app退出,就記錄一次,然後設定一個閥值(比如3次),達到閥值就走修復流程。如果達到閥值前有一次超過5s,計數就清0;

其實這兩者有點相似,區別是第1種需要檢測崩潰,第2種不用,相應的第1種更復雜但不會誤觸發,第2種簡單但有概率誤觸發。

我首先用Bugly實踐第一種方法,結果發現雖然Bugly有檢測到崩潰回調的函數,但這個回調處理是在Java層,而jni有些崩潰會導致jvm直接退出,如果在java層接受回調肯定是收不到的。jni層的崩潰只能在jni層檢測,由於我們的so庫是多個平臺公用,專爲Android端增加此功能的阻力較大,這種方式只好放棄。

於是我們採用了第2種方式,時間記錄法,下面是流程圖:

更新

更新的前提是進入修復流程,修復流程是不初始化任何第三方so庫及其他正常需要初始化的類,等到修復完纔回到正常流程。下面是流程圖:

更新 .png

上面的流程是比較簡單的,不過需要解決兩個問題:

1、 下載so庫時由於歡迎頁都沒初始化,怎麼顯示交互,總不能一片白色,讓用戶以爲ARN吧?

我們在下載so庫時,動態把ProgressBar加進android.R.id.content

 //添加進度條
mDownloadPb = (ProgressBar)LayoutInflater.from(mContext).inflate(R.layout.pb_update_so,
(ViewGroup) ((Activity)mContext).findViewById(android.R.id.content))
.findViewById(R.id.pb_update_so);

以下是下載so庫時的截圖:

下載.png

2、下載成功後怎麼讓程序使用最新的so庫

首先本地得保存你每次發佈時so庫的版本號,以及每次你更新完需要保存更新下來so庫的版本號,每次load之前都先對比一下,如果下載下來的版本號更新及文件存在的話,就判定爲新的so庫,加載此庫即可。

if (BuildConfig.LIB_VERSION < PreferenceHelper.getInstance().getLibVersion()) {
    File soPath = new File(FileUtil.getSoLibPath(),LIB_FILE_NAME));
    if (FileUtil.fileIsExists(soPath)) {
        System.load(soPath.getAbsolutePath());
    } else {
        System.loadLibrary(PROTOCOL_LIB_NAME);
    }
} else {
        System.loadLibrary(PROTOCOL_LIB_NAME);
}

注:本文的設計思想參考自微信讀書的文章

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