Service 插件化

代理分发实现

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 方告来完成代理分发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值