二、Hook Activity 启动过程
1、分析相关 类 / 成员 / 方法 结构
要 Hook 的方法是 Instrumentation 的 execStartActivity 方法 ;
public class Instrumentation { @UnsupportedAppUsage public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { } }
Activity 中维护了 Instrumentation mInstrumentation 成员变量 ;
// 1. 获取 Activity 字节码文件 // 字节码文件是所有反射操作的入口 Class<?> clazz = Activity.class;
public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { // set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called. @UnsupportedAppUsage private Instrumentation mInstrumentation; }
2、反射获取 Activity 中的 Instrumentation mInstrumentation 成员字段
首先 , 任何反射操作 , 都要获取其字节码文件 , 作为反射的入口 , 这里先获取 Activity 字节码对象 , 直接通过 Activity.class 获取即可 ;
// 1. 获取 Activity 字节码文件 // 字节码文件是所有反射操作的入口 Class<?> clazz = Activity.class;
然后 , 获取 Activity 中的 Instrumentation mInstrumentation 成员 Field 字段 ;
// 2. 获取 Activity 的 Instrumentation mInstrumentation 成员 Field 字段 Field mInstrumentation_Field = null; try { mInstrumentation_Field = clazz.getDeclaredField("mInstrumentation"); } catch (NoSuchFieldException e) { e.printStackTrace(); }
最后 , 设置 Field mInstrumentation 字段的可访问性 , 只要是调用反射方法 , 或者访问反射的成员字段 , 第一件事就是设置可访问性 ;
正常可访问的方法或字段 , 绝对不会使用反射获取 , 既然使用了反射 , 那么设置可访问性是标配操作 ;
// 3. 设置 Field mInstrumentation 字段的可访问性
// 3. 设置 Field mInstrumentation 字段的可访问性 mInstrumentation_Field.setAccessible(true);
本步骤完整代码示例 :
// 1. 获取 Activity 字节码文件 // 字节码文件是所有反射操作的入口 Class<?> clazz = Activity.class; // 2. 获取 Activity 的 Instrumentation mInstrumentation 成员 Field 字段 Field mInstrumentation_Field = null; try { mInstrumentation_Field = clazz.getDeclaredField("mInstrumentation"); } catch (NoSuchFieldException e) { e.printStackTrace(); } // 3. 设置 Field mInstrumentation 字段的可访问性 mInstrumentation_Field.setAccessible(true);
3、获取 Activity 中的 Instrumentation mInstrumentation 成员字段值
获取 Activity 的 Instrumentation mInstrumentation 成员对象值 , 该成员值就是需要被代理的目标对象 ;
代理者 需要 持有 被代理的目标对象 ;
获取该成员的意义是 , 创建 Instrumentation 代理时, 需要将原始的 Instrumentation 传入代理对象中 ;
// 4. 获取 Activity 的 Instrumentation mInstrumentation 成员对象值 // 获取该成员的意义是 , 创建 Instrumentation 代理时, 需要将原始的 Instrumentation 传入代理对象中 Instrumentation mInstrumentation = null; try { mInstrumentation = (Instrumentation) mInstrumentation_Field.get(this); } catch (IllegalAccessException e) { e.printStackTrace(); }
4、设置 Activity 中的 Instrumentation mInstrumentation 成员字段值
设置 Activity 中的 Instrumentation mInstrumentation 成员字段值 , 将 Activity 的 Instrumentation mInstrumentation 成员变量 设置为自己定义的 Instrumentation 代理对象 ;
此处使用的是静态代理 ;
// 5. 将 Activity 的 Instrumentation mInstrumentation 成员变量 // 设置为自己定义的 Instrumentation 代理对象 try { mInstrumentation_Field.set(this, new InstrumentationProxy(mInstrumentation)); } catch (IllegalAccessException e) { e.printStackTrace(); }