天天看點

小米手機混淆更新崩潰記錄與解決

首先介紹一下出現問題的背景:

最近在做應用更新的時候由于在新版本中proguard-rules.pro新增了一些混淆配置,在舊版本更新到新版本進入應用的時候小米手機就會報如下錯誤:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

Build fingerprint: 'xiaomi/cactus/cactus:8.1.0/O11019/9.1.17:user/release-keys'

Revision: '0'

ABI: 'arm'

pid: 396, tid: 510, name: AWCN Scheduler1  >>> 此處為應用包名 <<<

signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------

Abort message: 'java_vm_ext.cc:534] JNI DETECTED ERROR IN APPLICATION: JNI GetMethodID called with pending exception java.lang.NoSuchMethodError: no non-static method "Lorg/android/spdy/SpdyAgent;.spdySessionConnectCB(Lorg/android/spdy/SpdySession;Lorg/android/spdy/SuperviseConnectInfo;)V"'

    r0 00000000  r1 000001fe  r2 00000006  r3 00000008

    r4 0000018c  r5 000001fe  r6 89219074  r7 0000010c

    r8 00000000  r9 a4319368  sl 0000000a  fp 892190c0

    ip 972e59e0  sp 89219060  lr a4ec18bd  pc a4ebb40e  cpsr 200b0030

backtrace:

    #00 pc 0001a40e  /system/lib/libc.so (abort+63)

    #01 pc 0035ca45  /system/lib/libart.so (art::Runtime::Abort(char const*)+392)

    #02 pc 0041fe2d  /system/lib/libart.so (android::base::LogMessage::~LogMessage()+452)

    #03 pc 0024e545  /system/lib/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1212)

    #04 pc 0024e6c7  /system/lib/libart.so (art::JavaVMExt::JniAbortV(char const*, char const*, std::__va_list)+58)

    #05 pc 000d6403  /system/lib/libart.so (art::ScopedCheck::AbortF(char const*, ...)+42)

    #06 pc 000d5f83  /system/lib/libart.so (art::ScopedCheck::CheckThread(_JNIEnv*)+274)

    #07 pc 000d492d  /system/lib/libart.so (art::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::JniValueType*)+596)

    #08 pc 000d79e9  /system/lib/libart.so (art::CheckJNI::GetMethodIDInternal(char const*, _JNIEnv*, _jclass*, char const*, char const*, bool)+464)

    #09 pc 000c9365  /system/lib/libart.so (art::CheckJNI::GetMethodID(_JNIEnv*, _jclass*, char const*, char const*)+20)

    #10 pc 00003657  /data/app/此處為應用包名-K2pKM3UWvCbPitz1xjJr7A==/lib/arm/libtnet-3.1.11.so

    #11 pc 00004a0d  /data/app/此處為應用包名-K2pKM3UWvCbPitz1xjJr7A==/lib/arm/libtnet-3.1.11.so

    #12 pc 0003d0cd  /data/app/此處為應用包名-K2pKM3UWvCbPitz1xjJr7A==/oat/arm/base.odex (offset 0x3b000)

這個崩潰日志是小米系統直接捕獲的,但是我應用裡通過實作 UncaughtExceptionHandler 确不能捕獲這個異常,通過上面日志exception java.lang.NoSuchMethodError能看出這個确實是由于混淆導緻的無法找到應用方法出現的問題,但是這個問題在其他手機上(華為、oppo、nubia)并不會出現。

通過測試發現在小米手機上出現此問題之後,到設定-應用管理裡面找到該應用清除應用資料,之後應用又神奇般的能正常使用了,再結合上面日志裡面出現的data/app/應用包名/lib/***.so,由此推斷小米系統在覆寫安裝或更新新版本應用的時候如果老版本和新版本存在相同庫檔案并不會重新加載進系統導緻新版本安裝之後用的還是老版本加載的庫檔案,然而新版本由于新增了混淆而與老版本的緩存檔案之間沒有必要的關聯,進而導緻找不到方法名而報錯。至于為什麼隻有小米系統出現這個問題,這個也許是小米手機系統應用安裝的機制跟其他廠商不一樣。

解決方法:

根據上面分析,在新版本進入應用初始化的時候對應用緩存進行一次清理,在系統檢測到沒有緩存之後就會重新加載新的檔案;

主要清除的緩存檔案路徑就是:getFilesDir().getParent(); 在這個路徑下有一些檔案夾如:/lib、/databases、/shared_prefs...

/databases下面儲存的db資料庫檔案,/shared_prefs下面儲存的是SharePreference資料,這兩個檔案下面的檔案儲存着使用者資料,可以不用删除或者選擇性删除,删除代碼如下:

public static void deleteFolder(File file) {
   if (!file.exists())
      return;

   if (file.isDirectory()) {
      File files[] = file.listFiles();
      for (int i = 0; i < files.length; i++) {
         if(files[i].getAbsolutePath().endsWith("/databases")){ //儲存使用者資料,不清除
            continue;
         }
         deleteFolder(files[i]);
      }
   }
   if(file.getAbsolutePath().endsWith("/shared_prefs/user_info.xml") ){
      Log.i("儲存使用者資料SharePreference,不清除");
   }else{
      file.delete();
   }
   SharePreferenceUtil.saveOrUpdateAttribute(context,MyConstants.USER_INFO, "dataCleared", true);  //儲存已清除緩存狀态
}
           

 在Application 的onCreate()方法中調用删除

@Override
public void onCreate() {
	super.onCreate();
	if(!SharePreferenceUtil.getAttributeByKey(this,MyConstants.USER_INFO, "dataCleared",SharePreferenceUtil.VALUE_IS_BOOLEAN)){
		deleteFolder(new File(getFilesDir().getParent()));
	}
}
           

 在删除SharePreference資料的時候,我隻保留了自己建立的user_info.xml,其他的都删除了,因為在測試過程中發現如果保留整個/shared_prefs檔案夾的話還是會報錯,裡面有一些友盟或者其他的三方庫寫進去的資料如果不清除的話也會報錯,所已在這裡我隻保留了自己的資料。

這麼一來由于混淆配置導緻的新版本更新問題解決。

如有不同觀點或文中錯誤,歡迎大神指正。