android.os.Parcel.readException;ActivityRecord=null
错误日志:04-20 13:50:54.624 E/MtaSDK(30339): Caused by: java.lang.IllegalArgumentException04-20 13:50:54.624 E/MtaSDK(30339):at android.os.Parcel.readException(Parcel.java:1688)04-20 13:50:54.624 E/MtaSDK
错误日志:
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的线程设置处理程序。
参考:
- 关于使用AIDL出现空指针的解决办法
- android - Parcel.readException中的NullPointerException(等)
- Caused by: java.lang.IllegalArgumentException android.os.Parcel.readException(Parcel.java:1687)
- ActivityRecord、ActivityClientRecord、Activity的关系
四大组件之ActivityRecord- Android ActivityRecord 为空的异常处理方案
- java.lang.RuntimeException:如何解决无法使用java.lang.IllegalArgumentException恢复活动?
- Activity中onResume方法触发的ActivityRecord not found异常分析
更多推荐
所有评论(0)