ClassLoader 之 Element、DexFile 类

1. 他妈的坑

写了一大半,一个空格操作,让我刚才写的全部清空了,还没用备份保存。他奶奶的!!!!!

2. Element 类

这个类主要包含两个变量:

564        private final File path;
566        private final DexFile dexFile;

path 是 dex 的路径,dexFile 是 DexFile 对象。

刚才莫名消失的,再叙述一遍: BaseDexClassLoader 类调用 pathList 的方法,这个 pathList 就是 DexPathFile 对象,这个 DexPathFile 类包含了一个变量 dexElements 对象,而 dexElements 就是 Element 对象数组;遍历这个数组,然后在获取了 dexFile 元素后,去调用 findClass 方法,这里就跳入了 DexFile 类。


559    /*package*/ static class Element {
560        /**
561         * A file denoting a zip file (in case of a resource jar or a dex jar), or a directory
562         * (only when dexFile is null).
563         */
564        private final File path;
565
566        private final DexFile dexFile;
567
568        private ClassPathURLStreamHandler urlHandler;
569        private boolean initialized;
575        public Element(DexFile dexFile, File dexZipPath) {
576            this.dexFile = dexFile;
577            this.path = dexZipPath;
578        }
579
580        public Element(DexFile dexFile) {
581            this.dexFile = dexFile;
582            this.path = null;
583        }
584
585        public Element(File path) {
586          this.path = path;
587          this.dexFile = null;
588        }
589
598        @Deprecated
599        public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) {
600            System.err.println("Warning: Using deprecated Element constructor. Do not use internal"
601                    + " APIs, this constructor will be removed in the future.");
602            if (dir != null && (zip != null || dexFile != null)) {
603                throw new IllegalArgumentException("Using dir and zip|dexFile no longer"
604                        + " supported.");
605            }
606            if (isDirectory && (zip != null || dexFile != null)) {
607                throw new IllegalArgumentException("Unsupported argument combination.");
608            }
609            if (dir != null) {
610                this.path = dir;
611                this.dexFile = null;
612            } else {
613                this.path = zip;
614                this.dexFile = dexFile;
615            }
616        }
621        private String getDexPath() {
622            if (path != null) {
623                return path.isDirectory() ? null : path.getAbsolutePath();
624            } else if (dexFile != null) {
625                // DexFile.getName() returns the path of the dex file.
626                return dexFile.getName();
627            }
628            return null;
629        }
630
631        @Override
632        public String toString() {
633            if (dexFile == null) {
634              return (path.isDirectory() ? "directory \"" : "zip file \"") + path + "\"";
635            } else {
636              if (path == null) {
637                return "dex file \"" + dexFile + "\"";
638              } else {
639                return "zip file \"" + path + "\"";
640              }
641            }
642        }
643
644        public synchronized void maybeInit() {
645            if (initialized) {
646                return;
647            }
648
649            if (path == null || path.isDirectory()) {
650                initialized = true;
651                return;
652            }
653
654            try {
655                urlHandler = new ClassPathURLStreamHandler(path.getPath());
656            } catch (IOException ioe) {
657                /*
658                 * Note: ZipException (a subclass of IOException)
659                 * might get thrown by the ZipFile constructor
660                 * (e.g. if the file isn't actually a zip/jar
661                 * file).
662                 */
663                System.logE("Unable to open zip file: " + path, ioe);
664                urlHandler = null;
665            }
666
667            // Mark this element as initialized only after we've successfully created
668            // the associated ClassPathURLStreamHandler. That way, we won't leave this
669            // element in an inconsistent state if an exception is thrown during initialization.
670            //
671            // See b/35633614.
672            initialized = true;
673        }
674
675        public Class findClass(String name, ClassLoader definingContext,
676                List suppressed) {
677            return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
678                    : null;
679        }
680
681        public URL findResource(String name) {
682            maybeInit();
683
684            if (urlHandler != null) {
685              return urlHandler.getEntryUrlOrNull(name);
686            }
687
688            // We support directories so we can run tests and/or legacy code
689            // that uses Class.getResource.
690            if (path != null && path.isDirectory()) {
691                File resourceFile = new File(path, name);
692                if (resourceFile.exists()) {
693                    try {
694                        return resourceFile.toURI().toURL();
695                    } catch (MalformedURLException ex) {
696                        throw new RuntimeException(ex);
697                    }
698                }
699            }
700
701            return null;
702        }
703    }

3. DexFile 类

这个类有好几个 native 方法:

383    private static native boolean closeDexFile(Object cookie);
384    private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
385                                                  DexFile dexFile)
386            throws ClassNotFoundException, NoClassDefFoundError;
387    private static native String[] getClassNameList(Object cookie);
388    private static native boolean isBackedByOatFile(Object cookie);
393    private static native Object openDexFileNative(String sourceName, String outputName, int flags,
394            ClassLoader loader, DexPathList.Element[] elements);

这个类主要的变量有三个:

41@Deprecated
42public final class DexFile {
43  /**
44   * If close is called, mCookie becomes null but the internal cookie is preserved if the close
45   * failed so that we can free resources in the finalizer.
46   */
47    private Object mCookie;
48    private Object mInternalCookie;
49    private final String mFileName;
50}

mCookie 是 openDexFile(openDexFileNative) 方法返回
mInternalCookie = mCookie,两个相等
mFileName 就是 apk 的具体路径。

mCookie 的生成方法:

99    DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements) throws IOException {
100        mCookie = openDexFile(fileName, null, 0, loader, elements);
101        mInternalCookie = mCookie;
102        mFileName = fileName;
103        //System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName);
104    }
105



106    DexFile(ByteBuffer buf) throws IOException {
107        mCookie = openInMemoryDexFile(buf);
108        mInternalCookie = mCookie;
109        mFileName = null;
110    }



127    private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
128            DexPathList.Element[] elements) throws IOException {
129        if (outputName != null) {
130            try {
131                String parent = new File(outputName).getParent();
132                if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
133                    throw new IllegalArgumentException("Optimized data directory " + parent
134                            + " is not owned by the current user. Shared storage cannot protect"
135                            + " your application from code injection attacks.");
136                }
137            } catch (ErrnoException ignored) {
138                // assume we'll fail with a more contextual error later
139            }
140        }
141
142        mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
143        mInternalCookie = mCookie;
144        mFileName = sourceName;
145        //System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
146    }

openDexFile 方法:
350    private static Object openDexFile(String sourceName, String outputName, int flags,
351            ClassLoader loader, DexPathList.Element[] elements) throws IOException {
352        // Use absolute paths to enable the use of relative paths when testing on host.
353        return openDexFileNative(new File(sourceName).getAbsolutePath(),
354                                 (outputName == null)
355                                     ? null
356                                     : new File(outputName).getAbsolutePath(),
357                                 flags,
358                                 loader,
359                                 elements);
360    }

看到最后跳到了 native 方法。

获取 DexFile 对象:

158    @Deprecated
159    static public DexFile loadDex(String sourcePathName, String outputPathName,
160        int flags) throws IOException {
169        return loadDex(sourcePathName, outputPathName, flags, null, null);
170    }

调到这里:
191    static DexFile loadDex(String sourcePathName, String outputPathName,
192        int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException {
201        return new DexFile(sourcePathName, outputPathName, flags, loader, elements);
202    }

这里看到只需要三个参数:dex 路径、odex 路径、flags。odex 可以自定义,要指向内部目录。
这里最终也会调用 openDexFile 方法并返回 mCookie

你可能感兴趣的:(ClassLoader 之 Element、DexFile 类)