Android随笔-Instrumentation
一、Instrumentation 的本质定位
Instrumentation 是 Android 框架在SystemServer(AMS) 与 应用组件(Activity)之间插入的一个代理层/钩子(Proxy/Hook)。它既负责 Activity 等组件的创建和生命周期分发,又是 Android 自动化测试框架的核心基石,让测试代码能够与被测应用运行在同一进程中,实现对应用的精确控制和监控。它不是一个独立的进程,而是作为 ActivityThread 的成员变量存在,与应用运行在同一个进程中。
SystemServer (AMS) ←──Binder IPC──→ ActivityThread ←──Instrumentation──→ Activity
二、核心源码流程:Activity 启动中的 Instrumentation
2.1 调用链路全景
ActivityThread.performLaunchActivity()
→ Instrumentation.newActivity() // 反射创建 Activity
→ Activity.attach() // 绑定 Context、Window、Token
→ Instrumentation.callActivityOnCreate() // 触发生命周期
→ Activity.performCreate()
→ Activity.onCreate() // 开发者入口
2.2 Instrumentation.newActivity() 源码解析
// frameworks/base/core/java/android/app/Instrumentation.javapublicActivitynewActivity(ClassLoadercl,StringclassName,Intentintent)throwsInstantiationException,IllegalAccessException,ClassNotFoundException{Stringpkg=intent!=null&&intent.getComponent()!=null?intent.getComponent().getPackageName():null;// (1) Android 9+ 通过 AppComponentFactory 工厂模式创建returngetFactory(pkg).instantiateActivity(cl,className,intent);}关键点:
- 工厂模式:Android 9 之后引入了 AppComponentFactory,允许开发者自定义组件实例化方式(插件化框架常利用此点)
- 旧版本直接反射:Class.newInstance() 调用无参构造器创建 Activity
- attach 绑定:创建后立即调用 activity.attach() 绑定 Context、Window、Token 等核心对象
2.3 Instrumentation.callActivityOnCreate() 源码解析
// frameworks/base/core/java/android/app/Instrumentation.javapublicvoidcallActivityOnCreate(Activityactivity,Bundleicicle){prePerformCreate(activity);// (1) 前置钩子(可重写)activity.performCreate(icicle);// (2) 调用 Activity.performCreate()postPerformCreate(activity);// (3) 后置钩子(可重写)}// Activity.javafinalvoidperformCreate(Bundleicicle){dispatchActivityPreCreated(icicle);// 分发 PreCreate 事件if(mPersistentState!=null){onCreate(icicle,mPersistentState);}else{onCreate(icicle);// 最终调用开发者重写的 onCreate()}performCreateCommon();dispatchActivityPostCreated(icicle);// 分发 PostCreate 事件}关键点:
- prePerformCreate / postPerformCreate 是空方法,专门留给子类重写——这就是钩子机制
- 测试框架(如 AndroidJUnitRunner)重写这些方法,可以在 onCreate 前后注入 Mock 对象
- performCreate 是 final 方法,框架严格控制生命周期调用顺序
三、Instrumentation 作为"钩子"的设计模式
3.1 为什么能 Hook?
Instrumentation 是ActivityThread的一个成员变量:
// ActivityThread.javapublicfinalclassActivityThread{InstrumentationmInstrumentation;// 单例,一个进程只有一个}Hook 原理:通过反射替换ActivityThread 中的 mInstrumentation 字段:
// Hook 伪代码Class<?>activityThreadClass=Class.forName("android.app.ActivityThread");FieldsCurrentActivityThreadField=activityThreadClass.getDeclaredField("sCurrentActivityThread");sCurrentActivityThreadField.setAccessible(true);ObjectcurrentActivityThread=sCurrentActivityThreadField.get(null);FieldmInstrumentationField=activityThreadClass.getDeclaredField("mInstrumentation");mInstrumentationField.setAccessible(true);Instrumentationoriginal=(Instrumentation)mInstrumentationField.get(currentActivityThread);// 用自定义 Proxy 替换Instrumentationproxy=newInstrumentationProxy(original);mInstrumentationField.set(currentActivityThread,proxy);3.2 插件化框架如何利用它?
以 VirtualApk 为例,它重写了 Instrumentation 的三个关键方法:
| 方法 | 作用 |
|---|---|
execStartActivity | 拦截 startActivity 请求,替换 Intent 中的目标 Activity 为"坑位"Activity,欺骗 AMS 的 Manifest 校验 |
newActivity | 当 AMS 回调创建"坑位"Activity 时,从 Intent 中还原真实目标 Activity,反射创建真正的插件 Activity |
callActivityOnCreate | 在onCreate之前注入插件的 Resources、Context、Application |
四、Instrumentation 的关键方法一览
| 方法 | 作用 |
|---|---|
newActivity() | 反射创建 Activity 实例 |
callActivityOnCreate() | 触发 Activity.onCreate() |
callActivityOnStart() | 触发 Activity.onStart() |
callActivityOnResume() | 触发 Activity.onResume() |
callActivityOnPause() | 触发 Activity.onPause() |
callActivityOnStop() | 触发 Activity.onStop() |
callActivityOnDestroy() | 触发 Activity.onDestroy() |
newApplication() | 创建 Application 实例 |
callApplicationOnCreate() | 触发 Application.onCreate() |
execStartActivity() | 启动 Activity 的入口(可拦截) |
sendPointerSync() | 发送触摸事件(UI 测试) |
sendKeyDownUpSync() | 发送按键事件(UI 测试) |
五、核心作用
1. 组件创建与生命周期代理
- Application 创建:Instrumentation.newApplication() 负责创建 Application 对象
- Activity 启动:Instrumentation.newActivity() 负责通过反射实例化 Activity
- 生命周期分发:所有 Activity 的生命周期回调(onCreate、onResume、onPause 等)实际上都是通过 Instrumentation.callActivityOnXXX() 方法分发的
- 也就是说,Activity 的启动流程中,Instrumentation 是绕不开的关键节点——从 ActivityThread 到 Activity 的创建和生命周期调用,都要经过它
2. 自动化测试框架
这是 Instrumentation 最广为人知的用途:
- 测试 APK 和被测 APK 运行在同一个进程中,Instrumentation 作为桥梁实现直接交互
- 可以发送 UI 事件(点击、按键、触摸等)到被测应用
- 可以注入模拟的 Intent 启动 Activity
- 可以控制组件生命周期,检查程序运行状态
- 支持创建模拟的系统对象(MockContext、MockApplication 等)进行单元测试
3. 系统与应用交互的"钩子"
类似于 Windows 的 Hook 机制,Instrumentation 在系统与应用之间安装了一个"监听器":
- 监听 Activity 的启动、结束等事件
- 拦截并控制组件间的交互行为
- 可以获取应用上下文的 Handle,从而深入洞察应用内部状态
4. 典型使用场景
| 场景 | 说明 |
|---|---|
| 单元测试 | ActivityUnitTestCase可注入 MockContext/MockApplication |
| UI 自动化测试 | ActivityInstrumentationTestCase2可发送按键/触摸事件 |
| 应用性能监控 | 通过自定义 Instrumentation 统计 Activity 启动耗时 |
| 热修复/插件化 | 某些方案通过替换 Instrumentation 实现组件的动态加载 |
| 自动化测试框架 | Espresso、UI Automator 等底层都依赖 Instrumentation |
5. 在 Manifest 中的配置
<instrumentationandroid:name="androidx.test.runner.AndroidJUnitRunner"android:targetPackage="com.example.myapp"android:handleProfiling="true"android:functionalTest="false"/>- android:name:指定 Instrumentation 的实现类(测试 Runner)
- android:targetPackage:指定被测应用的包名
- 运行测试时,AMS 会先杀掉目标应用进程,然后以 Instrumentation 为入口重新启动,确保测试代码和被测代码在同一进程内运行
六、总结
Instrumentation 的核心原理是:Android 框架在「系统服务层」与「应用组件层」之间插入了一个「代理/钩子」。它通过「反射创建」+「生命周期中转」+「可重写钩子」三大机制,实现了对 Activity 等组件的创建控制、生命周期监控和测试注入。