反射之泛型类简单介绍

Android2024年1月13日 am8:08发布7个月前更新 3XCN.COM站长
0 1 0
广告也精彩
目录

前言

对于泛型类型,Android源码中是很常见的。偶尔需要对泛型进行反射,因此,记录一下,方便自己查阅。

Android P,不同版本可能不同

正文

本文以hook一下ActivityManager.startActivity(),在startActivity()启动新的Activity时打印Intent中带的参数。

回顾

之前《startActivity源码分析1》中介绍过startActivity()的分析。

Instrumentation.java
execStartActivity()
public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    //略
    //mActivityMonitors为null
    if (mActivityMonitors != null) {
        //略
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        //调用的ActivityManagerService.startActivity()
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

上面有个比较重要的

int result = ActivityManager.getService()
    .startActivity(whoThread, who.getBasePackageName(), intent,
    intent.resolveTypeIfNeeded(who.getContentResolver()),
    token, target != null ? target.mEmbeddedID : null,
    requestCode, 0, null, options);

虽然最终是调用了ActivityManagerService.startActivity(),这部分之前我们是略过的。

我们看看ActivityManager。

ActivityManager.java
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
    @Override
    protected IActivityManager create() {
        //通过ServiceManager获取了ActivityManagerService的IBinder
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
        return am;
    }
};

也就是这里,通过Singleton创建了IActivityManagerSingleton。

Singleton.java
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;
        }
    }
}

Singleton是个泛型。

这里是个泛型,也是唯一一个初始的地方,算是比较好hook的地方,也就是只需要替换mInstance即可。

HookAMS

本文主要以参考文中HookAMS例子基础上修改

IActivityManagerSingleton

先获取到IActivityManagerSingleton变量,这个是私有的静态变量。(若有疑惑,可看《反射之获取类的构造函数等》)

//加载ActivityManager类的Class
Class activityManagerClass = Class.forName("android.app.ActivityManager");
//获取IActivityManagerSingleton的Field
Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
//private修饰的变量
iActivityManagerSingletonField.setAccessible(true);
//获取IActivityManagerSingleton变量
//静态变量,针对类反射,参数传入null
Object IActivityManagerSingleton = iActivityManagerSingletonField.get(null);

通过上面,就可以获取到IActivityManagerSingleton变量。

mInstance

从上面知道,Singleton是一个泛型。如果要获取的mInstance其实就是Singleton<IActivityManager>的变量。

//加载Singleton类型
Class singletonClass = Class.forName("android.util.Singleton");
//获取mInstance的Field
Field mInstanceField = singletonClass.getDeclaredField("mInstance");
//mInstance是非静态私有变量
mInstanceField.setAccessible(true);
//获取mInstance变量,传入IActivityManagerSingleton是要获取此对象的mInstance变量
Object mInstance = mInstanceField.get(IActivityManagerSingleton);
HookAMS完整代码
HookHandler
class HookHandler implements InvocationHandler {
    private final String TAG = "BiuA_" + getClass().getName();
    private final Object mObject;
    
    public HookHandler(Object object) {
        mObject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //拦截startActivity,并打印Intent中的参数
        //IActivityManager中有很多方法
        if (method.getName().equals("startActivity")) {
            for (Object obj : args) {
                Log.d(TAG, "invoke obj : " + obj);
            }
        }
        return method.invoke(mObject, args);
    }
}
hook主要代码
try {
    //加载ActivityManager类的Class
    Class activityManagerClass = Class.forName("android.app.ActivityManager");
    //获取IActivityManagerSingleton的Field
    Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
    //private修饰
    iActivityManagerSingletonField.setAccessible(true);
    //获取IActivityManagerSingleton变量
    //静态变量,针对类反射,参数传入null
    Object IActivityManagerSingleton = iActivityManagerSingletonField.get(null);
    
    //加载Singleton
    Class singletonClass = Class.forName("android.util.Singleton");
    //获取mInstance的field
    Field mInstanceField = singletonClass.getDeclaredField("mInstance");
    //private修饰
    mInstanceField.setAccessible(true);
    //获取mInstance变量
    //传入IActivityManagerSingleton,是要获取此对象的mInstance变量
    Object mInstance = mInstanceField.get(IActivityManagerSingleton);
    
    //加载IActivityManager接口类(IActivityManager.aidl)
    //需要动态代理其的接口中的方法
    Class mIActivityManagerClass = Class.forName("android.app.IActivityManager");

    //动态代理
    Object proxy = Proxy.newProxyInstance(
        //使用当前线程的类加载器
        Thread.currentThread().getContextClassLoader(),
        //需要代理的接口
        new Class[]{mIActivityManagerClass},
        //创建InvocationHandler对象,这里HookHandler实现了
        new HookHandler(mInstance));
    //把Singleton的mInstance替换为proxy
    mInstanceField.set(IActivityManagerSingleton, proxy);
} catch (Exception e) {
    throw new RuntimeException("Hook Failed", e);
}

打印一下日志

invoke obj : android.app.ActivityThread$ApplicationThread@991d261
invoke obj : com.biumall.biutextview
invoke obj : Intent { cmp=com.biumall.biutextview/.SecondActivity (has extras) }
invoke obj : null
invoke obj : android.os.BinderProxy@c598330
invoke obj : null
invoke obj : -1
invoke obj : 0
invoke obj : null
invoke obj : null

部分关于Proxy.newProxyInstance()可以看《动态代理Proxy.newProxyInstance》。

参考文章

  1. 《Android插件化开发指南-包建强》

  2. 反射之获取类的构造函数等

  3. 动态代理Proxy.newProxyInstance

 历史上的今天

版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站文章: 部分来源于网络,仅供站长学习和参考,若侵权请留言
广告也精彩

相关文章

广告也精彩

1 条评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

  • 改变自己
    改变自己 管理员

    看看

    广东省深圳市
    回复

网站升级中

公告

近期网站升级中,可能存在一些bug。欢迎反馈 https://www.91es.com/we.html

本站域名

本站域名 : 91es.com3xcn.com。本站邮箱 : 站长邮箱 i@oorr.cn,通知邮箱we@oorr.cn ,如有更新,请看公告 。