XposedBridge源码中,反射字段的方法封装在de.robv.android.xposed.XposedHelpers类里面.下面来看看Xposed是如何获取和设置字段的值的

获取字段的值

获取字段的值有许多个方法,有获取基本类型字段的值的方法(getIntField,getLongField,getDoubleField...),也有获取对象类型字段的值的方法.它们的实现大同小异.我们以获取对象类型字段的值为例,来分析Xposed是如何反射获取字段对象的值.这个功能在XposedHelpers类的getObjectField方法

public static Object getObjectField(Object obj, String fieldName) {
try {
return findField(obj.getClass(), fieldName).get(obj);
} catch (IllegalAccessException e) {
// should not happen
XposedBridge.log(e);
throw new IllegalAccessError(e.getMessage());
} catch (IllegalArgumentException e) {
throw e;
}
}

getObjectField有两个参数:一个是要获取的字段的所属对象,另一个是字段的名称.

getObjectField主要调用findField方法和调用findField方法返回的对象的set方法,去看看findField方法:

public static Field findField(Class<?> clazz, String fieldName) {
String fullFieldName = clazz.getName() + '#' + fieldName; if (fieldCache.containsKey(fullFieldName)) {
Field field = fieldCache.get(fullFieldName);
if (field == null)
throw new NoSuchFieldError(fullFieldName);
return field;
} try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}

findField方法的开始,先拼接一个完整的字段名称.接下来根据完整字段名判断缓存中是否存在这个字段,如果有就从缓存中取出这个字段,就不用在查找了,这样子做可以提高反射速率.如果从缓存取出的为空值,代表这个字段之前找过了,找不到,并抛出异常.

缓存名叫fieldCache,它是一个HashMap.

private static final HashMap<String, Field> fieldCache = new HashMap<>();

如果缓存中没有这个字段呢,调用findFieldRecursiveImpl查找字段:

private static Field findFieldRecursiveImpl(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
while (true) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class))
break; try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignored) {}
}
throw e;
}
}

findFieldRecursiveImpl方法首先在传进来的Class类中查找有没有这个字段,如果有返回Field对象.如果没有,就开一个死循环从它的父类中找,如果这个类没有父类或者一直找到Object类也找不到这个方法,说明这个类真的没有要找的字段,抛出一个异常.如果在它的父类中找到了这个字段,返回Field对象.

findFieldRecursiveImpl调用结束,将会回到findField的后半段:

public static Field findField(Class<?> clazz, String fieldName) {
......
try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}

如果findFieldRecursiveImpl没有抛出异常,那么将这个字段加入缓存,并将这个字段返回.如果如果findFieldRecursiveImpl抛出异常,也放入缓存,但是放入的是空值.

findField方法结束,回到最初的getObjectField方法,调用get方法,来返回字段存储的对象值

设置字段的值

和获取字段的值的方法一样,设置字段的方法也是有许多,它们的实现也是大同小异.我们来看看其中的setObjectField方法:

public static void setObjectField(Object obj, String fieldName, Object value) {
try {
findField(obj.getClass(), fieldName).set(obj, value);
} catch (IllegalAccessException e) {
// should not happen
XposedBridge.log(e);
throw new IllegalAccessError(e.getMessage());
} catch (IllegalArgumentException e) {
throw e;
}
}

setObjectField方法和上面讲解的getObjectField几乎相同,也是通过调用findField方法得到Field类对象.不同的是,setObjectField得到Field对象后调用的是它的set方法,来对字段的值进行设置

Xposed反射字段流程分析的更多相关文章

  1. SpringBoot启动流程分析(六):IoC容器依赖注入

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. Android FART脱壳机流程分析

    本文首发于安全客 链接:https://www.anquanke.com/post/id/219094 0x1 前言 在Android平台上,程序员编写的Java代码最终将被编译成字节码在Androi ...

  3. Android7.0 Phone应用源码分析(二) phone来电流程分析

    接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有 ...

  4. ofbiz进击 。 ofbiz 退货流程(包含获取可退货项流程分析 以及 取消退货项的过程分析)

    根据订单获取可退货项流程分析 退货的时候,调用 services_return.xml 中的获取可进行退货的退货项  getReturnableItems  ,该服务调用了Java类 org.ofbi ...

  5. Solr4.8.0源码分析(5)之查询流程分析总述

    Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...

  6. PPTP协议握手流程分析

    一  PPTP概述 PPTP(Point to Point Tunneling Protocol),即点对点隧道协议.该协议是在PPP协议的基础上开发的一种新的增强型安全协议,支持多协议虚拟专用网,可 ...

  7. openstack之nova-api服务流程分析

    nova-api公布api服务没实用到一个些框架,基本都是从头写的.在不了解它时,以为它很复杂,难以掌握.花了两三天的时间把它分析一遍后,发现它本身的结构比較简单,主要难点在于对它所使用的一些类库不了 ...

  8. Netty 拆包粘包和服务启动流程分析

    Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...

  9. OA流程分析

    OA流程分析: 1. 流程定义:可视化可拖拽的流程环节设置,流程定义完成后保存在数据表中,字段有流程ID,名称,流程流转环节. 2. 画业务表单,新建业务数据表. 3. 表单数据填好后,启动流程:

随机推荐

  1. 两个对象值相同(x.equals(y)==true),但却可有不同的hashcode这句话对吗?

    1.这句话当然不对啦,请参看官方文档给出的解释! hashCode public int hashCode()返回该对象的哈希码值.支持此方法是为了提高哈希表(例如 java.util.Hashtab ...

  2. linux搭建ftp出错汇总

    重启vsftpd出现”500 OOPS: vsftpd: cannot open config file:restart” 2008-05-09 21:33 进到/etc/init.d/目录 输入: ...

  3. 监控io性能、free、ps命令、查看网络状态、Linux下抓包 使用介绍

    第7周第2次课(5月8日) 课程内容: 10.6 监控io性能 10.7 free命令10.8 ps命令10.9 查看网络状态10.10 linux下抓包扩展tcp三次握手四次挥手 http://ww ...

  4. PHP 获取服务器详细信息的原生方法

    获取系统类型及版本号:    php_uname()     (例:Windows NT PCA15130 6.1 build 7601 (Windows 7 Ultimate Edition Ser ...

  5. C# 中的委托和事件(一)

    引言 委 托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真 是太容易了,而没有 ...

  6. 每个开发人员都应该知道的11个Linux命令

    本文主要挑选出读者有必要首先学习的 11 个 Linux 命令,如果不熟悉的读者可以在虚拟机或云服务器上实操下,对于开发人员来说,能熟练掌握 Linux 做一些基本的操作是必要的! 事不宜迟,这里有 ...

  7. .Net Core使用Ocelot网关(一) -负载,限流,熔断,Header转换

    1.什么是API网关 API网关是微服务架构中的唯一入口,它提供一个单独且统一的API入口用于访问内部一个或多个API.它可以具有身份验证,监控,负载均衡,缓存,请求分片与管理,静态响应处理等.API ...

  8. python数据挖掘第二篇-爬虫

    python爬虫 urllib用法 eg1: from urllib import request data = request.urlopen(urlString).read() # data获取的 ...

  9. docker等文档

    docker strapi koa express

  10. react-native中TextInput在ios平台下不能输入中文

    目录 1. github上相关资料 2.需要满足defultValue和value属性 react-native 0.55.4版本,发现TextInput 在iOS平台上无法输入中文的问题. 1. g ...