Android插件化架构 - 拦截Activity的启动流程绕过AndroidManifest检测

1. 概述

了解了Java的动态代理设计模式之后,配合上一期的文章Android插件化架构 – Activity的启动流程分析,那么接下来就需要亲自操刀去拦截Activity的启动流程了。前面好事没少干,那么现在就来干干坏事,到底怎样才能让没有注册的Activity启动不报错呢?答案就是Hook下钩子。

2. Hook启动流程

怎么样去找Hook点是个问题,把钩子下在哪里呢?一般的套路肯定最好是静态,然后是接口,配合反射注入就可以了。Activity启动流程的源码我就不再贴了,如果不了解请移步这里Android插件化架构 – Activity的启动流程分析,我这里直接下钩子。

     /**
     * hook start activity
     */
    public void hookStartActivity() throws Exception{
        // 先获取ActivityManagerNative中的gDefault
        Class<?> amnClazz = Class.forName("android.app.ActivityManagerNative");
        Field defaultField = amnClazz.getDeclaredField("gDefault");
        defaultField.setAccessible(true);
        Object gDefaultObj = defaultField.get(null);

        // 获取Singleton里面的mInstance
        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        Field amsField = singletonClazz.getDeclaredField("mInstance");
        amsField.setAccessible(true);
        Object amsObj = amsField.get(gDefaultObj);

        // 动态代理Hook下钩子
        amsObj = Proxy.newProxyInstance(mContext.getClass().getClassLoader(),
                amsObj.getClass().getInterfaces(),
                new StartActivityInvocationHandler(amsObj));
        // 注入
        amsField.set(gDefaultObj,amsObj);
    }

    /**
     * Start Activity Invocation Handler
     */
    private class StartActivityInvocationHandler implements InvocationHandler{
        private Object mAmsObj;
        public StartActivityInvocationHandler(Object amsObj){
            this.mAmsObj = amsObj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 拦截到所有ActivityManagerService的方法
            Log.e("TAG","methodName"+method.getName());
            return method.invoke(mAmsObj,args);
        }
    }

3. 借尸还魂

上面我们已经拦截到了Activity的启动了,也能够看到startActivity方法的打印。但是如果不做任何处理还是会蹦,那么我们需要有一个Activity预先在AndroidMnifest.xml中注册一下,它是不怕太阳的,通过它可以做到借尸还魂。

     /**
     * Start Activity Invocation Handler
     */
    private class StartActivityInvocationHandler implements InvocationHandler{
        private Object mAmsObj;
        public StartActivityInvocationHandler(Object amsObj){
            this.mAmsObj = amsObj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 拦截到所有ActivityManagerService的方法
            Log.e("TAG","methodName"+method.getName());
            if(method.getName().equals("startActivity")){
                // 启动Activity的方法,找到原来的Intent
                Intent realIntent = (Intent) args[2];
                // 代理的Intent
                Intent proxyIntent = new Intent();
                proxyIntent.setComponent(new ComponentName(mContext,mProxyActivity));
                // 把原来的Intent绑在代理Intent上面
                proxyIntent.putExtra("realIntent",realIntent);
                // 让proxyIntent去晒太阳,借尸
                args[2] = proxyIntent;
            }
            return method.invoke(mAmsObj,args);
        }
    }

还魂

     /**
     * hook Launch Activity
     */
    public void hookLaunchActivity() throws Exception{
        // 获取ActivityThread
        Class<?> activityThreadClazz = Class.forName("android.app.ActivityThread");
        Field sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread");
        sCurrentActivityThreadField.setAccessible(true);
        Object sCurrentActivityThreadObj = sCurrentActivityThreadField.get(null);
        // 获取Handler mH
        Field mHField = activityThreadClazz.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mH = (Handler) mHField.get(sCurrentActivityThreadObj);
        // 设置Callback
        Field callBackField = Handler.class.getDeclaredField("mCallback");
        callBackField.setAccessible(true);
        callBackField.set(mH, new ActivityThreadHandlerCallBack());
    }

    class ActivityThreadHandlerCallBack implements Handler.Callback {

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == LAUNCH_ACTIVITY) {
                handleLaunchActivity(msg);
            }
            return false;
        }
    }
    // 还魂
    private void handleLaunchActivity(Message msg) {
        // final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
        try {
            Object obj = msg.obj;
            Field intentField = obj.getClass().getDeclaredField("intent");
            intentField.setAccessible(true);
            Intent proxyIntent = (Intent) intentField.get(obj);
            // 代理意图
            Intent originIntent = proxyIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
            if (originIntent != null) {
                // 替换意图
                intentField.set(obj, originIntent);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3. 兼容AppCompatActivity

继承自Activity是百试百灵,再也不需要在AndroidMnifest中注册了,但是发现继承AppCompatActivity还是会报错,我都不记得当时是怎么解决这个问题的,反正搞了好几天,我选择遗忘那段操蛋的时光。

    // 兼容AppCompatActivity报错问题
    Class<?> forName = Class.forName("android.app.ActivityThread");
    Field field = forName.getDeclaredField("sCurrentActivityThread");
    field.setAccessible(true);
    Object activityThread = field.get(null);
    Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
    Object iPackageManager = getPackageManager.invoke(activityThread);

    PackageManagerHandler handler = new PackageManagerHandler(iPackageManager);
    Class<?> iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager");
    Object proxy = newProxyInstance(Thread.currentThread().getContextClassLoader(),
        new Class<?>[]{iPackageManagerIntercept}, handler);

    // 获取 sPackageManager 属性
    Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager");
    iPackageManagerField.setAccessible(true);
    iPackageManagerField.set(activityThread, proxy);

总算走出了插件化架构的一小步,过程对于一般人来讲还是有点痛苦的,但是结果带来那种成就感还是值得的,后面我们解决一下资源和布局的加载问题,然后介绍一下360开源的插件化框架DroidPlugin,分析一下它的源码就直接拿过用吧。

所有分享大纲:2017Android进阶之路与你同行

视频讲解地址:http://pan.baidu.com/s/1o8bPZ9C

    原文作者:红橙Darren
    原文地址: https://www.jianshu.com/p/e359fafe5c29
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞