前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )

作者头像
韩曙亮
发布2023-03-29 15:23:23
1.3K0
发布2023-03-29 15:23:23
举报
文章被收录于专栏:韩曙亮的移动开发专栏

Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )

【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )

【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )

【Android 插件化】Hook 插件化框架 ( Hook 技术 | 代理模式 | 静态代理 | 动态代理 )

【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )

【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )

【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )

【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )

【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )

【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )

【Android 插件化】Hook 插件化框架 ( 创建插件应用 | 拷贝插件 APK | 初始化插件包 | 测试插件 DEX 字节码 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | Hook 点分析 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )

【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )


文章目录

一、插件包 Activity 启动原理


使用动态代理 , 替换 android.app.ActivityManager 中的 private static final Singleton IActivityManagerSingleton 成员的 mInstance 成员 ;

注意 : 该操作一定要在 AMS 启动之前将原来的 Intent 替换掉 , 使用占坑的 Activity 替换插件包中的 Activity , 之后 AMS 执行完毕 , 执行到主线程 实例化 Activity 对象之前 , 还要替换回去 ;

插件包组件启动方式 : 使用 Intent 启动插件包时 , 一般都使用隐式启动 ; 调用 Intent 的 setComponent , 通过包名和类名创建 Component , 这样操作 , 即使没有获得 Activity 引用 , 也不会报错

该插件包中的 Activity 没有在 “宿主” 应用中注册 , 因此启动报错 ;

AMS 会干掉没有注册过的 Activity , 这里先 在启动 AMS 之前 , 设置一个已经 注册过的 占坑 Activity ( StubActivity ) 执行启动流程 , 在主线程生成 Activity 实例对象时 , 还需要恢复插件包中的 Activity

二、分析主线程中创建 Activity 实例源码


1、LaunchActivityItem

ActivityManagerService 执行 Activity 启动 , 执行了一系列的操作后 , 需要在主线程中进行实例化 , 这些操作暂时不管 , 与 Hook 无关 , 直接开始分析 主线程中的 Activity 实例化操作 ;

Activity 实例化的起点 , 从 LaunchActivityItem 源码开始分析 ;

LaunchActivityItem 类 , 继承了 ClientTransactionItem 类 ;

该类中重写了 execute 方法 , 其中调用了 client.handleLaunchActivity 方法 , 就是调用的 ActivityThread 的 handleLaunchActivity 方法 ;

代码语言:javascript
复制
public class LaunchActivityItem extends ClientTransactionItem {
    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
}

源码路径 : /frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java

2、ActivityThread

ActivityThread 中的 handleLaunchActivity 方法中调用了 performLaunchActivity ,

在 performLaunchActivity 方法中 , 进行了 Activity 的实例化操作 ;

代码语言:javascript
复制
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);

在 class H extends Handler 类中 , 处理 EXECUTE_TRANSACTION 信号时 , 启动了 LaunchActivityItem 的 execute 方法 , 进而调用 ActivityThread 中的 handleLaunchActivity 方法 , 创建 Activity 实例对象 ;

这里劫持该 Handler , 将插件包 Activity 替换到原来的 Activity 中 ;

ActivityThread 的相关源码 :

代码语言:javascript
复制
public final class ActivityThread extends ClientTransactionHandler {

    final H mH = new H();

    /** Reference to singleton {@link ActivityThread} */
    private static volatile ActivityThread sCurrentActivityThread;

    class H extends Handler {
        public static final int EXECUTE_TRANSACTION = 159;
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        // Client transactions inside system process are recycled on the client side
                        // instead of ClientLifecycleManager to avoid being cleared before this
                        // message is handled.
                        transaction.recycle();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break;
            }
        }
	}

    /**
     * Extended implementation of activity launch. Used when server requests a launch or relaunch.
     */
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        if (!ThreadedRenderer.sRendererDisabled) {
            GraphicsEnvironment.earlyInitEGL();
        }
        WindowManagerGlobal.initialize();

        final Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            if (!r.activity.mFinished && pendingActions != null) {
                pendingActions.setOldState(r.state);
                pendingActions.setRestoreInstanceState(true);
                pendingActions.setCallOnPostCreate(true);
            }
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            try {
                ActivityManager.getService()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }

        return a;
    }


    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                checkAndBlockForNetworkAccess();
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
            }
            r.setState(ON_CREATE);

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }
}

源码路径 : /frameworks/base/core/java/android/app/ActivityThread.java

三、使用 Hook 技术在主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件


1、反射获取 ActivityThread 类

代码语言:javascript
复制
        // 反射获取 ActivityThread 类
        Class<?> activityThreadClass = null;
        try {
            activityThreadClass = Class.forName("android.app.ActivityThread");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

2、反射获取 ActivityThread 单例对象

代码语言:javascript
复制
        // Activity Thread 是一个单例 , 内部的单例成员是
        // private static volatile ActivityThread sCurrentActivityThread;
        // 可以直接通过 ActivityThread 类 , 获取该单例对象
        // 这也是 Hook 点优先找静态变量的原因 , 静态变量对象容易拿到 , 通过反射即可获取 , 不涉及系统源码相关操作
        Field sCurrentActivityThreadField = null;
        try {
            sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
            // 反射获取的字段一般都要设置可见性
            sCurrentActivityThreadField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 获取类的静态变量 , 使用 字段.get(null) 即可
        Object activityThreadObject = null;
        try {
            activityThreadObject = sCurrentActivityThreadField.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

3、反射获取 mH 字段

代码语言:javascript
复制
        // 获取 Activity Thread 中的 final H mH = new H() 成员字段 ;
        Field mHField = null;
        try {
            mHField = activityThreadClass.getDeclaredField("mH");
            // 设置该字段的可见性
            mHField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

4、反射获取 mH 对象

代码语言:javascript
复制
        // 通过反射获取 Activity Thread 中的 final H mH = new H() 成员实例对象
        Handler mHObject = null;
        try {
            mHObject = (Handler) mHField.get(activityThreadObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

5、反射获取 Handler 中的 mCallback 字段

代码语言:javascript
复制
        Class<?> handlerClass = null;
        try {
            handlerClass = Class.forName("android.os.Handler");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 通过反射获取 final H mH = new H() 成员的 mCallback 成员字段
        // Handler 中有成员变量 final Callback mCallback;
        Field mCallbackField = null;
        try {
            //mCallbackField = handlerClass.getDeclaredField("mCallback");
            mCallbackField = mHObject.getClass().getDeclaredField("mCallback");
            // 设置字段的可见性
            mCallbackField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

6、通过反射替换 Handler 中的 mCallback 成员

代码语言:javascript
复制
        // 使用静态代理类 HandlerProxy , 替换 final H mH = new H() 成员实例对象中的 mCallback 成员
        HandlerProxy proxy = new HandlerProxy();
        try {
            Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);
            mCallbackField.set(mHObject, proxy);
        } catch (Exception e) {
            e.printStackTrace();
        }

7、完整代码示例

代码语言:javascript
复制
    /**
     * 劫持 Activity Thread 的 final H mH = new H(); 成员
     * 该成员类型是 class H extends Handler ;
     * @param context
     */
    public static void hookActivityThread(Context context) {
        // 反射获取 ActivityThread 类
        Class<?> activityThreadClass = null;
        try {
            activityThreadClass = Class.forName("android.app.ActivityThread");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // Activity Thread 是一个单例 , 内部的单例成员是
        // private static volatile ActivityThread sCurrentActivityThread;
        // 可以直接通过 ActivityThread 类 , 获取该单例对象
        // 这也是 Hook 点优先找静态变量的原因 , 静态变量对象容易拿到 , 通过反射即可获取 , 不涉及系统源码相关操作
        Field sCurrentActivityThreadField = null;
        try {
            sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
            // 反射获取的字段一般都要设置可见性
            sCurrentActivityThreadField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 获取类的静态变量 , 使用 字段.get(null) 即可
        Object activityThreadObject = null;
        try {
            activityThreadObject = sCurrentActivityThreadField.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 获取 Activity Thread 中的 final H mH = new H() 成员字段 ;
        Field mHField = null;
        try {
            mHField = activityThreadClass.getDeclaredField("mH");
            // 设置该字段的可见性
            mHField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 通过反射获取 Activity Thread 中的 final H mH = new H() 成员实例对象
        Handler mHObject = null;
        try {
            mHObject = (Handler) mHField.get(activityThreadObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        Class<?> handlerClass = null;
        try {
            handlerClass = Class.forName("android.os.Handler");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 通过反射获取 final H mH = new H() 成员的 mCallback 成员字段
        // Handler 中有成员变量 final Callback mCallback;
        Field mCallbackField = null;
        try {
            //mCallbackField = handlerClass.getDeclaredField("mCallback");
            mCallbackField = mHObject.getClass().getDeclaredField("mCallback");
            // 设置字段的可见性
            mCallbackField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 使用静态代理类 HandlerProxy , 替换 final H mH = new H() 成员实例对象中的 mCallback 成员
        HandlerProxy proxy = new HandlerProxy();
        try {
            Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);
            mCallbackField.set(mHObject, proxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

四、用于替换 ActivityThread 中 mH 中的 mCallback 静态代理类


静态代理 ActivityThread 中的 final H mH = new H() 成员中的 mCallback 成员 ;

该静态代理类的主要作用是 , 在创建的 Activity 示例类之前 , 使用插件包中的 Activity 组件替换之前在 AMS 调用之前使用的 占坑用的 Activity , 就是要创建 插件包 中的 Activity 类的实例对象 ;

1、获取 ClientTransaction 类

代码语言:javascript
复制
            // 反射 android.app.servertransaction.ClientTransaction 类
            // 该类中有如下成员变量
            // private List<ClientTransactionItem> mActivityCallbacks;
            // 这个集合中存放的就是 android.app.servertransaction.LaunchActivityItem 类实例
            // 不能直接获取 LaunchActivityItem 实例 , 否则会出错
            Class<?> clientTransactionClass = null;
            try {
                clientTransactionClass =
                        Class.forName("android.app.servertransaction.ClientTransaction");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

2、验证 msg.obj 类型是否合法

验证处理的信号 , 是否是对应 LaunchActivityItem , 如果不是 , 直接退出 ;

代码语言:javascript
复制
            // 验证当前的 msg.obj 是否是 ClientTransaction 类型 , 如果不是则不进行 Intent 替换
            // 通过阅读源码可知 , 在 ActivityThread 的 mH 中, 处理 EXECUTE_TRANSACTION 信号时
            // 有 final ClientTransaction transaction = (ClientTransaction) msg.obj;
            if (!clientTransactionClass.isInstance(msg.obj)) {
                return true;
            }

3、反射获取 mActivityCallbacks 字段

代码语言:javascript
复制
            // 反射获取
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段
            Field mActivityCallbacksField = null;
            try {
                mActivityCallbacksField =
                        clientTransactionClass.getDeclaredField("mActivityCallbacks");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            // 设置成员字段可见性
            mActivityCallbacksField.setAccessible(true);

4、反射获取 mActivityCallbacks 成员对象

代码语言:javascript
复制
            // 反射获取
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段实例
            Object mActivityCallbacksObject = null;
            try {
                mActivityCallbacksObject = mActivityCallbacksField.get(msg.obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

5、使用插件 Activity 对应的 Intent 替换 LaunchActivityItem 类中的 mIntent 字段

遍历 ClientTransaction 中 private List mActivityCallbacks 成员对象 , 只针对 LaunchActivityItem 类型的元素进行后续处理 ;

获取 LaunchActivityItem 类中的 mIntent 成员变量 , 然后从其中获取 获取 启动 插件包 组件的 Intent , 使用该 Intent 替换之前的 mIntent 成员 ;

代码语言:javascript
复制
            // 将
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段实例
            // 强转为 List 类型 , 以用于遍历
            List mActivityCallbacksObjectList = (List) mActivityCallbacksObject;

            for (Object item : mActivityCallbacksObjectList) {
                Class<?> clazz = item.getClass();

                // 只处理 LaunchActivityItem 的情况
                if (clazz.getName().equals("android.app.servertransaction.LaunchActivityItem")) {
                    // 获取 LaunchActivityItem 的 private Intent mIntent; 字段
                    // 该 Intent 中的 Activity 目前是占坑 Activity 即 StubActivity
                    // 需要在实例化之前 , 替换成插件包中的 Activity
                    Field mIntentField = null;
                    try {
                        mIntentField = clazz.getDeclaredField("mIntent");
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                    mIntentField.setAccessible(true);

                    // 获取 LaunchActivityItem 对象的 mIntent 成员 , 即可得到 Activity 跳转的 Intent
                    Intent intent = null;
                    try {
                        intent = (Intent) mIntentField.get(item);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                    // 获取 启动 插件包 组件的 Intent
                    Intent pluginIntent = intent.getParcelableExtra("pluginIntent");
                    if (pluginIntent != null) {
                        // 使用 包含插件包组件信息的 Intent ,
                        // 替换之前在 Ams 启动之前设置的 占坑 StubActivity 对应的 Intent
                        try {
                            mIntentField.set(item, pluginIntent);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

6、完整代码示例

代码语言:javascript
复制
package kim.hsl.plugin;

import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 静态代理 ActivityThread 中的 final H mH = new H() 成员
 */
public class HandlerProxy implements Handler.Callback {

    public static final int EXECUTE_TRANSACTION = 159;

    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == EXECUTE_TRANSACTION) {


            // 反射 android.app.servertransaction.ClientTransaction 类
            // 该类中有如下成员变量
            // private List<ClientTransactionItem> mActivityCallbacks;
            // 这个集合中存放的就是 android.app.servertransaction.LaunchActivityItem 类实例
            // 不能直接获取 LaunchActivityItem 实例 , 否则会出错
            Class<?> clientTransactionClass = null;
            try {
                clientTransactionClass =
                        Class.forName("android.app.servertransaction.ClientTransaction");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

            // 验证当前的 msg.obj 是否是 ClientTransaction 类型 , 如果不是则不进行 Intent 替换
            // 通过阅读源码可知 , 在 ActivityThread 的 mH 中, 处理 EXECUTE_TRANSACTION 信号时
            // 有 final ClientTransaction transaction = (ClientTransaction) msg.obj;
            if (!clientTransactionClass.isInstance(msg.obj)) {
                return true;
            }

            // 反射获取
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段
            Field mActivityCallbacksField = null;
            try {
                mActivityCallbacksField =
                        clientTransactionClass.getDeclaredField("mActivityCallbacks");
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            // 设置成员字段可见性
            mActivityCallbacksField.setAccessible(true);

            // 反射获取
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段实例
            Object mActivityCallbacksObject = null;
            try {
                mActivityCallbacksObject = mActivityCallbacksField.get(msg.obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            // 将
            // private List<ClientTransactionItem> mActivityCallbacks; 成员字段实例
            // 强转为 List 类型 , 以用于遍历
            List mActivityCallbacksObjectList = (List) mActivityCallbacksObject;

            for (Object item : mActivityCallbacksObjectList) {
                Class<?> clazz = item.getClass();

                // 只处理 LaunchActivityItem 的情况
                if (clazz.getName().equals("android.app.servertransaction.LaunchActivityItem")) {
                    // 获取 LaunchActivityItem 的 private Intent mIntent; 字段
                    // 该 Intent 中的 Activity 目前是占坑 Activity 即 StubActivity
                    // 需要在实例化之前 , 替换成插件包中的 Activity
                    Field mIntentField = null;
                    try {
                        mIntentField = clazz.getDeclaredField("mIntent");
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                    mIntentField.setAccessible(true);

                    // 获取 LaunchActivityItem 对象的 mIntent 成员 , 即可得到 Activity 跳转的 Intent
                    Intent intent = null;
                    try {
                        intent = (Intent) mIntentField.get(item);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                    // 获取 启动 插件包 组件的 Intent
                    Intent pluginIntent = intent.getParcelableExtra("pluginIntent");
                    if (pluginIntent != null) {
                        // 使用 包含插件包组件信息的 Intent ,
                        // 替换之前在 Ams 启动之前设置的 占坑 StubActivity 对应的 Intent
                        try {
                            mIntentField.set(item, pluginIntent);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return false;
    }
}

五、Hook Activity 启动流程涉及的完整代码


代码语言:javascript
复制
package kim.hsl.plugin;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

/**
 * 主要职责 : Hook Activity 的启动过程
 * 本工具类只针对 API Level 28 实现 , 如果是完整插件化框架 , 需要实现所有版本的 Hook 过程
 * 不同的版本 , Activity 的启动过程是不同的 , 需要逐个根据 Activity 启动源码进行 Hook 适配
 */
public class HookUtils {

    private static final String TAG = "HookUtils";

    /**
     * 最终目的是劫持 ActivityManagerService 的 startActivity 方法 ,
     *      修改 Intent 中药启动的 Activity 类
     */
    public static void hookAms(Context context){
        // 获取 android.app.ActivityManager 类
        Class<?> activityManagerClass = null;
        try {
            activityManagerClass = Class.forName("android.app.ActivityManager");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 获取 android.app.ActivityManager 类 中的 IActivityManagerSingleton 属性
        // private static final Singleton<IActivityManager> IActivityManagerSingleton 成员变量
        Field iActivityManagerSingletonField = null;
        try {
            iActivityManagerSingletonField =
                    activityManagerClass.getDeclaredField("IActivityManagerSingleton");
            // 设置成员字段的可访问性
            iActivityManagerSingletonField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 获取 android.app.ActivityManager 类的静态成员变量
        // private static final Singleton<IActivityManager> IActivityManagerSingleton
        // 直接调用 Field 字段 iActivityManagerSingletonField 的 get 方法 , 传入 null 即可获取
        Object iActivityManagerSingletonObject = null;
        try {
            iActivityManagerSingletonObject = iActivityManagerSingletonField.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 获取 Singleton 类
        // ActivityManager 中的 IActivityManagerSingleton 成员是 Singleton<IActivityManager> 类型的
        Class<?> singletonClass = null;
        try {
            singletonClass = Class.forName("android.util.Singleton");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 反射获取 Singleton 类中的 mInstance 字段
        Field mInstanceField = null;
        try {
            mInstanceField = singletonClass.getDeclaredField("mInstance");
            // 设置字段的可访问性
            mInstanceField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 反射获取 Singleton 类中的 mInstance 成员对象
        // 该 mInstanceObject 成员对象就是 IActivityManager
        // private static final Singleton<IActivityManager> IActivityManagerSingleton
        Object mInstanceObject = null;
        try {
            mInstanceObject = mInstanceField.get(iActivityManagerSingletonObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 使用动态代理 , 替换 android.app.ActivityManager 中的
        // private static final Singleton<IActivityManager> IActivityManagerSingleton 成员的
        // mInstance 成员
        // 注意 : 该操作一定要在 AMS 启动之前将原来的 Intent 替换掉
        //          之后还要替换回去
        // 使用 Intent 启动插件包时 , 一般都使用隐式启动
        // 调用 Intent 的 setComponent , 通过包名和类名创建 Component ,
        //      这样操作 , 即使没有获得 Activity 引用 , 也不会报错
        // 该插件包中的 Activity 没有在 "宿主" 应用中注册 , 因此启动报错
        //      AMS 会干掉没有注册过的 Activity
        //      这里先在启动 AMS 之前 , 设置一个已经 注册过的 占坑 Activity ( StubActivity ) 执行启动流程
        //      在主线程生成 Activity 实例对象时 , 还需要恢复插件包中的 Activity

        // IActivityManager 是接口
        // 这是一个 AIDL 文件生成的 , 由 IActivityManager.aidl 生成
        Class<?> IActivityManagerInterface = null;
        try {
            IActivityManagerInterface = Class.forName("android.app.IActivityManager");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 动态代理的实际代理类
        AmsInvocationHandler amsInvocationHandler =
                new AmsInvocationHandler(context, mInstanceObject);

        // 动态代理过程
        Object proxy = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(), // 类加载器
                new Class[]{IActivityManagerInterface},         // 接口
                amsInvocationHandler);                          // 代理的对象

        // 使用动态代理类 , 替换原来的 ActivityManager 中的 IActivityManagerSingleton 成员
        //      的 Singleton 类中的 mInstance 成员
        try {
            mInstanceField.set(iActivityManagerSingletonObject, proxy);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 劫持 Activity Thread 的 final H mH = new H(); 成员
     * 该成员类型是 class H extends Handler ;
     * @param context
     */
    public static void hookActivityThread(Context context) {
        // 反射获取 ActivityThread 类
        Class<?> activityThreadClass = null;
        try {
            activityThreadClass = Class.forName("android.app.ActivityThread");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // Activity Thread 是一个单例 , 内部的单例成员是
        // private static volatile ActivityThread sCurrentActivityThread;
        // 可以直接通过 ActivityThread 类 , 获取该单例对象
        // 这也是 Hook 点优先找静态变量的原因 , 静态变量对象容易拿到 , 通过反射即可获取 , 不涉及系统源码相关操作
        Field sCurrentActivityThreadField = null;
        try {
            sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
            // 反射获取的字段一般都要设置可见性
            sCurrentActivityThreadField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 获取类的静态变量 , 使用 字段.get(null) 即可
        Object activityThreadObject = null;
        try {
            activityThreadObject = sCurrentActivityThreadField.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 获取 Activity Thread 中的 final H mH = new H() 成员字段 ;
        Field mHField = null;
        try {
            mHField = activityThreadClass.getDeclaredField("mH");
            // 设置该字段的可见性
            mHField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 通过反射获取 Activity Thread 中的 final H mH = new H() 成员实例对象
        Handler mHObject = null;
        try {
            mHObject = (Handler) mHField.get(activityThreadObject);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        Class<?> handlerClass = null;
        try {
            handlerClass = Class.forName("android.os.Handler");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 通过反射获取 final H mH = new H() 成员的 mCallback 成员字段
        // Handler 中有成员变量 final Callback mCallback;
        Field mCallbackField = null;
        try {
            //mCallbackField = handlerClass.getDeclaredField("mCallback");
            mCallbackField = mHObject.getClass().getDeclaredField("mCallback");
            // 设置字段的可见性
            mCallbackField.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 使用静态代理类 HandlerProxy , 替换 final H mH = new H() 成员实例对象中的 mCallback 成员
        HandlerProxy proxy = new HandlerProxy();
        try {
            Log.i(TAG, "mCallbackField : " + mCallbackField + " , mHObject : " + mHObject + " , proxy : " + proxy);
            mCallbackField.set(mHObject, proxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

六、博客资源

博客资源 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Android 插件化系列文章目录
    • 文章目录
    • 一、插件包 Activity 启动原理
    • 二、分析主线程中创建 Activity 实例源码
      • 1、LaunchActivityItem
        • 2、ActivityThread
        • 三、使用 Hook 技术在主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件
          • 1、反射获取 ActivityThread 类
            • 2、反射获取 ActivityThread 单例对象
              • 3、反射获取 mH 字段
                • 4、反射获取 mH 对象
                  • 5、反射获取 Handler 中的 mCallback 字段
                    • 6、通过反射替换 Handler 中的 mCallback 成员
                      • 7、完整代码示例
                      • 四、用于替换 ActivityThread 中 mH 中的 mCallback 静态代理类
                        • 1、获取 ClientTransaction 类
                          • 2、验证 msg.obj 类型是否合法
                            • 3、反射获取 mActivityCallbacks 字段
                              • 4、反射获取 mActivityCallbacks 成员对象
                                • 5、使用插件 Activity 对应的 Intent 替换 LaunchActivityItem 类中的 mIntent 字段
                                  • 6、完整代码示例
                                  • 五、Hook Activity 启动流程涉及的完整代码
                                  • 六、博客资源
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档