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