基于《Android插件化开发指南》第4章对于ActivityManager hook的思考

最近在读包建强老师的《Android插件化开发指南》一书,在读到第4章对于ActivityManager hook时,有点小启发。先看hook的代码(基于Android9.0源码,兼容Android7.0之前的版本代码需改动):

   public class HookHelper {
       public static void hookActivityManager() {


        try {

            Class<?> amClass = Class.forName("android.app.ActivityManager");
            Field gDefaultField = amClass.getDeclaredField("IActivityManagerSingleton");
            gDefaultField.setAccessible(true);
            // 这个iActivityManagerSingleton对象实际上就是一个Singleton对象
            Object iActivityManagerSingleton = gDefaultField.get(null);


            // 反射Singleton类
            @SuppressLint("PrivateApi")
            Class<?> singleClass = Class.forName("android.util.Singleton");
            Field instanceField = singleClass.getDeclaredField("mInstance");
            instanceField.setAccessible(true);
            Object rawIActivityManager = instanceField.get(iActivityManagerSingleton);

            // 注释留空处


            @SuppressLint("PrivateApi")
            Class<?> iActivityManagerInterface = Class.forName("android.app.IActivityManager");
            Object newProxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{iActivityManagerInterface},
                    new HookHandler(rawIActivityManager));

            // 将IActivityManagerSingleton中的mInstance字段替换成proxy对象
            instanceField.set(iActivityManagerSingleton, newProxyInstance);


        } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }


    }
 }

 public class HookHandler implements InvocationHandler {

    private Object mBase;

    public HookHandler(Object base){
        this.mBase = base;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Log.e("TAG", "-> before invoke....");
        Object result = method.invoke(mBase, args);
        Log.e("TAG",  "-> method name -> " + method.getName());
        Log.e("TAG",  "-> after invoke....");

        return result;
    }
 }

基础知识点就是反射和动态代理(不熟悉的童鞋可参看我的之前一篇文章)的使用。紧接着,我在MainActivity中调用了hookActivityManager方法,然后运行app,查看Log:

哇塞,hook成功了,好强大!但是当我第二次再打开app时,发现了一个问题:

发现会调用两次。第三次打开app呢?

会调用三次。

这是怎么回事呢?因为我们是在MainActivity中调用的,每次打开app都会进行一次hook,这样当第二次hook时,实际上是对第一次hook的代理对象又一次进行代理封装,此时相当于有两层代理对象了。同样地,第三次打开app时就会有三层代理对象了。所以,InvocationHandler的invoke方法会输出多次。我们可以试图来解决这个问题。

在前面代码的注释留空处添加:

if (Proxy.isProxyClass(rawIActivityManager.getClass())) {
    return;
}

这样就会hook一次。(这里建议将我们的demo卸载掉,重新安装)

##### 2020.06.12更新

评论区有小伙伴问到:instanceField.get(iActivityManagerSingleton);这个地方为什么要传入iActivityManagerSingleton。本来在评论区已经回复了,但是有些字打错,然后一不小心就把评论删了。这里直接在文章中解释了:实际上我们这里好像剥洋葱一样,先拿到ActivityManager中的IActivityManagerSingleton静态属性:

private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

由于IActivityManagerSingleton是Singleton类型对象,而Singleton的定义:

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

所以instanceField.get(iActivityManagerSingleton);  这行代码依据就在这里,就是为了拿到Singleton中的mInstance指向的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值