No field gDefault in class Landroid/app/ActivityManagerNative

启动未注册activity。8.0系统报错如下:

05-06 10:25:31.312 13973-13973/com.bolex.androidhookstartactivity W/System.err: java.lang.NoSuchFieldException: No field gDefault in class Landroid/app/ActivityManagerNative; (declaration of 'android.app.ActivityManagerNative' appears in /system/framework/framework.jar)
        at java.lang.Class.getDeclaredField(Native Method)
 

 

如何启动一个未注册过的Activity

几乎所有的插件化都会要的一个需求,启动一个未注册的Activiy,即加载插件包中的Activity,并且主应用并不知道插件应用中会有什么Activity,这是各个插件化框架主力解决的问题之一。

今天我们学习一下占坑式插件化框架的启动Activity原理。

关于动态代理的知识,了解过Retrofit的源码的或者看过Java设计模式之代理模式的高级使用的,应该都了解了。本章不做介绍,主介绍hook+反射

Hook是什么?

Hook直白点说就是拦截方法,自己对其参数等进行修改,或者替换返回值,达到自己不可告人的目的的一件事。

寻找Hook点

对于启动Activity,老实说光startActivity便有很多要说,很多文章会带着你一直追到ActivityManagerService中的若干个方法,最后再调用本地的ActivityThread里面的方法去启动本进程的Activity。

所以光上面的流程我们看出,我们把要启动的Activity信息发给AMS,其做了各种检查各种操作后真正让Activity启动的还是我们的ActivityThread

实现欺骗

欺骗系统就欺骗两个地方,我们在AndroidManifest里面申明一个假Activity,然后在启动真实Activity的地方,将Intent里面的Activity替换成我们已经注册过的。再在ActivityThread launch Activity的时候,替换成我们需要启动的便实现了启动一个未注册过的Activity的效果。


实行代码如下:

安卓系统8.0以下手机启动未注册activity方法

private static void hookActivityManager() {
    try {
        // 获取gDefault
        Class activityManagerClass = Class.forName("android.app.ActivityManagerNative");
        Field gDefaultField = activityManagerClass.getDeclaredField("gDefault");
        gDefaultField.setAccessible(true);
        Object gDefault = gDefaultField.get(null);

        // 获取mIntance
        Class singletonClass = Class.forName("android.util.Singleton");
        Field mInstanceField = singletonClass.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        Object mInstance = mInstanceField.get(gDefault);

        // 替换mIntance
        Object proxy = Proxy.newProxyInstance(
                mInstance.getClass().getClassLoader(),
                new Class[]{Class.forName("android.app.IActivityManager")},
                new IActivityManagerHandler(mInstance));
        mInstanceField.set(gDefault, proxy);

    } catch (Exception e) {
        Log.e("hook", "err", e);
    }
}

Android系统8.0及以上手机启动方法就不再调用ActivityManagerNative类,而是ActivityManager类,部分代码如下

Class activityManagerClass = Class.forName("android.app.ActivityManager");

demo链接:https://download.csdn.net/download/meixi_android/11161392

云盘demo链接:https://pan.baidu.com/s/1CjWTpmueLrBMpxlsR7Jjew

在线回复云盘密码:QQ1085220040

 

 

 

 

你可能感兴趣的:(移动开发)