前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )

【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )

作者头像
韩曙亮
发布2023-03-29 09:41:50
4170
发布2023-03-29 09:41:50
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

一、分析 PathClassLoader 源码


PathClassLoader 是 Android 平台的类加载器 , 继承了 BaseDexClassLoader ;

代码语言:javascript
复制
public class PathClassLoader extends BaseDexClassLoader {
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }
    
    public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
        super(dexPath, null, librarySearchPath, parent);
    }
}

源码路径 : libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java

二、分析 BaseDexClassLoader 源码


BaseDexClassLoader 中的 findClass 方法 , 就是查找字节码类的核心方法 ;

BaseDexClassLoader 的 protected Class<?> findClass(String name) 是 protected 属性的 , 不能直接调用 , 需要通过反射才能调用 ;

应用调用所有的类的入口 , 就是该函数 , 所有 Java 类都是通过该类进行查找的 ;

BaseDexClassLoader 中的 findClass 方法分析 : 传入查找的类名 name 后 , 会调用 DexPathList pathList 成员的额 findClass 方法 ;

代码语言:javascript
复制
public class BaseDexClassLoader extends ClassLoader {

    /**
     * Hook for customizing how dex files loads are reported.
     *
     * This enables the framework to monitor the use of dex files. The
     * goal is to simplify the mechanism for optimizing foreign dex files and
     * enable further optimizations of secondary dex files.
     *
     * The reporting happens only when new instances of BaseDexClassLoader
     * are constructed and will be active only after this field is set with
     * {@link BaseDexClassLoader#setReporter}.
     */
    /* @NonNull */ private static volatile Reporter reporter = null;

    private final DexPathList pathList;


    public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
        // TODO We should support giving this a library search path maybe.
        super(parent);
        this.pathList = new DexPathList(this, dexFiles);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException(
                    "Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }
}

源码路径 : libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

三、分析 PathDexList 源码


应用调用类 A.java 时 , 通过 PathClassLoader 调用 , PathClassLoader 没有实际内容 , 只是继承 BaseDexClassLoader , 主要靠 BaseDexClassLoader 的 findClass 方法查找 A.class 文件 , BaseDexClassLoader 又调用 DexPathList pathList 成员的 findClass 方法 , 查找 A.class 文件 ;

当应用运行时调用到某类 A.class 时 , 会通过 PathClassLoader 加载该类 , PathClassLoader 是一个包装类 , 其中封装了 PathDexList 类 , 该类中的 Element[] dexElements 成员存放着多个 Dex 文件 ;

每个 Dex 文件中封装了多个 Class 字节码文件 ; 查找某个具体的 A.class 时 , 主要是通过 DexPathList 的 findClass 方法 , 遍历 Element[] dexElements 成员 ,

Element[] dexElements 数组中保存的就是内存中的 DEX 文件 , 如果 APP 中有 3 个 DEX 文件 , 那么该数组就有 3 个元素 ;

然后逐个遍历 获取该 element 中的 dexFile , 这是 DexFile 类型文件 ,

调用 DexFile 的 loadClassBinaryName 加载对应的 A.class 类 , 如果找到了 A.class 类 , 直接返回 ; 如果没有找到 , 则继续遍历下一个 Element[] dexElements 元素 ;

代码语言:javascript
复制
/*package*/ final class DexPathList {

    /**
     * dex/resource (class path) 元素集合.
     * 应该调用 pathElements , 但是 Facebook 应用通过反射修改 dexElements .
     */
    private final Element[] dexElements;
    
    public Class findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            DexFile dex = element.dexFile;

            if (dex != null) {
                Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
                // 注意 : 这里如果查找到想要的类 , 直接返回 , 不会去向后遍历
                if (clazz != null) {
                    return clazz;
                }
            }
        }
        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }
}

参考源码地址 : libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

四、 源码资源


源码资源 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、分析 PathClassLoader 源码
  • 二、分析 BaseDexClassLoader 源码
  • 三、分析 PathDexList 源码
  • 四、 源码资源
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档