一.創(chuàng)建Activity對象
ART在加載完dex文件后获茬,會通過Instrumentation
創(chuàng)建Activity
對象
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//加載dex文件
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//創(chuàng)建Activity對象
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
...
}
1. Instrumentation.newActivity()
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
從之前的加載dex文件的過程中可以知道這里傳入的ClassLoader
是PathClassLoader
以我自己寫的demo為例,PathClassLoader是:
dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.singuloid.myapplication-1/base.apk"],
nativeLibraryDirectories=[/data/app/com.singuloid.myapplication-1/lib/arm, /system/lib, /vendor/lib]]]
PathClassLoader
繼承自BaseDexClassLoader
,而BaseDexClassLoader
又是繼承自ClassLoader
,PathClassLoader
和BaseDexClassLoader
兩個類都沒有重寫loadClass()
甸祭,所以這里實際調(diào)用的基類ClassLoader.loadClass
2. ClassLoader.loadClass()
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
//先查找之前是否已經(jīng)過要加載的類, [2.1]
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//在parent中查找類
c = parent.loadClass(name, false);
} else {
//如果parent為null,則代表當前ClassLoader是BootClassLoader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
}
}
return c;
}
從代碼中可以看出褥影,ART的類加載機制也同樣采用雙親委派模式池户,即先由父
ClassLoader
進行加載,如果沒有加載成功凡怎,再交由子ClassLoader
加載校焦,依照此順序,依次向下進行.
如果查找的是應(yīng)用自己的類栅贴,如果沒有加載過斟湃,最后都會在應(yīng)用自己的ClassLoader中查找
如果父類加載器沒有加載到類,則調(diào)用當前類加載器的findClass
方法檐薯,在創(chuàng)建Activity對象這個場景下,當前的類加載器是PathClassLoader
,而PathClassLoader
并沒有重寫findClass
,查看其父類BaseDexClassLoader
,發(fā)現(xiàn)BaseDexClassLoader
重寫了findClass
這個方法
2.1 ClassLoader.findLoadedClass
protected final Class<?> findLoadedClass(String name) {
ClassLoader loader;
if (this == BootClassLoader.getInstance())
loader = null;
else
loader = this;
return VMClassLoader.findLoadedClass(loader, name);
}
VMClassLoader.findLoadedClass
是一個native方法坛缕,其實現(xiàn)在art/runtime/native/lava_lang_VMClassLoader
:
static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
jstring javaName) {
ScopedFastNativeObjectAccess soa(env);
mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
ScopedUtfChars name(env, javaName);
if (name.c_str() == nullptr) {
return nullptr;
}
ClassLinker* cl = Runtime::Current()->GetClassLinker();
std::string descriptor(DotToDescriptor(name.c_str()));
const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
//在傳入的ClassLoader中查找類墓猎,每一個ClassLoader都有一個ClassTable曲梗,用來記錄已經(jīng)加載的類
mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
//如果找到類顽频,且類已經(jīng)被正確解析,則直接返回
if (c != nullptr && c->IsResolved()) {
return soa.AddLocalReference<jclass>(c);
}
//如果類是錯誤的骇陈,則拋出相應(yīng)異常
if (c != nullptr && c->IsErroneous()) {
...
return nullptr;
}
//執(zhí)行到這里宠页,意味著沒有在緩存的ClassTable中找到類左胞,需要進一步到dex文件中進行查找
if (loader != nullptr) {
StackHandleScope<1> hs(soa.Self());
cl->FindClassInPathClassLoader(soa, soa.Self(), descriptor.c_str(), descriptor_hash,
hs.NewHandle(loader), &c);
if (c != nullptr) {
return soa.AddLocalReference<jclass>(c);
}
}
// Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into
// the regular loadClass code.
return nullptr;
}
3. BaseDexClassLoader.findClass()
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
由之前的ART 加載dex文件可知,BaseDexClassLoader
的pathList
變量指向的是一個DexPathList
,而DexPathList
是用來保存加載的dex文件列表举户,從這里我們知道BaseDexClassLoader
又將加載類的過程委派給了DexPathList
4. DexPathList.findClass()
public Class findClass(String name, List<Throwable> suppressed) {
//迭代dexElements
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
從代碼中可知,其主要邏輯是遍歷之前加載過得dex文件列表烤宙,依次在每個dex文件中查找,直到加載到相應(yīng)的類
5. DexFile.loadClassBinaryName()
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
//mCookie保存的是加載的dex文件列表
return defineClass(name, loader, mCookie, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, Object cookie,
List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie);
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
private static native Class defineClassNative(String name, ClassLoader loader, Object cookie)
throws ClassNotFoundException, NoClassDefFoundError;
loadClassBinaryName
實際就是封裝調(diào)用了defineClass
(從代碼中可以看出俭嘁,傳入的參數(shù)中有一個是mCookie
躺枕,這個變量保存的正是之前加載的dex文件列表),而defineClass
實際調(diào)用的是native方法defineClassNative
,只是額外做了異常處理.defineClassNative
的實現(xiàn)在art/runtime/native/dalvik_system_DexFile.cc
6. DexFile_defineClassNative()
static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
jobject cookie) {
//將Java層傳入的mCookie變量轉(zhuǎn)換為vector類型的dex文件列表
std::unique_ptr<std::vector<const DexFile*>> dex_files = ConvertJavaArrayToNative(env, cookie);
...
ScopedUtfChars class_name(env, javaName);
...
//將com.xx.xx轉(zhuǎn)換為com/xx/xx
const std::string descriptor(DotToDescriptor(class_name.c_str()));
const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
for (auto& dex_file : *dex_files) {
//首先獲取ClassDef
const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(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)));
//生成dex_cache,并放入緩存隊列, [6.1]
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
//加載類供填,[7]
mirror::Class* result = class_linker->DefineClass(soa.Self(), descriptor.c_str(), hash,
class_loader, *dex_file, *dex_class_def);
// 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());
if (result != nullptr) {
...
return soa.AddLocalReference<jclass>(result);
}
}
}
return nullptr;
}
-
defineClassNative
第一個關(guān)鍵步驟是將Java層傳入的mCookie
變量轉(zhuǎn)換為Native的vector
類型的dex文件列表 - 在Native層,每個dex文件有一個對應(yīng)的DexCache結(jié)構(gòu)拐云,該結(jié)構(gòu)緩存了dex文件中一些基本的信息
- 遍歷dex文件列表時,首先從dex文件中獲取
ClassDef
結(jié)構(gòu)近她,之后再根據(jù)這個ClassDef
來加載相應(yīng)的類
6.1 ClassLinker::RegisterDexFile()
mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file,
mirror::ClassLoader* class_loader) {
Thread* self = Thread::Current();
{
ReaderMutexLock mu(self, dex_lock_);
//查找是由已經(jīng)有對應(yīng)的dex_cache叉瘩,有則直接返回
mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
if (dex_cache != nullptr) {
return dex_cache;
}
}
//獲取ClassLoader對應(yīng)的LinearAlloc
LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader);
DCHECK(linear_alloc != nullptr);
ClassTable* table;
{
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
//獲取ClassLoader的ClassTable
table = InsertClassTableForClassLoader(class_loader);
}
StackHandleScope<1> hs(self);
//在LinearAlloc創(chuàng)建一個dex_cache結(jié)構(gòu),此時不要持有dex_lock_鎖粘捎,因為分配時可能會掛起所有線程而且可能存在線程需要
//dex_lock_
Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc)));
{
WriterMutexLock mu(self, dex_lock_);
mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
if (dex_cache != nullptr) {
return dex_cache;
}
//如果分配dex_cache結(jié)構(gòu)失敗薇缅,則一定是發(fā)生了OOM
if (h_dex_cache.Get() == nullptr) {
self->AssertPendingOOMException();
return nullptr;
}
//根據(jù)dex_file生成dex_cache,并注冊dex_cache
RegisterDexFileLocked(dex_file, h_dex_cache);
}
table->InsertStrongRoot(h_dex_cache.Get());
return h_dex_cache.Get();
}
7. ClassLinker::DefineClass
mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(nullptr);
//如果ClassLinker還未初始化完成,且要加載的正好是幾個指定的系統(tǒng)類晌端,將kclass指向系統(tǒng)類
...
if (klass.Get() == nullptr) {
//創(chuàng)建Class對象
klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
}
...
//獲取dex_cache結(jié)構(gòu)捅暴,如果未獲取到則創(chuàng)建
mirror::DexCache* dex_cache = RegisterDexFile(dex_file, class_loader.Get());
if (dex_cache == nullptr) {
self->AssertPendingOOMException();
return nullptr;
}
klass->SetDexCache(dex_cache);
//設(shè)置klass基本屬性, [7.1]
SetupClass(dex_file, dex_class_def, klass, class_loader.Get());
...
ObjectLock<mirror::Class> lock(self, klass);
klass->SetClinitThreadId(self->GetTid());
// 將要加載的類添加到ClassLinker的已加載類列表
mirror::Class* existing = InsertClass(descriptor, klass.Get(), hash);
if (existing != nullptr) {
//如果插入失敗,則表明類已經(jīng)被加載過
return EnsureResolved(self, descriptor, existing);
}
//加載類咧纠,[7.2]
LoadClass(self, dex_file, dex_class_def, klass);
...
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, dex_file)) {
...
}
//正常情況下,此時klass->IsLoaded∨钛鳌= true
CHECK(klass->IsLoaded());
//正常情況下,此時klass->isResolved = false
CHECK(!klass->IsResolved());
auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr);
//對加載后的類進行鏈接解析漆羔,[7.3]
if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
...
}
...
return h_new_class.Get();
}
DefineClass
中的關(guān)鍵步驟可以總結(jié)為:SetupClass
-->InsertClass
-->LoadClass
-->LoadSuperAndInterfaces
-->LinkClass
7.1 ClassLinker::SetupClass
void ClassLinker::SetupClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass,
mirror::ClassLoader* class_loader) {
... //Check(...)
const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
... //Check(...)
klass->SetClass(GetClassRoot(kJavaLangClass));
uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
... //Check(...)
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
... //Check(...)
mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);
klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
klass->SetDexTypeIndex(dex_class_def.class_idx_);
... //Check(...)
}
可以看到梧奢,SetupClass
方法主要是給Class對象設(shè)置基本屬性如access_flags
,ClassLoader
7.2 ClassLinker::LoadClass()
void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
//獲取ClassData
const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
if (class_data == nullptr) {
return; // no fields or methods - for example a marker interface
}
bool has_oat_class = false;
if (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) {
//獲取OatClass,通過OatClass可以獲取類方法的本地機器指令
//klass->GetDexClassDefIndex()獲取相應(yīng)ClassDef結(jié)構(gòu)在dex文件內(nèi)的索引號,這個索引號是在之前的
//SetupClass()函數(shù)中獲取并設(shè)置
OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
&has_oat_class);
if (has_oat_class) {
//加載類成員, [7.2.1]
LoadClassMembers(self, dex_file, class_data, klass, &oat_class);
}
}
if (!has_oat_class) {
LoadClassMembers(self, dex_file, class_data, klass, nullptr);
}
}
- 從dex文件內(nèi)部獲取ClassData結(jié)構(gòu)
- 根據(jù)ClassDef的索引位置獲取相應(yīng)OatClass結(jié)構(gòu)演痒,通過OatClass結(jié)構(gòu)可以獲取類方法的本地機器指令
- 如果找到OatClass則根據(jù)OatClass來加載類成員
dex文件中每一個類在oat文件中都由一個對應(yīng)的
OatClass
結(jié)構(gòu)亲轨,根據(jù)OatClass
可以找到每一個類方法的本地機器指令
7.2.1 ClassLinker::LoadClassMembers()
void ClassLinker::LoadClassMembers(Thread* self,
const DexFile& dex_file,
const uint8_t* class_data,
Handle<mirror::Class> klass,
const OatFile::OatClass* oat_class) {
{
//在沒有加載完類成員之前,不允許當前線程掛起
ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
//加載靜態(tài)屬性
LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
ClassDataItemIterator it(dex_file, class_data);
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
allocator,
it.NumStaticFields());
size_t num_sfields = 0;
uint32_t last_field_idx = 0u;
for (; it.HasNextStaticField(); it.Next()) {
uint32_t field_idx = it.GetMemberIndex();
if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
//加載屬性,[7.2.1.1]
LoadField(it, klass, &sfields->At(num_sfields));
++num_sfields;
last_field_idx = field_idx;
}
}
//加載實例屬性
LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
allocator,
it.NumInstanceFields());
size_t num_ifields = 0u;
last_field_idx = 0u;
for (; it.HasNextInstanceField(); it.Next()) {
uint32_t field_idx = it.GetMemberIndex();
if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
LoadField(it, klass, &ifields->At(num_ifields));
++num_ifields;
last_field_idx = field_idx;
}
}
....
// Set the field arrays.
klass->SetSFieldsPtr(sfields);
klass->SetIFieldsPtr(ifields);
// 加載方法
klass->SetMethodsPtr(
AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
it.NumDirectMethods(),
it.NumVirtualMethods());
size_t class_def_method_index = 0;
uint32_t last_dex_method_index = DexFile::kDexNoIndex;
size_t last_class_def_method_index = 0;
//首先加載直接方法
for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
//加載方法鸟顺,[7.2.1.2]
LoadMethod(self, dex_file, it, klass, method);
//將方法同對應(yīng)的本地機器指令關(guān)聯(lián)惦蚊,這樣在方法執(zhí)行時就可以知道該如何執(zhí)行, [7.2.1.3]
LinkCode(method, oat_class, class_def_method_index);
uint32_t it_method_index = it.GetMemberIndex();
if (last_dex_method_index == it_method_index) {
method->SetMethodIndex(last_class_def_method_index);
} else {
method->SetMethodIndex(class_def_method_index);
last_dex_method_index = it_method_index;
last_class_def_method_index = class_def_method_index;
}
class_def_method_index++;
}
//加載虛擬方法
for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
LoadMethod(self, dex_file, it, klass, method);
LinkCode(method, oat_class, class_def_method_index);
class_def_method_index++;
}
}
// Ensure that the card is marked so that remembered sets pick up native roots.
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get());
self->AllowThreadSuspension();
}
- 首先便是設(shè)置當前線程在沒有完成加載類成員工作之前不能被掛起
- 之后依次加載Static Field器虾,Instance Field,所有Field都用ArtField表示
- 加載完Field后,再依次加載Direct Method和Virtual Method并關(guān)聯(lián)Method對應(yīng)的機器指令蹦锋,所有Method都用ArtMethod表示
- 當所有加載工作完成之后兆沙,告知線程加載工作完成,允許被掛起
7.2.1.1 ClassLinker::LoadField()
void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass,
ArtField* dst) {
const uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
dst->SetAccessFlags(it.GetFieldAccessFlags());
}
7.2.1.2 ClassLinker::LoadMethod()
void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it,
Handle<mirror::Class> klass, ArtMethod* dst) {
//從dex文件的ClassData結(jié)構(gòu)種獲取對應(yīng)Method的索引
uint32_t dex_method_idx = it.GetMemberIndex();
//獲取MethodId結(jié)構(gòu)
const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
ScopedAssertNoThreadSuspension ants(self, "LoadMethod");
dst->SetDexMethodIndex(dex_method_idx);
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
uint32_t access_flags = it.GetMethodAccessFlags();
//一般情況下莉掂,方法名不會是finalize
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
// Void return type.
if (klass->GetClassLoader() != nullptr) { // All non-boot finalizer methods are flagged.
klass->SetFinalizable();
} else {
std::string temp;
const char* klass_descriptor = klass->GetDescriptor(&temp);
//Enum枚舉類不設(shè)置finalizable,因為枚舉類已經(jīng)聲明了一個final finalize()
if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
klass->SetFinalizable();
}
}
}
} else if (method_name[0] == '<') {
//判斷是不是實例化構(gòu)造函數(shù)
bool is_init = (strcmp("<init>", method_name) == 0);
//判斷是不是類初始化方法
bool is_clinit = !is_init && (strcmp("<clinit>", method_name) == 0);
if (UNLIKELY(!is_init && !is_clinit)) {
... //LOG
} else {
if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
access_flags |= kAccConstructor;
}
}
}
dst->SetAccessFlags(access_flags);
}
7.2.1.3 ClassLinker::LinkCode()
void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class,
uint32_t class_def_method_index) {
Runtime* const runtime = Runtime::Current();
if (runtime->IsAotCompiler()) {
return;
}
...
if (oat_class != nullptr) {
//從OatClass中獲取對應(yīng)的OatMethod,OatMethod中記錄了方法的本地機器指令的偏移地址
//通過OatMethod::LinkMethod將OatMethod中記錄的信息設(shè)置到ArtMethod當中
const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
oat_method.LinkMethod(method);
}
//之后設(shè)置方法執(zhí)行的entry point
//判斷是否需要解釋執(zhí)行:
//1.當沒有本地機器指令
//2.Runtime指定以Interpreter方式運行且方法不是native同時也不是proxy
//JNI方法是沒有對應(yīng)的DEX字節(jié)碼的葛圃,因此即使ART虛擬機運行在解釋模式中,JNI方法也不能通過解釋器來執(zhí)行
bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
if (enter_interpreter && !method->IsNative()) {
method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
} else {
//有兩種情況會進入這一分支
//不需要解釋執(zhí)行的方法
//沒有本地機器指令或者Runtime以Interpreter方式運行憎妙,但該方法是native
method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
}
if (method->IsAbstract()) {
//抽象方法沒有機器指令库正,當有機器指令的方法調(diào)用抽象方法時,需要設(shè)置一個橋接函數(shù)厘唾,從而轉(zhuǎn)到
//解釋器褥符,由解釋器解釋執(zhí)行抽象方法
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
return;
}
if (method->IsStatic() && !method->IsConstructor()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
} else if (enter_interpreter) {
if (!method->IsNative()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
} else {
//只有當native方法沒有本地機器指令時,會執(zhí)行這一分支
method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
}
}
if (method->IsNative()) {
// Unregistering restores the dlsym lookup stub.
method->UnregisterNative();
if (enter_interpreter) {
//native方法且沒有對應(yīng)的機器指令阅嘶,則該方法如果是non-static,則entry point是generic JNI trampoline
//如果是static, 則entry point是resolution trampoline
const void* entry_point = method->GetEntryPointFromQuickCompiledCode();
DCHECK(IsQuickGenericJniStub(entry_point) || IsQuickResolutionStub(entry_point));
}
}
}
LinkCode
方法主要作用是根據(jù)方法屬性來設(shè)置entry point
- 對于需要解釋的方法属瓣,該方法需要由解釋器解釋執(zhí)行,當另一個解釋方法調(diào)用了這個需要解釋執(zhí)行的方法時讯柔,該方法的入口函數(shù)是
artInterpreterToInterpreterBridge
,從而繼續(xù)在解釋器中解釋執(zhí)行抡蛙;如果當前方法是執(zhí)行本地機器指令,當另一個解釋執(zhí)行的方法調(diào)用了這個執(zhí)行本地機器指令的方法魂迄,該方法的入口函數(shù)是artInterpreterToCompiledCodeBridge
粗截,artInterpreterToCompiledCodeBridge
會去調(diào)用相應(yīng)的機器指令 - 抽象方法需要由被子類實現(xiàn),所以抽象類是沒有本地機器指令的捣炬,需要由解釋器解釋執(zhí)行熊昌,當有機器指令的方法調(diào)用抽象方法時, 需要設(shè)置一個橋接函數(shù),從而轉(zhuǎn)到
解釋器湿酸,由解釋器解釋執(zhí)行抽象方法, 這個橋接函數(shù)是GetQuickToInterpreterBridge()
- 對于靜態(tài)非構(gòu)造函數(shù)婿屹,當有執(zhí)行機器指令的方法調(diào)用這類函數(shù)時,入口函數(shù)是
GetQuickResolutionStub()
.因為靜態(tài)方法不需要創(chuàng)建對象便可執(zhí)行推溃,著就有可能出現(xiàn)類還未初始化昂利,方法就要執(zhí)行,所以此時就需要現(xiàn)將類初始化铁坎,再執(zhí)行靜態(tài)方法蜂奸,GetQuickResolutionStub
完成的正是這項工作 - 對于需要解釋執(zhí)行且不是native的方法,當執(zhí)行本地機器指令的方法調(diào)用該方法時硬萍,入口函數(shù)是
GetQuickToInterpreterBridge()
,該函數(shù)會轉(zhuǎn)到解釋器扩所,由解釋器執(zhí)行這個需要解釋執(zhí)行的方法;當一個執(zhí)行本地機器指令的方法調(diào)用沒有機器指令的native方法時朴乖,入口函數(shù)是GetQuickGenericJniStub()
- 如果一個方法是native方法祖屏,設(shè)置本地方法的入口是通過
GetJniDlsymLookupStub
獲得的一個Stub
以上內(nèi)容參考老羅的Android運行時ART加載類和方法的過程分析
8. ClassLinker::InsertDexFileInToClassLoader
void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file,
mirror::ClassLoader* class_loader) {
Thread* const self = Thread::Current();
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
ClassTable* const table = ClassTableForClassLoader(class_loader);
//InsertStrongRoot方法將dex_file對象放入ClassTable的strong_table_隊列中
if (table->InsertStrongRoot(dex_file) && class_loader != nullptr) {
//執(zhí)行write barrier從而讓GC知道ClassLoader的ClassTable發(fā)生了改變
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
}
}