美文网首页
Classloader类加载

Classloader类加载

作者: 赛非斯 | 来源:发表于2022-01-16 18:41 被阅读0次
  • 反射的两种方式
    1、Classloder.loaderClass(String name)
    2、Class.forName(String name)
    两者最大的区别是
    Class.forName得到的class是已经初始化完成的
    Classloder.loaderClass得到的class是还没有初始化的
    ActivityThread.java 中有一段
@UnsupportedAppUsage
    private void handleBindApplication(AppBindData data) {
....
..
   // The test context's op package name == the target app's op package name, because
            // the app ops manager checks the op package name against the real calling UID,
            // which is what the target package name is associated with.
            final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
                    appContext.getOpPackageName());

            try {
                final ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            } catch (Exception e) {
                throw new RuntimeException(
                    "Unable to instantiate instrumentation "
                    + data.instrumentationName + ": " + e.toString(), e);
            }
}

调用了classloader的loadclass方法初始化mInstrumentation ,这里 parent.loadClass 就是类加载的双亲委托机制:首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
好处是:避免重复加载 + 避免核心类篡改

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    c = findClass(name);
                }
            }
            return c;
    }
  • 跟踪代码可以知道instrContext.getClassLoader(); 得到的classloader是PathClassLoader.java
    就是调用PathClassLoader 的 findClass(name)
    而public class PathClassLoader extends BaseDexClassLoader 且没有重写父类的findClass方法,所以调用
    BaseDexClassLoader 的 findClass
    代码路径:dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
protected Class<?> findClass(String name) throws ClassNotFoundException {
        // First, check whether the class is present in our shared libraries.
        if (sharedLibraryLoaders != null) {
            for (ClassLoader loader : sharedLibraryLoaders) {
                try {
                    return loader.loadClass(name);
                } catch (ClassNotFoundException ignored) {
                }
            }
        }
        // Check whether the class in question is present in the dexPath that
        // this classloader operates on.
        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;
    }

关键一句在 Class c = pathList.findClass(name, suppressedExceptions);
pathList 就是 DexPathList
dalvik/src/main/java/dalvik/system/DexPathList.java,从下面代码看是从dexElements去找

@UnsupportedAppUsage
    private Element[] dexElements;
DexPathList(ClassLoader definingContext, String dexPath,
            String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
   this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
                                           suppressedExceptions, definingContext, isTrusted);
}
    public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }

        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }
  • 从上面的代码看出dexElements是个关键,findClass就是从dexElements去找 找到就返回,也就是谁在前面就先被找到,后面的就不找了!!! 这里就涉及到了一个技术 热修复

  • 热修复 目前是比较成熟的技术了
    1、获取当前用的pathclassloader
    2、通过pathclassloader 反射拿 private Element[] dexElements;
    3、将dex补丁包转换成Elements_new 数组(反射makeDexElements)
    4、将Elements_new 插入到dexElements数组前面 更新 dexElements

相关文章

网友评论

      本文标题:Classloader类加载

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