• 安卓动态代理


    在这里插入图片描述


    https://blog.csdn.net/u011016373/article/details/82863710

    代理可以实现方法增强,也可以实现方法拦截,通过代理方法修改原方法的参数和返回值
    在这里插入图片描述

    静态代理

    自定义一个类implements实现某个接口里面的方法
    这种方式需要为每个代理写一个自定义类,而且无法拦截

    动态代理

    JVM在运行的时候动态生成一系列代理类
    就是hook方法
    先找点需要hook的对象,静态变量或单例

    注意jdk动态代理只能代理接口,所以想代理类的话需要先手写静态代理类覆盖掉原始的方法

    使用Class.forName(“模块名.包名.类名.类型名”)可以获取某个参数类型类
    比如Class.forName(“android.net.wifi.IWifiManager”);
    在这里插入图片描述
    类名.class.getDeclaredField(“变量名”);可以获取某个类里的变量
    比如
    serviceField = WifiManager.class.getDeclaredField(“mService”);
    这个mService变量的类型是IWifiManager
    可以设置下这个变量的可控性
    serviceField.setAccessible(true);

    这个IManager类型的service获取了
    但是实际的WiFi管理器是使用app上下文从系统服务里获取的
    然后使用这个IWifiManager服务变量获取app的原生wifiobj,把这个wifiobj传入自定义的操作触发器获取到自定义的触发器的代理实例
    之后使用Imanager类型的服务变量的set方法,传入获取到的现有的WiFi管理器和使用这个WiFi管理器的WiFiobj重构的WiFi管理器
    新的WiFi管理器是需要使用反射类里的代理方法重构处理的,需要传入WiFi服务变量的缓存,这个WiFi服务的新的类实例和自定义的重构的WiFi服务被触发的时候的方法才可以得到真正的WiFi控制器类

    现在要动态代理的是getHardwareAddress方法,这个方法由什么在控制呢
    这个方法在NetworkInterface。java里
    所以我们需要替代的是这个类,然后重新里面获取硬件信息的方法

    原理

    Subject subject = new RealSubject();
    ProxySubject proxy = new ProxySubject(subject);
    Subject sub = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
            subject.getClass().getInterfaces(), proxy);
    sub.operation();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class ProxySubject implements InvocationHandler{
         protected Subject subject;
        public ProxySubject(Subject subject) {
            this.subject = subject;
        }
    
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //do something before
        return method.invoke(subject, args);
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    public class RealSubject implements Subject{
        @Override
        public String operation() {
            return "operation by subject";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    public interface Subject {
        String operation();
    }
    
    • 1
    • 2
    • 3

    其优点是扩展和隐私,对外只提供一个代理访问,只有我自己可以用真正的类做操作。安卓系统中大量用到代理模式,比如获取系统的服务,App进程只能拿到服务的代理对象。
    https://blog.csdn.net/nannan1989yue/article/details/118297436

    代理两个方式
    静态代理在编译的时候已经确认自己的任务
    比如一个接口,然后一个实现这个接口的实现类

    写一个代理类是把原先的实现类定义为变量在重新的方法里做一些拦截处理后重新调用实例方法
    然后使用:接口名表示是哪个接口的实现类

    这样要写很多代理类

    所以动态代理,运行的时候才开始代理
    动态代理要配合proxy类和InvocationHanlder接口重写invoke方法来实现

    先获取类,之后获取某个参数
    之前实现的动态代理WifiManager类的时候是先获取WifiManager对应的接口IWiFiManager的,分享WiFimanager里面的getConnectionInfo方法的时候,可以看懂返回的实际是是MService.getConnectionInfo方法
    先使用app上下文获取系统WiFi服务也就是一个,之后使用servicefield获取到WiFimanager

    hook动态代理getHardwareAddress

    https://bbs.pediy.com/thread-215039.htm
    https://www.open-open.com/lib/view/open1494401599694.html
    InvocationHandler 接口和 Proxy 类
    Java 编译器编译好 Java 文件之后会在磁盘中产生 .class 文件
    .class 文件是二进制文件,内容是只有 JVM 虚拟机才能识别的机器码,JVM 虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析 .class 文件内的信息,使用相对应的 ClassLoader 类加载器生成对应的 Class 对象

    class 字节码文件是根据 JVM 虚拟机规范中规定的字节码组织规则生成的,具体的 .class 文件格式介绍可以查看博客 深入理解Java Class文件格式 和 Java 虚拟机规范

    JVM 是通过字节码的二进制信息加载类的,那么我们如果在运行期系统中,遵循 Java 编译系统组织 .class 文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据转换成对应的类,这样就可以在运行中动态生成一个我们想要的类

    Java 中有很多的框架可以在运行时根据 JVM 规范动态的生成对应的 .class 二进制字节码,比如 ASM 和 Javassist 等

    这样先获取要替代的类的一个实例
    分析一下要取代的方法
    里面先是定义了一个networkInterface变量,这个变量是使用getByName(name)方法获取的,这个方法是静态方法,需要往里面传入一个string类型的name变量,这个方法里先使用getAll获取所有的NetworkInterface[]变量,之后遍历这个变量里的所有元素,然后看看所有的NetworkInterface列表里哪个是要找的哪个name的networkInterface实例
    getHardwareAddress获取的是某个name的networkInterface实例里的Mac地址,没有这个实例会报错,实际上这个类的构造方法
    获取接口
    想要取得NetworkInterface对象,就必须要通过NetworkInterface类的public staticEnumeration getNetworkInterfaces()方法,该方法的返回值是泛型Enumeration,作用是返回此机器上的所有接口
    https://blog.csdn.net/cold___play/article/details/106600394
    在这里插入图片描述

    获取实例
    NetworkInterface同样没有提供公开的构造函数,而是提供一些静态方法来获取实例
    static NetworkInterface getByInetAddress(InetAddress addr)搜索绑定了制定IP地址的网络接口
    static NetworkInterface getByName(String name)搜索具有指定名称的网络接口
    static Enumeration getNetworkInterfaces()返回本机所有网络接口的一个枚举实例

    {'methodName':'getData','lineNumber':488,'className':'libcore.util.Janus','fileName':'Janus.java','level':0},{'methodName':'getHardwareAddress','lineNumber':565,'className':'java.net.NetworkInterface','fileName':'NetworkInterface.java','level':0}
    
    • 1

    getHardwareAddress()里使用了getByName(name),这个方法又使用了getAll(),里面定义了StructIfaddrs[] ifaddrs;
    实际上应该代理这个方法
    getHardwareAdress里返回使用getByName获取到的NetworkInterface变量的hardwareAddr
    所以这个方法最终调用的是getAll方法获取所有的Networkinterface变量,这个是一个private方法
    NetworkInterface ni = new NetworkInterface(name, index, null);

    private static NetworkInterface[] getAll()
    StructIfaddrs
    StructIfaddrs[] ifaddrs;
    ifaddrs = Libcore.os.getifaddrs()
    https://www.thinbug.com/q/35193646
    getAll方法必须调用的变量是StructIfaddrs[] ifaddrs,这是一个field变量
    libcore.io.Libcore

    @UnsupportedAppUsage

    https://blog.csdn.net/Mr_theSun/article/details/89607608

    动态代理里代理对象的生成过程

    https://www.open-open.com/lib/view/open1494401599694.html
    先获取原型对象的所有的接口列表
    确定一下要生成的代理类的类名
    根据要实现的接口信息在代码里动态创建代理对象类的字节码
    把对应的字节码转换成对应的class对象
    创建一个invokecat戳你Handler的实例对象用于处理代理角色的所有方法调用,用创建的实例对象实例化一个代理角色

    真的类实现对应的接口,代理类实现的是InvocationHandler接口,里面重新一个invoke方法,这个方法里

    新建一个原型对象实例,然后新建一个代理对象实例(实例化的时候传入原型类实例),然后使用代理类

    这个代理的对象需要新建一个代理实例,往代理实例里传入要替代的类的缓存,类的实例和替代料,然后执行代理类的opration方法就开始在运行过程替代所有方法了
    当然也可以使用一些set方法

    getHardwareAddress怎么获取Mac地址

    https://blog.csdn.net/qq_43080741/article/details/124237926
    产品地址和Mac地址都是在计算机里用二进制表示的,ip地址是32位。mac是48位

    InetAddress类和NetworkInterface类

    https://blog.csdn.net/lizefeng1998/article/details/121088480
    java.net.InetAddress类是Java对IP地址的高层表示。一般来说,它包括一个主机名和一个IP地址

    NetworkInterface类表示一个本地的IP地址,这可以是一个物理接口,如额外的以太网卡(常见于防火墙和路由器),也可以是一个虚拟接口,与机器的其他IP地址绑定到用一个物理硬件

    NetworkInterface有两个构造自身实例的静态工厂方法

    public static NetworkInterface getByName(String name) 表示有指定名字的网络接口
    public static NetworkInterface getByInetAddress(InetAddress address) 表示与指定IP地址绑定的网络接口。
    
    • 1
    • 2

    NetworkInterface还提供了一个getNetworkInterfaces()函数,该方法会返回一个java.util.Enumeration,他会列出本地主机上所有的网络接口

    ,NetworkInterface.getHardwareAddress()但这是针对API级别9和更高版本的 该API的level为9,只有android 2.3以上才有该接口

    https://blog.chinaoc.com.cn/p/1236387.html

    android获取有线网的Mac地址

    https://blog.csdn.net/nihenbuhao/article/details/53150027

    			InetAddress ip = getLocalInetAddress();
    			byte[] b = NetworkInterface.getByInetAddress(ip)
    					.getHardwareAddress();
    
    • 1
    • 2
    • 3

    https://blog.csdn.net/nihenbuhao/article/details/53150027

    动态代理核心原理

        @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {....}
    ————————————————
    版权声明:本文为CSDN博主「Android_HQK」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_30382601/article/details/118450742
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。

    JAVA基础——反射,反射详细内容介绍,类加载,反射获得有参无参构造,获取方法,获取属性,越过泛型检查,动态代理

    当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化

    jdk只能代理接口
    https://wenku.baidu.com/view/5d56068b2b4ac850ad02de80d4d8d15abe2300ea.html

    libcore.io.Libcore动态代理

    https://blog.csdn.net/lzz137/article/details/116095873
    android OS是一个io回调,是想动态代理
    android.system.StructIfaddrs
    Libcore.os.getifaddrs()

    libcore回调机制
    通过动态代理AndroidOs,调用Os.compareAndSetDefault进行替换
    看看里面的os赋值
    class静态初始化的时候赋值一次,compareAndSetOs函数调用的时候赋值一次

    安卓系统调用的是compareAndSetOs函数,设置了os回调,这个是调用了compareAndSetOs函数
    ActivityThread.java调用compareAndSetOs函数

    MzPush SDK魅族推送导致隐私不合格

    http://open.res.flyme.cn/fileserver/upload/file/202109/7bf101e2843642709c7a11f4b57861cd.pdf

    删除无关权限–图片,媒体内容和文件

    实际上是

    在这里插入图片描述

  • 相关阅读:
    Android 获取安装的app
    自学 6 个月 Java 找到了一份 15K 的工作,师弟的方式值得推荐给大家
    保存文件时电脑提示:你没有权限在此位置中保存文件。请与管理员联系以获得相应权限。
    GEE错误——利用selector选择指定的属性列表进行表格的导出(相关错误解析)
    Java基于微信小程序的自习室系统
    promtail multiline 堆栈日志处理
    处理非线性分类的 SVM一种新方法(Matlab代码实现)
    「UG/NX」Block UI 指定坐标SpecifyCSYS
    [Machine learning][Part4] 线性回归模型技巧
    苹果系统H5下拉加载事件重复触发(react hooks)
  • 原文地址:https://blog.csdn.net/weixin_46045444/article/details/125239867