DexFile_openDexFileNative对应于java层的openDexFile(String sourceName, String outputName, int flags)函数。其中sourceName为指定源文件路径,outputName为输出目录。
一、DexFile_openDexFileNative
static jint DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
ScopedUtfChars sourceName(env, javaSourceName); // 将 javaSourceName 从jstring类转换成ScopedUtfChars类
if (sourceName.c_str() == NULL) { // 若javaSourceName为空,则返回
return 0;
}
std::string dex_location(sourceName.c_str()); // char*型转换成c++中的string
NullableScopedUtfChars outputName(env, javaOutputName); // A smart pointer that provides read-only access to a Java string's UTF chars.
if (env->ExceptionCheck()) { // NullableScopedUtfChars的习惯用法
return 0;
}
ScopedObjectAccess soa(env); // 线程加锁
.
.
.
ClassLinker* linker = Runtime::Current()->GetClassLinker(); // Get ClassLinker* of current Runtime
const DexFile* dex_file;
if (outputName.c_str() == NULL) { // 如果outputName为空,则dex_file由sourceName确定
dex_file = linker->FindDexFileInOatFileFromDexLocation(dex_location, dex_location_checksum); // ②
} else { // 如果outputName
std::string oat_location(outputName.c_str());
dex_file = linker->FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, oat_location); // ①
}
if (dex_file == NULL) {
LOG(WARNING) << "Failed to open dex file: " << dex_location;
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;",
"Unable to open dex file: %s", dex_location.c_str());
return 0;
}
return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
}
函数位于/art/runtime/native/dalvik_system_DexFile.cc中。
函数做的4件事:
1.字符串类型的转换。将 javaSourceName 从jstring类转换成ScopedUtfChars类。ScopedUtfChars类的实例sourceName中的utf_chars_变量中保存着javaSourceName的信息。然后将得到的utf_chars_从char*型转换成c++中的string类型。string类实例变量dex_location中保存着javaSourceName的信息。(javaSourceName对应为一个jar/zip/dex/apk文件)
2.NullableScopedUtfChars类的 outputName实例中的jstring mString和 const char* mUtfChars值,分别对应于javaOutputName的jstring和char*类型。
3.得到此源文件的checksum_值。保存在dex_location_checksum中,用于对源文件进行校验。
4.分两条支路outputName==NULL和outputName!=NULL对源文件提取dex_file的提取。
二、FindOrCreateOatFileForDexLocation
首先,分析outputName!=NULL时的分支:
这个分支首先调用 FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, oat_location)方法:
const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
uint32_t dex_location_checksum,
const std::string& oat_location) {
WriterMutexLock mu(Thread::Current(), dex_lock_); // 互锁
return FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_location);
}
该方法位于/art/runtime/class_linker.cc中。
函数根据源文件目录dex_location(由javaSourceName指定)产生oat文件存储到输出目录oat_location(由javaOutputName指定)中。并返回此oat文件中的DexFile文件。// ??????
WriterMutexLock是对当前的互锁。接着调用:FindOrCreateOatFileForDexLocationLocked(dex_location, dex_location_checksum, oat_location)函数