Dex文件加载过程
PathClassLoader 和 DexClassLoader都可以加载dex和apk文件,其对应的基类都是BaseDexClassLoader。在new一个PathClassLoader/DexClassLoader对象时就会调用其对应的构造函数,然后调用父类BaseDexClassLoader的构造函数。最终的调用链为:
Method | file |
---|---|
BaseDexClassLoader() | libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java |
new DexPathList | libcore/dalvik/src/main/java/dalvik/system/DexPathList.java |
DexPathList.makeDexElements | ... |
DexPathList.loadDexFile | ... |
new DexFile | libcore/dalvik/src/main/java/dalvik/system/DexFile.java |
DexFile.openDexFile | ... |
DexFile.openDexFileNative | ... |
DexFile_openDexFileNative
DexFile.openDexFileNative对应的native函数为DexFile_openDexFileNative,此函数会调用OpenDexFilesFromOat
//art/runtime/native/dalvik_system_DexFile.cc
static jobject DexFile_openDexFileNative(JNIEnv* env,
jclass,
jstring javaSourceName,
jstring javaOutputName ATTRIBUTE_UNUSED,
jint flags ATTRIBUTE_UNUSED,
jobject class_loader,
jobjectArray dex_elements) {
std::vector<std::string> error_msgs;
const OatFile* oat_file = nullptr;
std::vector<std::unique_ptr<const DexFile>> dex_files =
Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(),
class_loader,
dex_elements,
/*out*/ &oat_file,
/*out*/ &error_msgs);
}
OatFileManager::OpenDexFilesFromOat_Impl
OpenDexFilesFromOat最终会调用OpenDexFilesFromOat_Impl,OpenDexFilesFromOat_Impl的主要代码如下,最重要的就是调用dex_file_loader.Open去加载dex文件
std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat_Impl(
std::vector<MemMap>&& dex_mem_maps,
jobject class_loader,
jobjectArray dex_elements,
const OatFile** out_oat_file,
std::vector<std::string>* error_msgs) {
...
std::vector<std::unique_ptr<const DexFile>> dex_files;
for (size_t i = 0; i < dex_mem_maps.size(); ++i) {
static constexpr bool kVerifyChecksum = true;
const ArtDexFileLoader dex_file_loader;
std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(
DexFileLoader::GetMultiDexLocation(i, dex_location.c_str()),
dex_headers[i]->checksum_,
std::move(dex_mem_maps[i]),
/* verify= */ (vdex_file == nullptr) && Runtime::Current()->IsVerificationEnabled(),
kVerifyChecksum,
&error_msg));
if (dex_file != nullptr) {
dex::tracking::RegisterDexFile(dex_file.get()); // Register for tracking.
dex_files.push_back(std::move(dex_file));
} else {
error_msgs->push_back("Failed to open dex files from memory: " + error_msg);
}
}
...
return dex_files;
}
android类加载过程
ClassLoader::LoadClass
ClassLoader类是所有类加载器的虚基类,在静态/动态加载一个类时会首先调用此虚基类的LoadClass函数。
//libcore/ojluni/src/main/java/java/lang/ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
//查找此类是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
//父加载器不为空就先让父加载器加载此类
c = parent.loadClass(name, false);
} else {
//父加载器为空说明此加载器为根加载器BootClassLoader,让根加载器去加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
//如果父加载器都加载不了就让当前类加载器调用findclass去加载。
c = findClass(name);
}
}
return c;
}
BaseDexClassLoader::findClass
因为BaseDexClassLoader继承了ClassLoader虚类,其他加载器的类基本都继承于BaseDexClassLoader类,BaseDexClassLoader类中重写了findClass方法,所以上一步会去调用BaseDexClassLoader类中的findClass方法。
//libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
protected Class<?> findClass(String name) throws ClassNotFoundException {
...
// Check whether the class in question is present in the dexPath that
// this classloader operates on.
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c != null) {
return c;
}
}
BaseDexClassLoader的findclass会继续调用DexPathList的findClass方法
//libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
DexPathList的findClass方法调用Element类的findClass方法。
//libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
defineClassNative
Element类的findClass方法去调用loadClassBinaryName函数,loadClassBinaryName函数接着会调用defineClass->defineClassNative。defineClassNative函数是一个native函数在art虚拟机中实现。
//libcore/dalvik/src/main/java/dalvik/system/DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, Object cookie,
DexFile dexFile, List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie, dexFile);
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
defineClassNative对应的art中的native函数为DexFile_defineClassNative,在art中进行类的字段,方法的加载。
DexFile_defineClassNative
- FindClassDef枚举此类加载器的所有dex文件,并在这些dex文件中寻找Class_def看是否等于当前加载类,如果找不到则返回失败
- ClassLinker::DefineClass加载对应类的字段和方法
- 将对应的DexFile添加到类加载器对应的ClassTable中
//art/runtime/native/dalvik_system_DexFile.cc
static jclass DexFile_defineClassNative(JNIEnv* env,
jclass,
jstring javaName,
jobject javaLoader,
jobject cookie,
jobject dexFile) {
std::vector<const DexFile*> dex_files;
const std::string descriptor(DotToDescriptor(class_name.c_str()));
const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
//枚举此类加载器的所有dex文件
for (auto& dex_file : dex_files) {
//找到dex中的ClassDef
const dex::ClassDef* dex_class_def =
OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash);
if (dex_class_def != nullptr) {
ScopedObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
ObjPtr<mirror::DexCache> dex_cache =
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
if (dex_cache == nullptr) {
// OOME or InternalError (dexFile already registered with a different class loader).
soa.Self()->AssertPendingException();
return nullptr;
}
//完成目标类的加载
ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),
descriptor.c_str(),
hash,
class_loader,
*dex_file,
*dex_class_def);
//将对应的DexFile添加到类加载器对应的ClassTable中
// Add the used dex file. This only required for the DexFile.loadClass API since normal
// class loaders already keep their dex files live.
class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile),
class_loader.Get());
}
ClassLinker::DefineClass
DefineClass主要就是调用ClassLinker::LoadClass加载对应类的字段和方法
//art/runtime/class_linker.cc
ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const dex::ClassDef& dex_class_def) {
//从DexFile dex文件中(内存中的)加载所有的field和method
// Load the fields and other things after we are inserted in the table. This is so that we don't
// end up allocating unfree-able linear alloc resources and then lose the race condition. The
// other reason is that the field roots are only visited from the class table. So we need to be
// inserted before we allocate / fill in these fields.
LoadClass(self, *new_dex_file, *new_class_def, klass);
}
ClassLinker::LoadClass
ClassLinker::LoadClass调用LoadField加载所有的字段,调用LoadMethod加载所有的方法。
//art/runtime/class_linker.cc
void ClassLinker::LoadClass(Thread* self,
const DexFile& dex_file,
const dex::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
uint16_t hotness_threshold = runtime->GetJITOptions()->GetWarmupThreshold();
// Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the
// methods needs to decode all of the fields.
accessor.VisitFieldsAndMethods([&](
//加载所有的静态field
const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t field_idx = field.GetIndex();
DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier.
if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {
LoadField(field, klass, &sfields->At(num_sfields));
++num_sfields;
last_static_field_idx = field_idx;
}
}, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
//加载所有的field
uint32_t field_idx = field.GetIndex();
DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier.
if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {
LoadField(field, klass, &ifields->At(num_ifields));
++num_ifields;
last_instance_field_idx = field_idx;
}
}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
//加载所有的对象方法(direct method)
ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,
image_pointer_size_);
LoadMethod(dex_file, method, klass.Get(), art_method);
LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
uint32_t it_method_index = method.GetIndex();
if (last_dex_method_index == it_method_index) {
// duplicate case
art_method->SetMethodIndex(last_class_def_method_index);
} else {
art_method->SetMethodIndex(class_def_method_index);
last_dex_method_index = it_method_index;
last_class_def_method_index = class_def_method_index;
}
art_method->ResetCounter(hotness_threshold);
++class_def_method_index;
}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
//加载所有的抽象方法(virtual method)
ArtMethod* art_method = klass->GetVirtualMethodUnchecked(
class_def_method_index - accessor.NumDirectMethods(),
image_pointer_size_);
art_method->ResetCounter(hotness_threshold);
LoadMethod(dex_file, method, klass.Get(), art_method);
LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
++class_def_method_index;
});
}
标签:dex,class,field,源码,file,android,method,加载
From: https://www.cnblogs.com/revercc/p/16808386.html