Android插件化架構 - 攔截Activity的啟動流程繞過AndroidManifest檢測

1. 概述


了解了Java的動態(tài)代理設計模式之后,配合上一期的文章Android插件化架構 - Activity的啟動流程分析,那么接下來就需要親自操刀去攔截Activity的啟動流程了。前面好事沒少干,那么現(xiàn)在就來干干壞事,到底怎樣才能讓沒有注冊的Activity啟動不報錯呢?答案就是Hook下鉤子。

2. Hook啟動流程


怎么樣去找Hook點是個問題,把鉤子下在哪里呢?一般的套路肯定最好是靜態(tài),然后是接口,配合反射注入就可以了。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);

        // 動態(tài)代理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. 借尸還魂


上面我們已經(jīng)攔截到了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中注冊了,但是發(fā)現(xiàn)繼承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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容