android.os.Parcel.readException;ActivityRecord=null

错误日志:


04-20 13:50:54.624 E/MtaSDK  (30339): Caused by: java.lang.IllegalArgumentException
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.os.Parcel.readException(Parcel.java:1688)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.os.Parcel.readException(Parcel.java:1637)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.app.ActivityManagerProxy.isTopOfTask(ActivityManagerNative.java:5677)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.app.Activity.isTopOfTask(Activity.java:6106)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.app.Activity.onResume(Activity.java:1284)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at android.support.v4.app.FragmentActivity.onResume(SourceFile:485)
04-20 13:50:54.624 E/MtaSDK  (30339): 	at ctrip.android.basebusiness.activity.CtripBaseActivity.onResume(SourceFile:166)

原理:

这段代码报错出现在 系统层面,通过现象来看 主要是出现在android 7.0 android 8.0 以上的机型

定位问题发生处:通过源码看进去

  @CallSuper
    protected void onResume() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
        getApplication().dispatchActivityResumed(this);
        mActivityTransitionState.onResume(this, isTopOfTask());
        mCalled = true;
    }

定位问题类:
frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

public boolean isTopOfTask(IBinder token) {
    synchronized (this) {
        ActivityRecord r = ActivityRecord.isInStackLocked(token);
        if (r == null) {
            throw new IllegalArgumentException();
        }
        return r.task.getTopActivity() == r;
    }
}

ActivityRecord r 为空了,是什么原因导致的 现在还不好去分析,所以做了保护的处理方案

解决方案1:

没有足够的信息来确定原因java.lang.IllegalArgumentException,不幸的是android ActivityThread没有记录该异常的堆栈跟踪,并且异常消息似乎是空的。

在super.resume 的地方 添加 异常捕获

 try {
      super.onResume();
 } catch (Exception e) {
      callUpActivity();
      e.printStackTrace();       
 }

  private void callUpActivity() {
        try {
            Class videoSuperClass = Activity.class;
            Field callField = videoSuperClass.getDeclaredField("mCalled");
            callField.setAccessible(true);
            callField.setBoolean(HotelVideoActivity.this, true);
        } catch (IllegalAccessException e) {
            //替换成自己的异常打印
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
           //替换成自己的异常打印
            e.printStackTrace();
        }
    }

通过反射的方式,将mCalled 这个参数强制设置为true,保证Activity 能正常启动!

解决方案2:

在Application的onCreate()方法里调用IActivityManagerHook.iActivityManagerHook()即可完成全局的IActivityManagerHook了。

object IActivityManagerHook {
   private const val TAG = "IActivityManagerHook"

    @SuppressLint("PrivateApi")
    fun iActivityManagerHook() {
        if (Build.VERSION.SDK_INT < 24 || Build.VERSION.SDK_INT > 28) {
            return
        }

        Logger.i(TAG, "IActivityManager hook ...")
        try {
            val singletonCls = Class.forName("android.util.Singleton")

            // 第一步:找到ActivityManager里的IActivityManagerSingleton常量
            // 这里通过变量的类型对比找出IActivityManagerSingleton这个常量,
            // 没有通过名字来查找,防止名字有变法
            // 这里也可以直接使用ActivityManager::class.java.getDeclaredField("IActivityManagerSingleton")来获取
            var iActivityManagerSingleton: Any? = null
            for (field in ActivityManager::class.java.declaredFields) {
                if (field.type == singletonCls) {
                    field.isAccessible = true
                    iActivityManagerSingleton = field.get(null)
                    break
                }
            }
            if (iActivityManagerSingleton == null) {
                Logger.w(TAG, "Not found IActivityManagerSingleton field in class ActivityManager.")
                return
            }

            // 第二步:找出iActivityManagerSingleton常量对象里的mInstance变量,该变量就是IActivityManager实列
            // 注意这里的iActivityManagerSingleton是Singleton的一个匿名子类
            // 如果要用iActivityManagerSingleton来进行反射,需要这样处理:
            // iActivityManagerSingleton::class.java.superclass.getDeclaredField("mInstance")
            val instanceField = singletonCls.getDeclaredField("mInstance")
            instanceField.isAccessible = true
            val iActivityManager = instanceField.get(iActivityManagerSingleton)
            if (iActivityManager == null) {
                Logger.w(TAG, "Not found IActivityManager instance.")
                return
            }

            // 第三步:使用动态代理替换原来的IActivityManager对象
            val proxy = IActivityManagerProxy(iActivityManager)
            val iActivityManagerCls = Class.forName("android.app.IActivityManager")
            val iActivityManageProxy = Proxy.newProxyInstance(iActivityManagerCls.classLoader, arrayOf(iActivityManagerCls), proxy)
            instanceField.set(iActivityManagerSingleton, iActivityManageProxy)
            Logger.i(TAG, "IActivityManager hook success.")
        } catch (e: Throwable) {
            Logger.w(TAG, "IActivityManager hook fail: $e")
        }
    }

    private class IActivityManagerProxy(private val instance: Any): InvocationHandler {
        override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
            Logger.i(TAG, "invoke: ${method.name}()")
            if (method.name == "isTopOfTask") {
                return try {
                    val result = method.invoke(instance, *(args ?: emptyArray())) as Boolean
                    Logger.i(TAG, "isTopOfTask() invoke success")
                    result 
                } catch (e: Exception) {
                    Logger.w(TAG, "isTopOfTask() invoke exception: $e")
                    false
                }
            }

            return method.invoke(instance, *(args ?: emptyArray()))
        }
    }
}

解决方案3:

如果您为活动注册了一个Instrumentation类,那么应该可以使用onException方法来记录导致异常的stacktrace。另一种可能是使用Thread.setUncaughtExceptionHandler程序为抛出IllegalArgumentException的线程设置处理程序。

参考:

  1. 关于使用AIDL出现空指针的解决办法
  2. android - Parcel.readException中的NullPointerException(等)
  3. Caused by: java.lang.IllegalArgumentException android.os.Parcel.readException(Parcel.java:1687)
  4. ActivityRecord、ActivityClientRecord、Activity的关系
    四大组件之ActivityRecord
  5. Android ActivityRecord 为空的异常处理方案
  6. java.lang.RuntimeException:如何解决无法使用java.lang.IllegalArgumentException恢复活动?
  7. Activity中onResume方法触发的ActivityRecord not found异常分析
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值