一个简单的系统插桩实现
核心设计思想
插桩通过在系统关键流程中插入自定义逻辑,实现对系统行为的监控或修改,同时保持原有代码结构不变。其核心特点是:
- 无侵入性:不改动原有业务代码
- 动态替换:通过接口/抽象类实现逻辑替换
- 集中管理:统一通过XXXStub类控制实现
换一句程序员喜欢的人话:单例模式和接口解耦实现
本文是使用接口的方式进行实现
桩接口(Stub Interface):
DozePlusStub定义标准接口,提供单例模式插桩
桩实现(Stub Implementation):
DozePlusStubImpl包含实际业务逻辑
桩管理器(Stub Manager):
FadiEngineStub负责实现类的注入
1. 系统入口插桩(SystemServer)
在main中是android最早的启动入口,故非常适合插桩点注入
public static void main(String[] args) {
// 在系统启动时注入自定义实现
// 原理:利用Java类加载机制,在系统服务初始化前完成实现类替换
com.android.server.engine.FadiEngineStub.collectInjectors();
new SystemServer().run(); // 继续正常启动流程
}
2. 桩管理类(FadiEngineStub)
public class FadiEngineStub {
/**
* 系统级桩注入入口
* 作用:替换系统默认实现为自定义实现
*/
private static void collectInjectors() {
// 创建具体实现类并注入到全局桩接口
DozePlusStub.setInstance(Creator.createDozePlusImpl());
}
public static class Creator {
/**
* 工厂方法模式创建具体实现
* 优势:可在此处实现条件化创建(如根据设备类型选择不同实现)
*/
public static DozePlusStub createDozePlusImpl() {
return new DozePlusStubImpl(); // 返回带业务逻辑的实现
}
}
}
3. 桩接口设计(DozePlusStub)
动态替换实现的核心方法setInstance
package com.android.server.power.dozeplus;
public interface DozePlusStub {
static DozePlusStub getInstance() {
return InstanceHolder.get();
}
/**
* 动态替换实现的核心方法
*/
static void setInstance(DozePlusStub instance) {
InstanceHolder.set(instance);
}
class InstanceHolder {
private static DozePlusStub sInstance = new DozePlusStub() {
};
private static DozePlusStub get() {
return sInstance;
}
private static void set(DozePlusStub internal) {
sInstance = internal;
}
}
/**
* 插桩方法声明
* 典型应用:在系统原有逻辑中插入自定义事件处理
*/
default void screenOnEvent() {
// 默认空实现保证系统不崩溃
}
}
4. 桩实现类(DozePlusStubImpl)
public class DozePlusStubImpl implements DozePlusStub {
private long mLastScreenOnTime;
/**
* 实际业务逻辑实现
* 被插入到DeviceIdleController的屏幕状态处理流程中
*/
@Override
public void screenOnEvent() {
// 记录屏幕点亮时间(可用于统计亮屏时长等业务)
mLastScreenOnTime = SystemClock.elapsedRealtime();
// 可扩展:在此处添加通知逻辑、性能调优等
}
}
5. 系统原有逻辑插桩点(DeviceIdleController)
@GuardedBy("this")
void updateInteractivityLocked() {
boolean screenOn = mPowerManager.isInteractive();
if (screenOn) {
// >>>>> 插桩点开始 <<<<<
// 原理:在系统原有状态判断逻辑中插入自定义回调
DozePlusStub.getInstance().screenOnEvent();
// >>>>> 插桩点结束 <<<<<
mScreenOn = true;
// ... 原有逻辑 ...
}
}
系统最简单的插桩就是单例模式把事件引过来,为了对于追求代码优雅和解耦的要求,也会进行通过单例模式+接口解耦+反射实现逻辑进行封装,让stub接口类和stubImpl实现类解耦。