Andorid的好东西

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

2018-07-23  本文已影响90人  1999c1b720cd

背景

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

问题

反射的使用方法

拦截主线程消息处理

Android Message 处理流程
// 拿到 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();
}
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();
}

总结

上一篇 下一篇

猜你喜欢

热点阅读