反射之泛型类简单介绍

Android2024年1月13日 am8:08发布8个月前更新 91es.com站长
29 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. 2021: Android焦点管理类AudioFocusManager(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com[备用域名]
3、 本站内容: 部分来源于网络,仅供站长学习和参考,若侵权请留言

1 条评论

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

    看看

    广东省
    回复

随机推荐

Android 强制性横屏和设置系统横屏简介

前言简单记录一下应用横屏和系统横屏的使用。网上很多,但还是自己整理一下,方便自己查阅。正文Android横屏有应用横屏和系统横屏。单个应用横屏就是只对当前应用有效,其他应用依旧跟系统保持一样,系统横屏的话对所有应用有效(前提是应用没有自己单独处理)。下面介绍应用横屏,系统横屏的配置,以及...

泰戈尔:生如夏花

生命,一次又一次轻薄过轻狂不知疲倦——题记 1我听见回声,来自山谷和心间以寂寞的镰刀收割空旷的灵魂不断地重复决绝,又重复幸福终有绿洲摇曳在沙漠我相信自己生来如同璀璨的夏日之花不凋不败,妖冶如火承受心跳的负荷和呼吸的累赘乐此不疲 2我听见音乐,来自...

Android ListView子item高度定长固定值无效问题详解

前言最近做显示音乐列表信息时,发现ListView的Item布局中固定的高度失效了,怎么设置这个高度都失效。参考网用和自己折腾过程,记录一下,防止下次忘记。总结整理一下原因:1. LayoutInflater.inflate(int resource, ViewGroup root)...

朱自清:背影

那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!”回家变卖典质,父亲还了亏空;又借钱办了丧事。这些日子,家中光景很是惨淡,一半为了丧事...

铁凝:幸福就在此刻

去探望一位生病的友人,聊起很多从前的事情,计划很多未来的事情,她忽然发问:对于你来说,幸福的时刻是什么?想了半天,竟然没有一个很适合的答案。那阵子,经常携带这个难题去和人打交道,不管是新朋还是故友,聊到酣畅总是抛出这个问题冷场,当然,收获的答案也是五花八门——有人说,幸福的时刻就是加官晋爵时买房...

丰子恺:秋

我的年岁上冠用了“三十”二字,至今已两年了。不解达观的我,从这两个字上受到了不少的暗示与影响。虽然明明觉得自己的体格与精力比二十九岁时全然没有什么差异,但“三十”这一个观念笼在头上,犹之张了一顶阳伞,使我的全身蒙了一个暗淡色的阴影,又仿佛在日历上撕过了立秋的一页以后,虽然太阳的炎威依然没有减却,寒暑...