Activity中onResume方法触发的ActivityRecord not found异常分析


Activity中onResume方法触发的ActivityRecord not found异常分析

https://www.jianshu.com/p/0c63a8e5c1ad

再次基础上 写了个Java版供参考

问题

最近我在处理线上奔溃日志的时候发现一个由Activity中onResume方法触发的ActivityRecord not found异常,具体信息如下:

java.lang.RuntimeException: Unable to resume activity {com.xxx.xx/com.xxx.xxx.RegisterActivity}: java.lang.IllegalArgumentException
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4025)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4057)
    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1960)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7097)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
Caused by: java.lang.IllegalArgumentException
    at android.os.Parcel.createException(Parcel.java:1970)
    at android.os.Parcel.readException(Parcel.java:1934)
    at android.os.Parcel.readException(Parcel.java:1884)
    at android.app.IActivityManager$Stub$Proxy.isTopOfTask(IActivityManager.java:7845)
    at android.app.Activity.isTopOfTask(Activity.java:6551)
    at android.app.Activity.onResume(Activity.java:1404)
    at androidx.fragment.app.FragmentActivity.onResume(ProGuard:1)
    at com.xxx.xxx.BaseMVPActivity.onResume(ProGuard:1)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1416)
    at android.app.Activity.performResume(Activity.java:7585)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4017)
    ... 11 more
Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.isTopOfTask(ActivityManagerService.java:18293)
    at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2058)
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:4174)
    at android.os.Binder.execTransact(Binder.java:739)

可见当发生ActivityRecord not found时,isTopOfTask()方法里抛出来了一个IllegalArgumentException异常。引起ActivityRecord not found的原因有多种,这里不太好针对ActivityRecord not found进行处理,所以我想怎么来屏蔽这个异常,让程序不奔溃。

分析

首先我们来看看Activity的源码(API 24):

...
@CallSuper
protected void onResume() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
    getApplication().dispatchActivityResumed(this);
    mActivityTransitionState.onResume(this, isTopOfTask());
    mCalled = true;
}
...
private boolean isTopOfTask() {
    if (mToken == null || mWindow == null) {
        return false;
    }
    try {
        return ActivityManagerNative.getDefault().isTopOfTask(getActivityToken());
    } catch (RemoteException e) {
        return false;
    }
}

注意,在7.0到9.0系统上的onResume方法里才会调用这个isTopOfTask方法,所以这个问题只有这几个版本有。

网上有一种做法是直接try-catch onResume方法,然后通过反射将mCalled修改为true。由于这个问题不好复现,我没有去验证这个方法的可行性,但是这种简单粗暴的方法看上去其实是有问题的,因为isTopOfTask()抛出异常后,mActivityTransitionState.onResume()方法里的逻辑就没有执行。

我们分析下isTopOfTask()方法,发现这个方法try-catch了一个RemoteException异常,当发生这个异常的时候将返回false,后面的流程能正常执行,不会影响Activity,于是我们想这里可不可以将IllegalArgumentException异常也try-catch一下呐,但是发现这是一个私有方法,无法重写,所以只能继续往下追踪。
来看看ActivityManagerNative.getDefault()的实现:
在API 24、25上:

public abstract class ActivityManagerNative {
    ...
    static public IActivityManager getDefault() {
        return gDefault.get();
    }
    ...
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
    ...
}

在API 26+上:

public abstract class ActivityManagerNative {
    ...
    static public IActivityManager getDefault() {
        return ActivityManager.getService();
    }
    ...
}

继续看ActivityManager.getService()

public class ActivityManager {
    ...
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
    ...
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
    ...
}

我们发现getDefault()方法返回的是一个IActivityManager对象,所以实际上执行的是IActivityManager里的isTopOfTask()方法。而IActivityManager是一个单例,在7.0和7.1上这个单例对象在ActivityManagerNative类里面的,而从8.0开始放到了ActivityManager里。而且通过上面的final IActivityManager am = IActivityManager.Stub.asInterface(b);这句还知道了IActivityManager其实是一个接口(懒得继续翻源码了^_^)。
继续看这个Singleton

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

到这里我们就可以想到使用反射和动态代理就可以对IActivityManager里的方法进行Hook,然后就可以处理这个IllegalArgumentException异常了。

处理方法

第一步:通过反射拿到Singleton对象:

// Singleton是一个隐藏类,无法直接访问,所以这里通过Class.forName来加载,备用
val singletonCls = Class.forName("android.util.Singleton")

在API 24、25上:

private fun getIActivityManagerSingletonInstanceN(singletonCls: Class<*>): Any? {
    // 找到ActivityManagerNative里的gDefault这个常量
    // 这里通过变量的类型对比找出gDefault这个常量,
    // 没有通过名字来查找,防止名字有变法
    // 这里也可以直接使用activityManagerNativeCls.getDeclaredField("gDefault")来获取
    val activityManagerNativeCls = Class.forName("android.app.ActivityManagerNative")
    var iActivityManagerSingleton: Any? = null
    for (field in activityManagerNativeCls.declaredFields) {
        if (field.type == singletonCls) {
            field.isAccessible = true
            iActivityManagerSingleton = field.get(null)
            break
        }
    }
    if (iActivityManagerSingleton == null) {
        Logger.w(TAG, "Not found IActivityManager singleton field in class ActivityManagerNative.")
    }

    return iActivityManagerSingleton
}

在API 26+上:

private fun getIActivityManagerSingletonInstance(singletonCls: Class<*>): Any? {
    // 找到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 IActivityManager singleton field in class ActivityManager.")
    }

    return iActivityManagerSingleton
}

第二步:拿到Singleton里的mInstance字段:

// 注意这里的iActivityManagerSingleton是Singleton的一个匿名子类
// 如果要用iActivityManagerSingleton来进行反射,需要这样处理:
// iActivityManagerSingleton::class.java.superclass.getDeclaredField("mInstance")
val instanceField = singletonCls.getDeclaredField("mInstance")
instanceField.isAccessible = true
val iActivityManager = instanceField.get(iActivityManagerSingleton)

第三步:把代理类写出来
(本方法的处理核心就在这里)

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()))
    }
}

第四步:用动态代理替换原来的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)

完整代码如下:

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")

            // 第一步:通过反射拿到Singleton对象
            val iActivityManagerSingleton = if (Build.VERSION.SDK_INT <= 25) {
                getIActivityManagerSingletonInstanceN(singletonCls)
            } else {
                getIActivityManagerSingletonInstance(singletonCls)
            } ?: return

            // 第二步:找出Singleton里的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")
        }
    }

    @SuppressLint("PrivateApi")
    private fun getIActivityManagerSingletonInstanceN(singletonCls: Class<*>): Any? {
        // 找到ActivityManagerNative里的gDefault这个常量
        // 这里通过变量的类型对比找出gDefault这个常量,
        // 没有通过名字来查找,防止名字有变法
        // 这里也可以直接使用activityManagerNativeCls.getDeclaredField("gDefault")来获取
        val activityManagerNativeCls = Class.forName("android.app.ActivityManagerNative")
        var iActivityManagerSingleton: Any? = null
        for (field in activityManagerNativeCls.declaredFields) {
            if (field.type == singletonCls) {
                field.isAccessible = true
                iActivityManagerSingleton = field.get(null)
                break
            }
        }
        if (iActivityManagerSingleton == null) {
            Logger.w(TAG, "Not found IActivityManager singleton field in class ActivityManagerNative.")
        }

        return iActivityManagerSingleton
    }

    private fun getIActivityManagerSingletonInstance(singletonCls: Class<*>): Any? {
        // 找到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 IActivityManager singleton field in class ActivityManager.")
        }

        return iActivityManagerSingleton
    }

    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()))
        }
    }
}

java代码

public class IActivityManagerHook {
    private final static String TAG = "IActivityManagerHook";

    public static void iActivityManagerHook() {
        if (Build.VERSION.SDK_INT < 24 || Build.VERSION.SDK_INT > 28) {
            return;
        }

        Log.i(TAG, "IActivityManager hook ...");
        try {
            Class<?> singletonCls = Class.forName("android.util.Singleton");

            // 第一步:通过反射拿到Singleton对象
            Object iActivityManagerSingleton = null;
            if (Build.VERSION.SDK_INT <= 25) {
                iActivityManagerSingleton = getIActivityManagerSingletonInstanceN(singletonCls);
            } else {
                iActivityManagerSingleton = getIActivityManagerSingletonInstance(singletonCls);
            }

            if (iActivityManagerSingleton == null) return;

            // 第二步:找出Singleton里的mInstance变量
            Field instanceField = singletonCls.getDeclaredField("mInstance");
            instanceField.setAccessible(true);
            Object iActivityManager = instanceField.get(iActivityManagerSingleton);
            if (iActivityManager == null) {
                Log.w(TAG, "Not found IActivityManager instance.");
                return;
            }

            // 第三步:使用动态代理替换原来的IActivityManager对象
            IActivityManagerProxy proxy = new IActivityManagerProxy(iActivityManager);
            Class<?> iActivityManagerCls = Class.forName("android.app.IActivityManager");
            Object iActivityManageProxy = Proxy.newProxyInstance(iActivityManagerCls.getClassLoader(), new Class[]{iActivityManagerCls}, proxy);
            instanceField.set(iActivityManagerSingleton, iActivityManageProxy);
            Log.i(TAG, "IActivityManager hook success.");
        } catch (Throwable e) {
            Log.e(TAG, e);
        }

    }

    private static Object getIActivityManagerSingletonInstanceN(Class<?> singletonCls) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
        // 找到ActivityManagerNative里的gDefault这个常量
        // 这里通过变量的类型对比找出gDefault这个常量,
        // 没有通过名字来查找,防止名字有变法
        // 这里也可以直接使用activityManagerNativeCls.getDeclaredField("gDefault")来获取
        Class<?> activityManagerNativeCls = Class.forName("android.app.ActivityManagerNative");
        Object iActivityManagerSingleton = null;
        for (Field field : activityManagerNativeCls.getDeclaredFields()) {
            if (field.getType() == singletonCls) {
                field.setAccessible(true);
                iActivityManagerSingleton = field.get(null);
                break;
            }
        }

        if (iActivityManagerSingleton == null) {
            Log.w(TAG, "Not found IActivityManager singleton field in class ActivityManagerNative.");
        }
        return iActivityManagerSingleton;
    }

    private static Object getIActivityManagerSingletonInstance(Class<?> singletonCls) throws ClassNotFoundException, IllegalAccessException {
        // 找到ActivityManager里的IActivityManagerSingleton常量
        // 这里通过变量的类型对比找出IActivityManagerSingleton这个常量,
        // 没有通过名字来查找,防止名字有变法
        // 这里也可以直接使用ActivityManager::class.java.getDeclaredField("IActivityManagerSingleton")来获取
        Object iActivityManagerSingleton = null;
        for (Field field : ActivityManager.class.getDeclaredFields()) {
            if (field.getType() == singletonCls) {
                field.setAccessible(true);
                iActivityManagerSingleton = field.get(null);
                break;
            }
        }

        if (iActivityManagerSingleton == null) {
            Log.w(TAG, "Not found IActivityManager singleton field in class ActivityManagerNative.");
        }

        return iActivityManagerSingleton;
    }

    private static class IActivityManagerProxy implements InvocationHandler {

        private Object instance;

        public IActivityManagerProxy(Object instance) {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.i(TAG, "invoke: " + method.getName() + "()");
            if (method.getName() == "isTopOfTask") {
                boolean invoke = false;
                try {
                    invoke = (boolean) method.invoke(instance, args);
                    Log.i(TAG, "isTopOfTask() invoke success");
                } catch (Exception e) {
                    Log.w(TAG, "isTopOfTask() invoke exception: ", e);
                }
                return invoke;
            }

            return method.invoke(instance, args);
        }
    }
}

文章作者: ECM
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ECM !
评论
  目录