• [原创]Andorid DexClassLoader的创建过程解析(基于5.0)


    做Android插件框架时,经常会用到dex的动态加载,就要直接或间接的使用DexClassLoader,在new DexClassLoader的时候Android系统做了很多工作,下面我们详细分析一下:

    public class DexClassLoader extends BaseDexClassLoader {
        public DexClassLoader(String dexPath, String optimizedDirectory,
                String libraryPath, ClassLoader parent) {
            super(dexPath, new File(optimizedDirectory), libraryPath, parent);
        }
    }
    public class BaseDexClassLoader extends ClassLoader {
        private final DexPathList pathList;
    
        public BaseDexClassLoader(String dexPath, File optimizedDirectory,
                String libraryPath, ClassLoader parent) {
            super(parent);
            this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
        }
      ......
    @Override
    protected URL findResource(String name) { return pathList.findResource(name); } @Override protected Enumeration<URL> findResources(String name) { return pathList.findResources(name); } @Override public String findLibrary(String name) { return pathList.findLibrary(name); }
      ......
    }

    看到关键步骤了,设置完parent的ClassLoader之后,创建了DexPathList对象pathList,可以看到,很多操作都是直接委托给pathList的,我们看下这个对象里面做了什么。

    这里涉及到两个目录,optimizedDirectory和libraryPath,我们先从简单的入手,先看看DexPathList是如何处理libraryPath

    final class DexPathList {
        private static final String DEX_SUFFIX = ".dex";/** List of native library directories. */
        private final File[] nativeLibraryDirectories;public DexPathList(ClassLoader definingContext, String dexPath,
                String libraryPath, File optimizedDirectory) {
    
            ......
    
            this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
        }
    
        private static File[] splitLibraryPath(String path) {
            // Native libraries may exist in both the system and
            // application library paths, and we use this search order:
            //
            //   1. this class loader's library path for application libraries
            //   2. the VM's library path from the system property for system libraries
            //
            // This order was reversed prior to Gingerbread; see http://b/2933456.
            ArrayList<File> result = splitPaths(path, System.getProperty("java.library.path"), true);
            return result.toArray(new File[result.size()]);
        }
    
        private static ArrayList<File> splitPaths(String path1, String path2,
                boolean wantDirectories) {
            ArrayList<File> result = new ArrayList<File>();
    
            splitAndAdd(path1, wantDirectories, result);
            splitAndAdd(path2, wantDirectories, result);
            return result;
        }
    
        private static void splitAndAdd(String searchPath, boolean directoriesOnly,
                ArrayList<File> resultList) {
            if (searchPath == null) {
                return;
            }
            for (String path : searchPath.split(":")) {
                try {
                    StructStat sb = Libcore.os.stat(path);
                    if (!directoriesOnly || S_ISDIR(sb.st_mode)) {
                        resultList.add(new File(path));
                    }
                } catch (ErrnoException ignored) {
                }
            }
        }
    
    }

    从上面代码可以看到,系统会将用户传进的目录和默认的系统lib目录(System.getProperty("java.library.path"))通过“:”分割后,存进一个File数组中。

    这就是DexClassLoader对libraryPath的所有操作,所以可以看到,和optimizePath不一样,并没有对so文件解压。

    接下来,我们看看DexClassLoader初始化时候对optimizePath做了什么

     还是从DexPathList入手

    final class DexPathList {
    
        /** class definition context */
        private final ClassLoader definingContext;
    
        private final Element[] dexElements;
    
        private final IOException[] dexElementsSuppressedExceptions;
    
        public DexPathList(ClassLoader definingContext, String dexPath,
                String libraryPath, File optimizedDirectory) {
            ......
            //check optimized directory
            ......
    
            this.definingContext = definingContext;
            ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
            this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
                                               suppressedExceptions);
            //save Exceptions
            ......
            this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
        }
    
        private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
                                                 ArrayList<IOException> suppressedExceptions) {
            ......
    
                    if (name.endsWith(DEX_SUFFIX)) {
                        // Raw dex file (not inside a zip/jar).
                        try {
                            dex = loadDexFile(file, optimizedDirectory);
                        } catch (IOException ex) {
                            System.logE("Unable to load dex file: " + file, ex);
                        }
                    } else {
                        zip = file;
                        try {
                            dex = loadDexFile(file, optimizedDirectory);
                        } catch (IOException suppressed) {
                            suppressedExceptions.add(suppressed);
                        }
                    }
               ......
    
        private static DexFile loadDexFile(File file, File optimizedDirectory)
                throws IOException {
            if (optimizedDirectory == null) {
                return new DexFile(file);
            } else {
                String optimizedPath = optimizedPathFor(file, optimizedDirectory);
                return DexFile.loadDex(file.getPath(), optimizedPath, 0);
            }
        }
    
    }    

    除了一些目录检查,异常处理,从构造函数一步一步调用到了loadDexFile,从而进入到DexFile中,我们继续。

    public final class DexFile {
    
        public DexFile(File file) throws IOException {
            this(file.getPath());
        }
    
        public DexFile(String fileName) throws IOException {
            mCookie = openDexFile(fileName, null, 0);
            mFileName = fileName;
            guard.open("close");
            //System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName);
        }
    
        private DexFile(String sourceName, String outputName, int flags) throws IOException {
            if (outputName != null) {
                try {
                    String parent = new File(outputName).getParent();
                    if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
                        throw new IllegalArgumentException("Optimized data directory " + parent
                                + " is not owned by the current user. Shared storage cannot protect"
                                + " your application from code injection attacks.");
                    }
                } catch (ErrnoException ignored) {
                    // assume we'll fail with a more contextual error later
                }
            }
    
            mCookie = openDexFile(sourceName, outputName, flags);
            mFileName = sourceName;
            guard.open("close");
            //System.out.println("DEX FILE cookie is " + mCookie + " sourceName=" + sourceName + " outputName=" + outputName);
        }
    
        static public DexFile loadDex(String sourcePathName, String outputPathName,
            int flags) throws IOException {
            return new DexFile(sourcePathName, outputPathName, flags);
        }
    
        private static long openDexFile(String sourceName, String outputName, int flags) throws IOException {
            // Use absolute paths to enable the use of relative paths when testing on host.
            return openDexFileNative(new File(sourceName).getAbsolutePath(),
                                     (outputName == null) ? null : new File(outputName).getAbsolutePath(),
                                     flags);
        }
    }

    可以看到,最终走到openDexFileNative这个native方法中,这个方法的native实现在art/runtime/native/dalvik_system_DexFile.cc中,看代码:

    static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
      ......
      bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
                                                 dex_files.get());
      ......
    }

    方法OpenDexFilesFromOat的实现在art/runtime/class_linker.cc中,这个方法太长,我先把全部内容贴上来,

      1 bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
      2                                       std::vector<std::string>* error_msgs,
      3                                       std::vector<std::unique_ptr<const DexFile>>* dex_files) {
      4   // 1) Check whether we have an open oat file.
      5   // This requires a dex checksum, use the "primary" one.
      6   uint32_t dex_location_checksum;
      7   uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
      8   bool have_checksum = true;
      9   std::string checksum_error_msg;
     10   if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
     11     // This happens for pre-opted files since the corresponding dex files are no longer on disk.
     12     dex_location_checksum_pointer = nullptr;
     13     have_checksum = false;
     14   }
     15 
     16   bool needs_registering = false;
     17 
     18   const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location,
     19                                                                  dex_location_checksum_pointer);
     20   std::unique_ptr<const OatFile> open_oat_file(
     21       oat_dex_file != nullptr ? oat_dex_file->GetOatFile() : nullptr);
     22 
     23   // 2) If we do not have an open one, maybe there's one on disk already.
     24 
     25   // In case the oat file is not open, we play a locking game here so
     26   // that if two different processes race to load and register or generate
     27   // (or worse, one tries to open a partial generated file) we will be okay.
     28   // This is actually common with apps that use DexClassLoader to work
     29   // around the dex method reference limit and that have a background
     30   // service running in a separate process.
     31   ScopedFlock scoped_flock;
     32 
     33   if (open_oat_file.get() == nullptr) {
     34     if (oat_location != nullptr) {
     35       // Can only do this if we have a checksum, else error.
     36       if (!have_checksum) {
     37         error_msgs->push_back(checksum_error_msg);
     38         return false;
     39       }
     40 
     41       std::string error_msg;
     42 
     43       // We are loading or creating one in the future. Time to set up the file lock.
     44       if (!scoped_flock.Init(oat_location, &error_msg)) {
     45         error_msgs->push_back(error_msg);
     46         return false;
     47       }
     48 
     49       // TODO Caller specifically asks for this oat_location. We should honor it. Probably?
     50       open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,
     51                                                              oat_location, &error_msg));
     52 
     53       if (open_oat_file.get() == nullptr) {
     54         std::string compound_msg = StringPrintf("Failed to find dex file '%s' in oat location '%s': %s",
     55                                                 dex_location, oat_location, error_msg.c_str());
     56         VLOG(class_linker) << compound_msg;
     57         error_msgs->push_back(compound_msg);
     58       }
     59     } else {
     60       // TODO: What to lock here?
     61       bool obsolete_file_cleanup_failed;
     62       open_oat_file.reset(FindOatFileContainingDexFileFromDexLocation(dex_location,
     63                                                                       dex_location_checksum_pointer,
     64                                                                       kRuntimeISA, error_msgs,
     65                                                                       &obsolete_file_cleanup_failed));
     66       // There's no point in going forward and eventually try to regenerate the
     67       // file if we couldn't remove the obsolete one. Mostly likely we will fail
     68       // with the same error when trying to write the new file.
     69       // TODO: should we maybe do this only when we get permission issues? (i.e. EACCESS).
     70       if (obsolete_file_cleanup_failed) {
     71         return false;
     72       }
     73     }
     74     needs_registering = true;
     75   }
     76 
     77   // 3) If we have an oat file, check all contained multidex files for our dex_location.
     78   // Note: LoadMultiDexFilesFromOatFile will check for nullptr in the first argument.
     79   bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
     80                                               dex_location_checksum_pointer,
     81                                               false, error_msgs, dex_files);
     82   if (success) {
     83     const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
     84     if (needs_registering) {
     85       // We opened the oat file, so we must register it.
     86       RegisterOatFile(oat_file);
     87     }
     88     // If the file isn't executable we failed patchoat but did manage to get the dex files.
     89     return oat_file->IsExecutable();
     90   } else {
     91     if (needs_registering) {
     92       // We opened it, delete it.
     93       open_oat_file.reset();
     94     } else {
     95       open_oat_file.release();  // Do not delete open oat files.
     96     }
     97   }
     98 
     99   // 4) If it's not the case (either no oat file or mismatches), regenerate and load.
    100 
    101   // Need a checksum, fail else.
    102   if (!have_checksum) {
    103     error_msgs->push_back(checksum_error_msg);
    104     return false;
    105   }
    106 
    107   // Look in cache location if no oat_location is given.
    108   std::string cache_location;
    109   if (oat_location == nullptr) {
    110     // Use the dalvik cache.
    111     const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
    112     cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str());
    113     oat_location = cache_location.c_str();
    114   }
    115 
    116   bool has_flock = true;
    117   // Definitely need to lock now.
    118   if (!scoped_flock.HasFile()) {
    119     std::string error_msg;
    120     if (!scoped_flock.Init(oat_location, &error_msg)) {
    121       error_msgs->push_back(error_msg);
    122       has_flock = false;
    123     }
    124   }
    125 
    126   if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
    127     // Create the oat file.
    128     open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
    129                                                     oat_location, error_msgs));
    130   }
    131 
    132   // Failed, bail.
    133   if (open_oat_file.get() == nullptr) {
    134     std::string error_msg;
    135     // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.
    136     DexFile::Open(dex_location, dex_location, &error_msg, dex_files);
    137     error_msgs->push_back(error_msg);
    138     return false;
    139   }
    140 
    141   // Try to load again, but stronger checks.
    142   success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
    143                                          dex_location_checksum_pointer,
    144                                          true, error_msgs, dex_files);
    145   if (success) {
    146     RegisterOatFile(open_oat_file.release());
    147     return true;
    148   } else {
    149     return false;
    150   }
    151 }
    class_linker.cc的方法ClassLinker::OpenDexFilesFromOat

    我们按步骤分析,首先会先获取这个dex文件的Checksum值:

      if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
        // This happens for pre-opted files since the corresponding dex files are no longer on disk.
        dex_location_checksum_pointer = nullptr;
        have_checksum = false;
      }

    这个checksum的值存放在dex_location_checksum_pointer指向的地址,然后通过这个dex_location和checksum查找oat文件是否已经生成,并且加载到内存,

      const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location, dex_location_checksum_pointer);

    进入FindOpenedOatDexFile()函数,

    const OatFile::OatDexFile* ClassLinker::FindOpenedOatDexFile(const char* oat_location,
                                                                 const char* dex_location,
                                                                 const uint32_t* dex_location_checksum) {
      ReaderMutexLock mu(Thread::Current(), dex_lock_);
      for (const OatFile* oat_file : oat_files_) {
        DCHECK(oat_file != nullptr);
    
        if (oat_location != nullptr) {
          if (oat_file->GetLocation() != oat_location) {
            continue;
          }
        }
    
        const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
                                                                          dex_location_checksum,
                                                                          false);
        if (oat_dex_file != nullptr) {
          return oat_dex_file;
        }
      }
      return nullptr;
    }

    从代码看出,先根据oat的文件路径,查找内存里是否加载了同路径的oat文件,有的话执行oat_file->GetOatDexFile(),

     1 const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
     2                                                   const uint32_t* dex_location_checksum,
     3                                                   bool warn_if_not_found) const {
     4   // NOTE: We assume here that the canonical location for a given dex_location never
     5   // changes. If it does (i.e. some symlink used by the filename changes) we may return
     6   // an incorrect OatDexFile. As long as we have a checksum to check, we shall return
     7   // an identical file or fail; otherwise we may see some unpredictable failures.
     8 
     9   // TODO: Additional analysis of usage patterns to see if this can be simplified
    10   // without any performance loss, for example by not doing the first lock-free lookup.
    11 
    12   const OatFile::OatDexFile* oat_dex_file = nullptr;
    13   StringPiece key(dex_location);
    14   // Try to find the key cheaply in the oat_dex_files_ map which holds dex locations
    15   // directly mentioned in the oat file and doesn't require locking.
    16   auto primary_it = oat_dex_files_.find(key);
    17   if (primary_it != oat_dex_files_.end()) {
    18     oat_dex_file = primary_it->second;
    19     DCHECK(oat_dex_file != nullptr);
    20   } else {
    21     // This dex_location is not one of the dex locations directly mentioned in the
    22     // oat file. The correct lookup is via the canonical location but first see in
    23     // the secondary_oat_dex_files_ whether we've looked up this location before.
    24     MutexLock mu(Thread::Current(), secondary_lookup_lock_);
    25     auto secondary_lb = secondary_oat_dex_files_.lower_bound(key);
    26     if (secondary_lb != secondary_oat_dex_files_.end() && key == secondary_lb->first) {
    27       oat_dex_file = secondary_lb->second;  // May be nullptr.
    28     } else {
    29       // We haven't seen this dex_location before, we must check the canonical location.
    30       std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
    31       if (dex_canonical_location != dex_location) {
    32         StringPiece canonical_key(dex_canonical_location);
    33         auto canonical_it = oat_dex_files_.find(canonical_key);
    34         if (canonical_it != oat_dex_files_.end()) {
    35           oat_dex_file = canonical_it->second;
    36         }  // else keep nullptr.
    37       }  // else keep nullptr.
    38 
    39       // Copy the key to the string_cache_ and store the result in secondary map.
    40       string_cache_.emplace_back(key.data(), key.length());
    41       StringPiece key_copy(string_cache_.back());
    42       secondary_oat_dex_files_.PutBefore(secondary_lb, key_copy, oat_dex_file);
    43     }
    44   }
    45   if (oat_dex_file != nullptr &&
    46       (dex_location_checksum == nullptr ||
    47        oat_dex_file->GetDexFileLocationChecksum() == *dex_location_checksum)) {
    48     return oat_dex_file;
    49   }
    50 
    51   if (warn_if_not_found) {
    52     std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
    53     std::string checksum("<unspecified>");
    54     if (dex_location_checksum != NULL) {
    55       checksum = StringPrintf("0x%08x", *dex_location_checksum);
    56     }
    57     LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_location
    58                  << " ( canonical path " << dex_canonical_location << ")"
    59                  << " with checksum " << checksum << " in OatFile " << GetLocation();
    60     if (kIsDebugBuild) {
    61       for (const OatDexFile* odf : oat_dex_files_storage_) {
    62         LOG(WARNING) << "OatFile " << GetLocation()
    63                      << " contains OatDexFile " << odf->GetDexFileLocation()
    64                      << " (canonical path " << odf->GetCanonicalDexFileLocation() << ")"
    65                      << " with checksum 0x" << std::hex << odf->GetDexFileLocationChecksum();
    66       }
    67     }
    68   }
    69 
    70   return NULL;
    71 }
    oat_file.cc的OatFile::GetOatDexFile函数

    简单说一下GetOatDexFile函数做了什么,系统每次成功生成oat后,都会将dex文件的路径(注意这里是dex文件,不是oat文件)和对应的OatDexFile对象以key/value的形式保存到oat_dex_files_中,在GetOatDexFile函数中,会根据key从oat_dex_files_中查找是否有已加载到内存的oat对象。(这里有两点注意,第一,缓存的key值是原dex或apk的路径,不是oat的;第二,之所以一个oat对象会用一个map做缓存,是因为会有multidex的情况存在。)

    首次运行,内存中没有已打开的oat对象,从磁盘查找,

          open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,
                                                                 oat_location, &error_msg));
    
          if (open_oat_file.get() == nullptr) {
            std::string compound_msg = StringPrintf("Failed to find dex file '%s' in oat location '%s': %s",
                                                    dex_location, oat_location, error_msg.c_str());
            VLOG(class_linker) << compound_msg;
            error_msgs->push_back(compound_msg);
          }

    FindOatFileInOatLocationForDexFile()函数会尝试打开目标oat文件,并对其checksum,oat_offset,patch_delta做校验,如果oat文件存在且内容正确,则

      bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
                                                  dex_location_checksum_pointer,
                                                  false, error_msgs, dex_files);
      if (success) {
        const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
        if (needs_registering) {
          // We opened the oat file, so we must register it.
          RegisterOatFile(oat_file);
        }
        // If the file isn't executable we failed patchoat but did manage to get the dex files.
        return oat_file->IsExecutable();
      }

    LoadMultiDexFilesFromOatFile()是将多个dex文件(例如classes1.dex,classes2.dex)映射成DexFile对象,并添加到一个vector数据结构dex_files中,之后调用RegisterOatFile()函数将内存中的oat对象注册到oat_files_中,然后整个流程就跑完了。

    如果oat文件不存在,或者文件不匹配,则重新创建dex的oat文件,并加载,

     // Look in cache location if no oat_location is given.
      std::string cache_location;
      if (oat_location == nullptr) {
        // Use the dalvik cache.
       // GetDalvikCacheOrDie()函数在art/runtime/utils.cc中
         // 这句意味着如果没有指定oat的存放目录,则使用类似/data/dalvik-cache目录
        const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
        cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str());
        oat_location = cache_location.c_str();
      }
    
      // 对文件上锁
      bool has_flock = true;
      // Definitely need to lock now.
      if (!scoped_flock.HasFile()) {
        std::string error_msg;
        if (!scoped_flock.Init(oat_location, &error_msg)) {
          error_msgs->push_back(error_msg);
          has_flock = false;
        }
      }
    
      if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
        // Create the oat file.
        // 如果dex2oat工具可用,则生成oat文件
        open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
                                                        oat_location, error_msgs));
      }

    由于代码比较简单,直接写在注释里了,接下来看下oat是怎么生成的,也就是CreateOatFileForDexLocation()函数做了什么,

    const OatFile* ClassLinker::CreateOatFileForDexLocation(const char* dex_location,
                                                            int fd, const char* oat_location,
                                                            std::vector<std::string>* error_msgs) {
      std::string error_msg;
      if (!GenerateOatFile(dex_location, fd, oat_location, &error_msg)) {
        CHECK(!error_msg.empty());
        error_msgs->push_back(error_msg);
        return nullptr;
      }
      ......
    
      return oat_file.release();
    }

    真正生成oat是在GenerateOatFile()函数中,

     1 bool ClassLinker::GenerateOatFile(const char* dex_filename,
     2                                   int oat_fd,
     3                                   const char* oat_cache_filename,
     4                                   std::string* error_msg) {
     5   Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
     6   std::string dex2oat(Runtime::Current()->GetCompilerExecutable());
     7 
     8   gc::Heap* heap = Runtime::Current()->GetHeap();
     9   std::string boot_image_option("--boot-image=");
    10   if (heap->GetImageSpace() == nullptr) {
    11     // TODO If we get a dex2dex compiler working we could maybe use that, OTOH since we are likely
    12     // out of space anyway it might not matter.
    13     *error_msg = StringPrintf("Cannot create oat file for '%s' because we are running "
    14                               "without an image.", dex_filename);
    15     return false;
    16   }
    17   boot_image_option += heap->GetImageSpace()->GetImageLocation();
    18 
    19   std::string dex_file_option("--dex-file=");
    20   dex_file_option += dex_filename;
    21 
    22   std::string oat_fd_option("--oat-fd=");
    23   StringAppendF(&oat_fd_option, "%d", oat_fd);
    24 
    25   std::string oat_location_option("--oat-location=");
    26   oat_location_option += oat_cache_filename;
    27 
    28   std::vector<std::string> argv;
    29   argv.push_back(dex2oat);
    30   argv.push_back("--runtime-arg");
    31   argv.push_back("-classpath");
    32   argv.push_back("--runtime-arg");
    33   argv.push_back(Runtime::Current()->GetClassPathString());
    34 
    35   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
    36 
    37   if (!Runtime::Current()->IsVerificationEnabled()) {
    38     argv.push_back("--compiler-filter=verify-none");
    39   }
    40 
    41   if (Runtime::Current()->MustRelocateIfPossible()) {
    42     argv.push_back("--runtime-arg");
    43     argv.push_back("-Xrelocate");
    44   } else {
    45     argv.push_back("--runtime-arg");
    46     argv.push_back("-Xnorelocate");
    47   }
    48 
    49   if (!kIsTargetBuild) {
    50     argv.push_back("--host");
    51   }
    52 
    53   argv.push_back(boot_image_option);
    54   argv.push_back(dex_file_option);
    55   argv.push_back(oat_fd_option);
    56   argv.push_back(oat_location_option);
    57   const std::vector<std::string>& compiler_options = Runtime::Current()->GetCompilerOptions();
    58   for (size_t i = 0; i < compiler_options.size(); ++i) {
    59     argv.push_back(compiler_options[i].c_str());
    60   }
    61 
    62   if (!Exec(argv, error_msg)) {
    63     // Manually delete the file. Ensures there is no garbage left over if the process unexpectedly
    64     // died. Ignore unlink failure, propagate the original error.
    65     TEMP_FAILURE_RETRY(unlink(oat_cache_filename));
    66     return false;
    67   }
    68 
    69   return true;
    70 }

    上面代码一目了然,直接执行dex2oat工具来生成oat文件,这个dex2oat工具是如何执行的就不分析了。

    我们再回到OpenDexFilesFromOat函数中,继续往下走,

      // Failed, bail.
      if (open_oat_file.get() == nullptr) {
        std::string error_msg;
        // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.
        DexFile::Open(dex_location, dex_location, &error_msg, dex_files);
        error_msgs->push_back(error_msg);
        return false;
      }
    
      // Try to load again, but stronger checks.
      success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
                                             dex_location_checksum_pointer,
                                             true, error_msgs, dex_files);
      if (success) {
        RegisterOatFile(open_oat_file.release());
        return true;
      } else {
        return false;
      }

    这里和之前一样,先LoadMultiDexFilesFromOatFile()来加载其他dex,如果成功则RegisterOatFile()注册到oat_files_中。

    至此,整个DexClassLoader的创建流程就分析完了。

    总结

    1.在创建DexClassLoader的时候,Android只是把libraryPath提供的目录保存到一个File数组中,以便之后知道去哪找so库,并没有真正解压出so文件;

    2.其实最主要工作还是生成dex文件的oat文件。首先系统会先从内存中查找是否有已经优化并加载好的oat,如果没有,则再从磁盘查找是否有dex对应的oat文件,并判断oat文件是否和dex匹配,如果没有对应的oat文件,则使用dex2oat工具生成oat文件,文件保存在DexClassLoader构造函数中指定的参数目录,如果没指定,就保存在类似/data/dalvik-cache的系统目录中,如果oat文件创建成功,就加载到内存,最后DexClassLoader构造完毕。

  • 相关阅读:
    openlayers6聚合图(附源码下载)
    arcgis api 4.x for js地图加载第三方矢量切片
    leaflet读取tif像素值的两种实现方式(附源码下载)
    openlayers6热力图(附源码下载)
    cesium 3dtiles模型单体化点击高亮效果
    leaflet聚合图功能(附源码下载)
    openlayers6绘制扇形(附源码下载)
    【 Windows 10】神州网信政府版官方镜像
    Windows10 解决“装了 .NET Framework 4.5.2/4.6.1/4.7.1等等任何版本 或版本更高的更新”问题
    App.config/Web.config 中特殊字符的处理
  • 原文地址:https://www.cnblogs.com/coding-way/p/5212208.html
Copyright © 2020-2023  润新知