由于特殊需求,需要在应用启动的时候动态替换启动的 Activity,参考插件化原理,在 Application 阶段进行 hook ,从而拿到 AcitvityThread
的 mH
,然后在启动 activity 的时候进行替换
设备 Android 8.1,其他 Android 版本可能需要兼容
实例
应用包含两个界面,SplashActivity 和 MainActivity。在桌面点击应用图标,启动 SplashActivity。打印启动流程
1 2 3 4 5 6 7 8 9
| E/xxxxxx: hookActivityThreadHHanlder: activityThread=android.app.ActivityThread@eaa28fb E/xxxxxx: hookActivityThreadHHanlder: mh=Handler (android.app.ActivityThread$H) {4121d18} E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-103ms what=100 obj=ActivityRecord{dfa7556 token=android.os.BinderProxy@9e859d7 {pub.hanks.testhooksplashactivity/pub.hanks.testhooksplashactivity.SplashActivity}} target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: obj=ActivityRecord{dfa7556 token=android.os.BinderProxy@9e859d7 {pub.hanks.testhooksplashactivity/pub.hanks.testhooksplashactivity.SplashActivity}} W/xxxxxx: SplashActivity.onCreate=pub.hanks.testhooksplashactivity.SplashActivity@56a8fa9 E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-51ms what=140 arg1=5 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-127ms what=149 obj=android.os.BinderProxy@9e859d7 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-1ms what=1010 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-10ms what=132 target=android.app.ActivityThread$H }
|
在handler处理消息过程中,判断是 LAUNCH_ACTIVITY
(100) 并且是 SplashActivity,替换成 MainActivity,此处注意 Android P上开始,启动 activity 变成了 EXECUTE_TRANSACTION
(159)
1 2 3 4 5 6 7 8 9
| // Application public class HookApplication extends Application {
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); HookHelper.hookActivityThreadHHanlder(); } }
|
找到 activityThread 的 mH
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // hook 并替换 public static void hookActivityThreadHHanlder() { try { // 获取 activityThread Class<?> aClass = Class.forName("android.app.ActivityThread"); Field sCurrentActivityThread = aClass.getDeclaredField("sCurrentActivityThread"); sCurrentActivityThread.setAccessible(true); Object activityThread = sCurrentActivityThread.get(aClass);
Log.e(TAG, "hookActivityThreadHHanlder: activityThread=" + activityThread);
//获取 mH Field mHField = aClass.getDeclaredField("mH"); mHField.setAccessible(true); Handler mh = (Handler) mHField.get(activityThread);
Log.e(TAG, "hookActivityThreadHHanlder: mh=" + mh);
Class<?> handlerClass = Class.forName("android.os.Handler"); Field mCallbackField = handlerClass.getDeclaredField("mCallback"); mCallbackField.setAccessible(true); mCallbackField.set(mh, new android.os.Handler.Callback() { @Override public boolean handleMessage(@NonNull Message msg) { // 处理启动 activity 的事件 handleLaunchActivityMessage(msg); return false; } }); } catch (Exception e) { e.printStackTrace(); } }
|
找到对应的 Message,然后进行替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public static final int LAUNCH_ACTIVITY = 100; public static final int EXECUTE_TRANSACTION = 159;
private static void handleLaunchActivityMessage(Message msg) { Log.e(TAG, "hookActivityThreadHHanlder: msg=" + msg); switch (msg.what) { case LAUNCH_ACTIVITY: { Object obj = msg.obj; Log.e(TAG, "hookActivityThreadHHanlder: obj=" + obj); try { Field intentField = HackHelper.getField(obj.getClass(), "intent"); intentField.setAccessible(true); Intent intent = (Intent) intentField.get(obj); if ("pub.hanks.testhooksplashactivity.SplashActivity".equals(intent.getComponent().getClassName())) { Log.e(TAG, "hookActivityThreadHHanlder: 原始 intent =" + intent); intent.setComponent(new ComponentName("pub.hanks.testhooksplashactivity", "pub.hanks.testhooksplashactivity.MainActivity")); Log.e(TAG, "hookActivityThreadHHanlder: 替换后的 intent intentCopy=" + intent); } } catch (Exception e) { e.printStackTrace(); } } break;
case EXECUTE_TRANSACTION: // 适配 androidP, HackHelper 突破 P 上反射限制 { Object object = msg.obj; Log.e(TAG, "hookActivityThreadHHanlder: 159 obj=" + object); try { //拿到ClientTransaction中的列表:mActivityCallbacks Field mActivityCallbacksField = HackHelper.getField(object.getClass(), "mActivityCallbacks"); mActivityCallbacksField.setAccessible(true); List<Object> mActivityCallbacks = (List<Object>) mActivityCallbacksField.get(object); //拿到LaunchActivityItem的实例对象. String itemName = "android.app.servertransaction.LaunchActivityItem"; for (Object obj : mActivityCallbacks) { Log.e(TAG, "hookActivityThreadHHanlder: mActivityCallbacks=" + obj); if (itemName.equals(obj.getClass().getCanonicalName())) { //拿到LaunchActivityItem中的mIntent. Field mIntentField = HackHelper.getField(obj.getClass(), "mIntent"); mIntentField.setAccessible(true); Intent intent = (Intent) mIntentField.get(obj); if ("pub.hanks.testhooksplashactivity.SplashActivity".equals(intent.getComponent().getClassName())) { Log.e(TAG, "hookActivityThreadHHanlder: 原始 intent =" + intent); intent.setComponent(new ComponentName("pub.hanks.testhooksplashactivity", "pub.hanks.testhooksplashactivity.MainActivity")); Log.e(TAG, "hookActivityThreadHHanlder: 替换后的 intent intentCopy=" + intent); } break; } } } catch (Exception e) { e.printStackTrace(); } } break;
default: break; } }
|
hook 后成功替换了 SplashActivity, 直接启动了 MainActivity
1 2 3 4 5 6 7 8 9 10 11 12
| E/xxxxxx: hookActivityThreadHHanlder: activityThread=android.app.ActivityThread@eaa28fb E/xxxxxx: hookActivityThreadHHanlder: mh=Handler (android.app.ActivityThread$H) {4121d18} E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-95ms what=140 arg1=5 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-100ms what=100 obj=ActivityRecord{dfa7556 token=android.os.BinderProxy@9e859d7 {pub.hanks.testhooksplashactivity/pub.hanks.testhooksplashactivity.SplashActivity}} target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: obj=ActivityRecord{dfa7556 token=android.os.BinderProxy@9e859d7 {pub.hanks.testhooksplashactivity/pub.hanks.testhooksplashactivity.SplashActivity}} E/xxxxxx: hookActivityThreadHHanlder: 原始 intent =Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=pub.hanks.testhooksplashactivity/.SplashActivity (has extras) } E/xxxxxx: hookActivityThreadHHanlder: 替换后的 intent intentCopy=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=pub.hanks.testhooksplashactivity/.MainActivity (has extras) } W/xxxxxx: MainActivity.onCreate=pub.hanks.testhooksplashactivity.MainActivity@56a8fa9 E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-26ms what=149 obj=android.os.BinderProxy@9e859d7 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-2ms what=1010 target=android.app.ActivityThread$H } E/xxxxxx: hookActivityThreadHHanlder: msg={ when=-9ms what=132 target=android.app.ActivityThread$H }
|
文章来自: https://hanks.pub