public static void install(Context context) {
...
ApplicationInfo applicationInfo = getApplicationInfo(context);
...
synchronized(installedApk) {
String apkPath = applicationInfo.sourceDir;
...
ClassLoader loader = context.getClassLoader();
...
// 获取缓存目录
File dexDir = getDexDir(context, applicationInfo);
// 加载缓存文件
List<File> files = MultiDexExtractor.load(context, applicationInfo, dexDir, false);
...
// 安装提取dex
installSecondaryDexes(loader, dexDir, files);
}
}
// MultiDexExtractor#load
// 获取dex文件列表
static List<File> load(Context context, ApplicationInfo applicationInfo, File dexDir, boolean forceReload) {
...
files = loadExistingExtractions(context, sourceApk, dexDir);
...
}
private static void installSecondaryDexes(ClassLoader loader, File dexDir, List<File> files) {
if (!files.isEmpty()) {
if (Build.VERSION.SDK_INT >= 19) {
V19.install(loader, files, dexDir);
} else if (Build.VERSION.SDK_INT >= 14) {
V14.install(loader, files, dexDir);
} else {
V4.install(loader, files);
}
}
}
/**
* Installer for platform versions 14, 15, 16, 17 and 18.
*/
private static final class V14 {
private static void install(ClassLoader loader, List<File> additionalClassPathEntries, File optimizedDirectory){
// 扩展ClassLoader实例的"pathList"字段。
Field pathListField = findField(loader, "pathList");
Object dexPathList = pathListField.get(loader);
expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList,
new ArrayList<File>(additionalClassPathEntries), optimizedDirectory));
}
private static Object[] makeDexElements(
Object dexPathList, ArrayList<File> files, File optimizedDirectory)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
Method makeDexElements =
findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class);
return (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory);
}
}
final class DexPathList {
private static final String DEX_SUFFIX = ".dex";
private static final String JAR_SUFFIX = ".jar";
private static final String ZIP_SUFFIX = ".zip";
private static final String APK_SUFFIX = ".apk";
// 加载解压dex文件, 并放到elements数组
private static Element[] makeDexElements(ArrayList<File> files,
File optimizedDirectory) {
ArrayList<Element> elements = new ArrayList<Element>();
for (File file : files) {
ZipFile zip = null;
DexFile dex = null;
String name = file.getName();
if (name.endsWith(DEX_SUFFIX)) {
// Raw dex file (not inside a zip/jar).
...
dex = loadDexFile(file, optimizedDirectory);
...
}
...
elements.add(new Element(file, zip, dex));
}
return elements.toArray(new Element[elements.size()]);
}
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);
}
}
}
// sourceName: apk/dex路径; outputName: dex优化后的输出路径
private DexFile(String sourceName, String outputName, int flags) throws IOException {
...
mCookie = openDexFile(sourceName, outputName, flags);
...
}
/*
* Open a DEX file. The value returned is a magic VM cookie. On
* failure, an IOException is thrown.
*/
private static int openDexFile(String sourceName, String outputName,
int flags) throws IOException {
return openDexFileNative(new File(sourceName).getCanonicalPath(),
(outputName == null) ? null : new File(outputName).getCanonicalPath(),
flags);
}
native private static int openDexFileNative(String sourceName, String outputName,
int flags) throws IOException;
// 查看art/runtime/native/dalvik_system_DexFile.cc的实现
// 关键逻辑
bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
dex_files.get());
// Multidex files make it possible that some, but not all, dex files can be broken/outdated. This
// complicates the loading process, as we should not use an iterative loading process, because that
// would register the oat file and dex files that come before the broken one. Instead, check all
// multidex ahead of time.
bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
std::vector<std::string>* error_msgs,
std::vector<const DexFile*>* dex_files) {
...
//查看目标Oat文件是否已经被加载过了
const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location, dex_location_checksum_pointer);
...
bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
dex_location_checksum_pointer,
false, error_msgs, dex_files);
...
}
// Loads all multi dex files from the given oat file returning true on success.
//
// Parameters:
// oat_file - the oat file to load from
// dex_location - the dex location used to generate the oat file
// dex_location_checksum - the checksum of the dex_location (may be null for pre-opted files)
// generated - whether or not the oat_file existed before or was just (re)generated
// error_msgs - any error messages will be appended here
// dex_files - the loaded dex_files will be appended here (only if the loading succeeds)
static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file,
const char* dex_location,
const uint32_t* dex_location_checksum,
bool generated,
std::vector<std::string>* error_msgs,
std::vector<const DexFile*>* dex_files) {
...
// 尝试寻找对应的OAT文件
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(next_name, nullptr, false);
...
const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
...
}
// art/runtime/oat_file.cc
const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
dex_file_location_checksum_, error_msg);
}
// art/runtime/dex_file.cc
bool DexFile::Open(const char* filename, const char* location, std::string* error_msg,
std::vector<const DexFile*>* dex_files) {
uint32_t magic;
...
if (IsZipMagic(magic)) {
//因为传入的是APK,所以进到这里
return DexFile::OpenZip(fd.release(), location, error_msg, dex_files);
}
...
}
bool DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg,
std::vector<const DexFile*>* dex_files) {
...
return DexFile::OpenFromZip(*zip_archive, location, error_msg, dex_files);
}
bool DexFile::OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
std::string* error_msg, std::vector<const DexFile*>* dex_files) {
ZipOpenErrorCode error_code;
std::unique_ptr<const DexFile> dex_file(Open(zip_archive, kClassesDex, location, error_msg,
&error_code));
if (dex_file.get() == nullptr) {
return false;
} else {
// Had at least classes.dex.
dex_files->push_back(dex_file.release());
// Now try some more.
size_t i = 2;
// We could try to avoid std::string allocations by working on a char array directly. As we
// do not expect a lot of iterations, this seems too involved and brittle.
while (i < 100) {
// 找到编译器生成多个dexclasses2.dex...
std::string name = StringPrintf("classes%zu.dex", i);
std::string fake_location = location + kMultiDexSeparator + name;
std::unique_ptr<const DexFile> next_dex_file(Open(zip_archive, name.c_str(), fake_location,error_msg, &error_code));
...
dex_files->push_back(next_dex_file.release());
i++;
}
return true;
}
}