美文网首页Andorid的好东西
Java 利用反射遍历类和对象信息

Java 利用反射遍历类和对象信息

作者: 1999c1b720cd | 来源:发表于2018-07-23 00:08 被阅读90次

背景

项目中遇到需要监控 System.loadLibrary 方法调用,实现如果链接失败则弹出对话框的「问题」。「解决方案」就是 hook java.lang.Runtime#nativeLoad 方法对应的 JNI 函数入口 art#ArtMethod#ptr_sized_fields#data_ 字段,从而先跳转到我们 hook 的函数再执行系统的 JNI 函数。这个需要在运行时拿到一个 Java 方法的相关信息,比如 Method 类、ArtMethod 类、JNI 函数信息等。反射是能读写一个类、对象的内部数据的一种手段,在此做记录。

问题

  • 我们能不能拿到系统某些 private 字段的信息 ?
  • 我们能不能执行系统某些 private 方法?
  • 我们能不能拦截某些系统的行为?
    接下来记录一下使用反射拦截主线程消息队列例子

反射的使用方法

  • 拿到 Class 对象
    • 通过 java.lang.Class#forName(java.lang.String) 拿类名对应的类
    • 通过 java.lang.Object#getClass 拿对象所属的类
    • 通过 java.lang.Class#getSuperclass 拿父类
  • 拿到 Field / Method 对象
    • 拿当前类(不包含父类)字段 java.lang.Class#getDeclaredField
    • 拿当前类方法 java.lang.Class#getDeclaredMethod
  • 读写字段 / 执行方法
    • 读字段 java.lang.reflect.Field#get
    • 写字段 java.lang.reflect.Field#set
    • 执行方法 java.lang.reflect.Method#invoke

拦截主线程消息处理

Android Message 处理流程
  • Android 主线程是设计成事件驱动,Java 层的核心是生产者/消费者模型
  • 主线程属于消费者,负责从 android.os.MessageQueue 中取消息执行
  • 当前进程内的所有线程都可以作为生产者向 android.os.MessageQueue 中投递消息,这样就让某些代码在主线程执行
  • 主线程执行到 android.os.Looper#loop 中时就进入了轮询过程,取消息,执行消息
  • 由于 android.os.Looper#sThreadLocal 变量是 java.lang.ThreadLocal 类型,所以每个 java.lang.Thread 对象至多有一个 android.os.Looper 对象
  • 因此我们需要拿到主线程的 android.os.MessageQueue 和 android.os.Looper 对象
  • 利用 android.os.Looper#getMainLooper 接口可以很简单拿到 Looper 对象
  • 拿到 Looper 对象后可以利用反射遍历对象的所有字段,拿到 android.os.Looper#mQueue 字段
  • 接下来我们模拟 android.os.Looper#loop 内部的实现,反射执行 android.os.MessageQueue#next 方法取得一条消息
  • 找到消息所属的 Handler 对象 android.os.Message#getTarget
  • 给 Handler 派发消息 android.os.Handler#dispatchMessage
    这样我们在应用层就能够看到主线程的每条消息,从而改变系统的某些行为,比如某些消息不执行
// 拿到 Looper 对象
Looper mainLooper = Looper.getMainLooper();
// 拿到 MessageQueue 对象
MessageQueue queue = (MessageQueue) Reflection.field(null, null, mainLooper, "mQueue");
while (true){
    // 取消息
    Message msg = (Message) Reflection.call(null, null, queue, "next", new Class[]{});
    if (msg != null){
        Log.d(TAG, "run: " + msg);
        // 这里拦截消息
        ...

        Handler handler = msg.getTarget();
        // 派发消息
        handler.dispatchMessage(msg);
    }
}

练习题

  • 利用反射遍历类层次结构
// 拿到 Class 对象
Class c = xx;
while (c != null) {
    // 读取 c 信息
    ...

    // 指向父类
    c = c.getSuperclass();
}
  • 利用反射遍历对象的所有字段和值
Class c = xx;
while (c != null) {
    Field[] fields = c.getDeclaredFields();
    for (Field f : fields) {
        try {
            f.setAccessible(true);
            Log.d(TAG, f + " = " + f.get(obj));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    c = c.getSuperclass();
}
  • 利用反射修改 private 字段和执行 private 方法
Class c = xx;
// 遍历类结构
while (c != null) {
    // 遍历当前类所有字段
    for (Field f : c.getDeclaredFields()) {
        // 查找指定字段名
        if (f.getName().equals(fieldName)) {
            f.setAccessible(true);
            // 修改字段的值
            f.set(o, value);
            return;
        }
    }

    c = c.getSuperclass();
}
Class c = xx;
while (c != null) {
    Method m = null;
    try{
        // 在当前类查找
        m = c.getDeclaredMethod(name, parameterTypes);
    } catch (Throwable e){
        Log.e(TAG, "call: ", e);
    }

    if (m != null){
        m.setAccessible(true);
        // 执行方法
        value = m.invoke(o, args);
        break;
    }

    c = c.getSuperclass();
}

总结

  • 在读写系统私有信息方面,反射是一个不错的技术手段。

相关文章

  • Java 利用反射遍历类和对象信息

    背景 项目中遇到需要监控 System.loadLibrary 方法调用,实现如果链接失败则弹出对话框的「问题」。...

  • 判断对象的部分属性是否为空

    利用反射获取对象属性,遍历进行判断 测试: 实体类:

  • Java入门--反射

    Java入门--反射(Reflect) 利用反射和配置文件, 加载不同的类和方法 创建配置文件对象 new Pro...

  • Class类与JAVA反射

    Class类与JAVA反射通过反射可以访问的主要信息 包路径 getPackage() Package对象 ...

  • 反射

    反射简介 反射允许我们在程序运行时获取和使用类的信息。 Class 对象 Java程序运行时,用Class对象表示...

  • 【日拱一卒】:反射的作用和意义?

    Java的反射:在程序运行过程中,动态的获取类的信息和动态调用对象的方法。反射就是把java类中的各种成分映射成一...

  • jvm结构分析

    堆 创建的对象都放在这里 方法区 class加载的时候类的信息都放到这里,利用java反射获取的信息就是来自这里 ...

  • java面试知识点(四)- java 动态代理

    java 反射 反射是一种机制,提供java 程序在RunTime获取类的元属性信息,创建对象,执行方法,修改权限...

  • JAVA 获取Bean对象的属性名和该属性对应的值

    主要使用到了java.beans包下的类,利用底层反射来获取对象对应的属性和方法; ** BeanInfo **:...

  • Spring

    反射 给定一个类的名字(字符串形式),怎么创建该类的对象? 利用Class类构造实例 什么是反射机制? Java反...

网友评论

    本文标题:Java 利用反射遍历类和对象信息

    本文链接:https://www.haomeiwen.com/subject/hcmrmftx.html