天天看点

小米手机混淆升级崩溃记录与解决

首先介绍一下出现问题的背景:

最近在做应用升级的时候由于在新版本中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文件夹的话还是会报错,里面有一些友盟或者其他的三方库写进去的数据如果不清除的话也会报错,所已在这里我只保留了自己的数据。

这么一来由于混淆配置导致的新版本升级问题解决。

如有不同观点或文中错误,欢迎大神指正。