代理分发实现
Service 插件化的重点是保证它的优先级,这就需要一个真正的 Service 来实现,而不是像占坑 Activity 那样起一个占坑的作用。 当启动插件 Service 时,就会先启动代理 Service,当这个代理 Service 运行起来之后,在它的 onStartCommand 等方法里面进行分发,执行插件 TargetService的 onCreate 等方法,这一方案就叫作代理分发。
启动代理 Service
Service 插件化需要一个真正的 Service 来实现,我们先要在 AndroidManifest.xml 中注册代理 ProxyService,如下所示:
<service android:name=".hook.service.ProxyService"/>
在 MainActivity 中启动插件 Service:
Intent intent = new Intent(MainActivity2.this, TargetService.class);
startService(intent);
TargetService.java
public class TargetService extends Service {
private static final String TAG = "TargetService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
TargetService 用来代表插件 Service ,不能够直接启动,需要先启动代理 ProxyService。首先定义替换!ActivityManager 的代理类 IActivityManagerProxy:
public class IActivityManagerProxy implements InvocationHandler {
private Object mActivityManager;
private static final String TAG = "IActivityManagerProxy";
public IActivityManagerProxy(Object mActivityManager) {
this.mActivityManager = mActivityManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("startService".equals(method.getName())){//1.
Intent intent;
int index = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Intent){
index = i;
break;
}
}
intent = (Intent) args[index];
Intent proxyIntent = new Intent();//2.
String packageName = "com.imooc.javaioc.hook.service";
proxyIntent.setClassName(packageName,packageName+".ProxyService");//3
proxyIntent.putExtra(ProxyService.TARGET_SERVICE,intent.getComponent().getClassName()); //4
args[index] = proxyIntent; //5
Log.d(TAG,"Hook 成功");
}
return method.invoke(mActivityManager,args);
}
}
在注释 1 处拦截 startService 方法,接着获取参数 args 中第一个 Intent 对象
在注释2、 注释3处新建一个 proxyIntent 用来启动 ProxyService
注释4 处将这个 ProxyService 的 Intent 保存到 proxyIntent 中
注释 5 处将 proxyIntent 值给参数 args ,这样启动的目标就变为了 ProxyService。
用 IActivityManagerProxy 来替换系统的!Activity Manager:
HookHelper.java
public class HookHelper {
public static final String TARGET_INTENT = "target_intent";
public static void hookAMS() throws Exception{
Object defaultSingleton = null;
if (Build.VERSION.SDK_INT >= 26){ // 1
Class<?> activityManagerClazz = Class.forName("android.app.ActivityManager");
//获取 activityManager 中的 IActivityMaηagerSingleton 字段
defaultSingleton = FieldUtil.getField(activityManagerClazz, null, "" +
"IActivityManagerSingleton");
}else{
Class<?> activityManagerNativeClazz = Class.forName("android.app.ActivityManagerNative");
//获取 ActivityManagerNative 中的 gDefault 字段
defaultSingleton = FieldUtil.getField(activityManagerNativeClazz, null, "" +
"gDefault");
}
Class<?> singletonClazz = Class.forName("android.util.Singleton");
// 处获取 Singleton 中的 mlnstance
Field mInstanceField = FieldUtil.getField(singletonClazz, "mInstance"); // 2
// 获取 iActivityManager
Object iActivityManager = mInstanceField.get(defaultSingleton); //3
////获取 iActivityManager
Class<?> iIActivityManagerClazz = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{iIActivityManagerClazz},new IActivityManagerProxy(iActivityManager));
mInstanceField.set(defaultSingleton,proxy);
}
}
在注释 1 处对系统版本进行区分,最终获取的是 Singleton<IActivityManager>类型的IActivityManagerSingleton 或者 gDefault 字段。
在注释 2 处获取 Singleton 类中的 mlnstance 字段。
在注释 3 处得到 IActivityManagerSingleton 或者 gDefault 宇段中的 T 的 类型,T的类型为 IActivityManager。
最后动态创建代理类 IActivityManagerProxy ,用 IActivityManagerProxy来替换 IActivityManager。
自定义一个 Application 周用 HookHelper 的 hookAMS 方法:
BaseApplication.java
public class BaseApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
HookHelper.hookAMS();
} catch (Exception e) {
e.printStackTrace();
}
}
代理分发
ProxyService.java
public class ProxyService extends Service {
public static final String TARGET_SERVICE ="target_service" ;
private static final String TAG = "TargetService";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@SuppressLint("PrivateApi")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (null == intent || !intent.hasExtra(TARGET_SERVICE)){
return START_STICKY;
}
String serviceName = intent.getStringExtra(TARGET_SERVICE);
if (null == serviceName){
return START_STICKY;
}
Service targetService = null;
try{
Class activityThreadClazz = Class.forName("android.app.ActivityThread");
Method getApplicationThread = activityThreadClazz.getDeclaredMethod("getApplicationThread");
getApplicationThread.setAccessible(true);
Object activityThread = FieldUtil.getField(activityThreadClazz,null,"sCurrentActivityThread");// 1
Object applicationThread = getApplicationThread.invoke(activityThread); // 2
Class iInterfaceClazz = Class.forName("android.os.IInterface");
Method asBinderMethod = iInterfaceClazz.getDeclaredMethod("asBinder");
asBinderMethod.setAccessible(true);
Object token = asBinderMethod.invoke(applicationThread); // 3
Class serviceClazz = Class.forName("android.app.Service");
Method attachMethod = serviceClazz.getDeclaredMethod("attach", Context.class,activityThreadClazz,String.class,IBinder.class,
Application.class,Object.class);
attachMethod.setAccessible(true);
Object defaultSingleton = null;
if (Build.VERSION.SDK_INT >= 26){ // 4
Class<?> activityManagerClazz = Class.forName("android.app.ActivityManager");
// 获取 activityManagerClazz 中的 IActivityManagerSingleton 字段
defaultSingleton = FieldUtil.getField(activityManagerClazz,null,"IActivityManagerSingleton");
}else{
Class<?> activityManagerNativeClazz = Class.forName("android.app.ActivityManagerNative");
// 获取 ActivityManagerNative 中的 gDefault 字段
defaultSingleton = FieldUtil.getField(activityThreadClazz,null,"gDefault");
}
Class<?> singletonClazz = Class.forName("android.util.Singleton");
Field mInstanceField = FieldUtil.getField(singletonClazz , "mInstance");
// 获取 iActivityManager
Object iActivityManager = mInstanceField.get(defaultSingleton);// 5
targetService = (Service) Class.forName(serviceName).newInstance(); // 6
attachMethod.invoke(targetService,this,activityThread,intent.getComponent().getClassName(),
token,getApplication(),iActivityManager); // 7
targetService.onCreate();
}catch (Exception e){
e.printStackTrace();
return START_STICKY;
}
targetService.onStartCommand(intent,flags,startId);
return START_STICKY;
}
}
- ProxyService 需要长时间对 Service 进行分发处理,所以在参数条件不满足、出现异常和代码执行完毕时需要返回 START_STICKY ,这样 ProxyService 会重新被创建并执行 onStartCommand 方法去。
- 创建 targetService 并反射调用 targetService 的 attach 方法。
- 进行代理分发,执行 targetService 的 onCreate 方法。
注释1 处得到 ActivityThread 对象。
注释 2 处根据 ActivityThread 得到 applicationThread 对象,得到 applicationThread 对象为的是在注释 3 处反射调用 ApplicationThread 的 asBinder 方怯得到 token 对象。
注释 4 和 注释 5 是为了获取 iActivityManager 。
在注释 处反射得到 targetService。
在注释 7 处反射执行 targetService 的 attach 方法,并传入此前得到的参数。
最后执行 targetService 的 onCreate 方告来完成代理分发。