天天看點

ART雙親委托機制雜記

1.ART雙親委托機制:
    PathClassLoader,DexClassLoader --繼承自--> BaseDexClassLoader  --繼承自--> ClasssLoader

     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 {
                            //若頂級類加載器父類是空 則調用這個方法 這個方法是又ClassLoader類提供的private方法,預設傳回null
                            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;
        }

         protected final Class<?> findLoadedClass(String name) {
                ClassLoader loader;
                if (this == BootClassLoader.getInstance())
                    loader = null;
                else
                    loader = this;
                return VMClassLoader.findLoadedClass(loader, name);
            }
          //VMClassLoader.findLoadedClass是一個native方法,其實作在art/runtime/native/lava_lang_VMClassLoader: VMClassLoader_findLoadedClass方法



    首次加載類 檢察類是否加載過,如果加載過直接傳回,由目标classLoader的父類去加載,加載成功直接傳回,
    加載失敗則再次尋找父類的父類去加載,如果目前類是BootClassLoader則調用VMClassLoader.findLoadedClass去加載,成功則傳回,失敗則由原始目标classLoader的findClass去加載

    BaseDexClassLoader -> findClass -> pathList.findClass() ->
        //DexPathList
        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;
            }


2.反射擷取類中的dexElements (MutliDex插樁)
    通過反射我們最終可以去修改DexPathList中的dexElements數組 ->   BaseDexClassLoader:pathList(DexPathList):dexElements(Elements[])
        2.1.反射擷取BaseDexClassLoader的成員變量pathList(DexPathList)
        2.2.反射擷取DexPathList的成員變量dexElements(Elements[])
        2.3.修改dexElements ()