加載的類在 Dalvik 中是以 struct ClassObject 的形式存在的。
//@dalvik/vm/oo/Object.h
struct ClassObject : Object {
u4 instanceData[CLASS_FIELD_SLOTS];
const char* descriptor;//類描述符
char* descriptorAlloc;
u4 accessFlags;//訪問標(biāo)示符
u4 serialNumber;//系列號
DvmDex* pDvmDex;//指向所屬的 Dex 文件
ClassStatus status;//類狀態(tài)標(biāo)志 state of class initialization
ClassObject* verifyErrorClass;//錯(cuò)誤處理
u4 initThreadId;//初始化進(jìn)程 ID
size_t objectSize;
ClassObject* elementClass;//元素類 arrays only
int arrayDim;//數(shù)組維數(shù) arrays only
PrimitiveType primitiveType;//原始類型
ClassObject* super;//超類
Object* classLoader;//類裝載器 defining class loader, or NULL for the "bootstrap" system loader
InitiatingLoaderList initiatingLoaderList;//initiating class loader list
int interfaceCount;//接口數(shù)目
ClassObject** interfaces;//對象接口
int directMethodCount;//直接方法數(shù)
Method* directMethods;//指向直接方法區(qū)
int virtualMethodCount;//虛方法數(shù)
Method* virtualMethods;//指向虛方法區(qū)
//Virtual method table, for use by "involke-virtual". The
//vtable from superclass is copied in, and virtual methods from
//our class either replace those from the super or are appended;
//與 Hotspot 虛擬機(jī)類似,子類會(huì) copy 一份父類的虛方法巷波,并且重寫重寫方法的指針
int vtableCount;
Method** vtable;
//Interface table, one entry per interface supported by this class.
int iftableCount;//接口表數(shù)目
InterfaceEntry* iftable;//指向接口表
int ifviPoolCount;//常量池?cái)?shù)目
int* ifviPool;//指向常量池
//instance fields
int ifieldCount;//實(shí)例字段數(shù)目
int ifieldRefCount;//引用字段數(shù)目
InstField* ifields;//實(shí)例字段數(shù)目
u4 refOffsets;//字段區(qū)偏移
const char* sourceFile;//源文件名
int sfieldCount;//靜態(tài)字段數(shù)目
StaticField sfields[ ];//靜態(tài)字段指針
}
接下里看比較重要 Method 結(jié)構(gòu)
struct Method{
ClassObject* clazz;
u4 accessFlags;
//for concrete virtual methods, this is the offset of the method in "vtable";
//For abstract methods in an interface class, this is the offset of the method in "iftable[n]->methodIndexArray"
u2 methodIndex;
u2 registersSize;
u2 outSize;
u2 insSize;
//method name
const char* name;
//方法原型 Method prototype descriptor string(return and argument types)
DexProto prototype;
//short-form method descriptor string短方法原型
const char* shorty;
//the actual code
const u2* insns;
int jniArgInfo;
DalvikBridgeFunc nativeFunc;
bool fastJni;
bool noRef;
bool shouldTrace;
const RegisterMap* registerMap;
bool inProfile;
}
另外一個(gè)特別重要的作為ClassObject 緩存的哈希表 DexClassLookup
@dalvik/libdex/DexFile.h
struct DexClassLookup{
//表的總大小
int size;
//表項(xiàng)入口數(shù)量,為了減少哈希碰撞蔡旭 dexRoundUpPower2()算法計(jì)算
//在源碼體現(xiàn)是比如實(shí)際數(shù)量是 5,則先 x2 獲得 10,再向上取 2 的冪豁护。即 16
int numEntries;
struct{
//類描述符的哈希
u4 classDescriptorHash;
//類描述符在 dex 文件的偏移
int classDescriptorOffset;
//類定義在 dex 文件的偏移
int classDefOffset;
}table[1];
};
看一波類加載的調(diào)用鏈
findClass(String name)@BaseDexClassLoader.java
↓
findClass(String name)@DexPathList.java
↓
loadClassBinaryName(String name, ClassLoader loader )@DexFile.java
↓
native static Class defineClass(String name, ClassLoader loader, in cookie) @DexFile.java[這里的 cookie 就是前文解析的 DexOrJar]
↓
static void Dalvik_dalvik_system_DexFile_defineClass(const u4* args, JValue* pResult) @ dalvik/vm/native/dalvik_system_DexFile.cpp
↓
ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descritor, Object* classLoader) @ dalvik/vm/oo/Class.cpp
↓
static ClassObject* findClassNoInit(const char* descriptor, Object* loader, DvmDex* pDvmDex) @ dalvik/vm/oo/Class.cpp
--
重點(diǎn)解析 static ClassObject* findClassNoInit()@Class.cpp
static ClassObect* findClassNoInit(const char* descriptor, Object* loader, DvmDex* pDvmDex){
Thread* self = dvmThreadSelf( );
ClassObject* clazz;
...
//從緩存加載
clazz = dvmLookupClass(descriptor, loader, true);
if(clazz == NULL){
//緩存加載失敗,說明還未加載
//類在 Dex 中的數(shù)據(jù)結(jié)構(gòu) class_def_item
const DexClassDef* pClassDef;
if(pDvmDex == NULL){
//說明加載的是系統(tǒng)類
pDvmDex = searchBootPathForClass(descriptor, &pClassDef);
}else{
//加載的是用戶類,重點(diǎn) 1
pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);
}
...
//根據(jù) DevmDex, ClassDef,和 loader 加載 ClasObject
clazz = loadClassFromDex(pDvmDex, pClassDef, loader);
...
dvmAddClassToHash(clazz);
}
}
//@DexFile.h
// Direct-mapped "class_def_item".
struct DexClassDef {
u4 classIdx; /* index into typeIds for this class */
u4 accessFlags;
u4 superclassIdx; /* index into typeIds for superclass */
u4 interfacesOff; /* file offset to DexTypeList */
u4 sourceFileIdx; /* index into stringIds for source file name */
u4 annotationsOff; /* file offset to annotations_directory_item */
u4 classDataOff; /* file offset to class_data_item */
u4 staticValuesOff; /* file offset to DexEncodedArray */
};
上面的重點(diǎn)有兩個(gè)欲间,一個(gè)是根據(jù)DvmDex和 descriptor 獲取 DexClassRef,一個(gè)是根據(jù) DvmDex,ClassRef,loader,獲得ClassObject
- 1
//@DexFile.cpp
const DexClassDef* dexFindClass(const DexFile* pDexFile, const char*descriptor){
const DexClassLookup* pLookup = pDexFile->pClassLookup;
u4 hash;
int idx, mask;
//根據(jù) descriptor 獲取 has 值楚里;
hash = classDescriptorHash(descriptor);
mask = pLookup->numEntries-1;
//根據(jù)根據(jù)哈希模運(yùn)算獲得索引
idx = has&mask;
while(true){
int offset;
offset = pLookup->table[idx].classDescriptorOffset;
if(offset == 0)
return NULL;
if(pLookup->table[idx].classDescriptorHash == hash){
const char* str;
str = (const char*)(pDexFile->baseAddr + offset);
if(strcmp(str, descriptor) == 0){
return (const DexClassDef*)(pDexFile->baseAddr + pLookup->table[idx].classDefOffset);
}
}
idx = (idx+1) & mask;
}
}
可以看到,如果發(fā)生了哈希碰撞猎贴,則會(huì)取下一個(gè)位置進(jìn)行判斷班缎。關(guān)于 ClassLookup 的是在 loadAllClassed( )@DexPrepare.cpp 中
- 2
static ClassObject* loadClassFromDex(DvmDex* pDvmDex, const DexClassDef* pClassDef, Object* classloader){
ClassObject* result;
DexClassDataHeader header;
const u1* pEncodedData;
const DexFile* pDexFile;
pDexFile = pDvmDex->pDexFile;
...
result = loadClassFromDex0(pDvmDex, pClassDef, &header, pEncodedData);
}
static ClassObject* loadClassFromDex0(DvmDex* pDvmDex, const DexClassDef* pClassDef, const DexClassDataHeader* pHeader, const u1* pEncodedData, Object* classLoader){
ClassObject* newClass = NULL;//目標(biāo)類實(shí)例對象
const DexFile* pDexFile;//存儲(chǔ)類對應(yīng)的 DexFile 對象
const char* descriptor;//類描述符
pDexFile = pDvmDex->pDexFile;
descriptor = dexGetClassDescriptor(pDexFile, pClassDef);
if(classLoader = NULL && ...){
newClass = gDvm.classJavaLangClass;
}else{
//獲取對象實(shí)例大小并且在內(nèi)存申請空間
size_t size = classObjectSize(pHeader->staticFieldsSize);
newClass = (ClassObject*) dvmMalloc(size, ALLOC_NON_MOVING);
}
...
//設(shè)置字段對象
dvmSetFieldObject((Object *)newClass, OFFSETOF_MEMBER(ClassObject, classLoader), (Object *)classLoader);
newClass->pDvmDex = pDvmDex;
newClass->primitiveType = PRIM_NOT;
newClass->status = CLASS_IDX;
const DexTypeList* pInterfacesList;
//接口列表
pInterfacesList = dexGetInterfacesList(pDexFile, pClassDef);
if (pInterfacesList != NULL) {
//接口數(shù)量
newClass->interfaceCount = pInterfacesList->size;
//接口
newClass->interfaces = (ClassObject**) dvmLinearAlloc(classLoader,
newClass->interfaceCount * sizeof(ClassObject*));
//遍歷處理接口
for (i = 0; i < newClass->interfaceCount; i++) {
const DexTypeItem* pType = dexGetTypeItem(pInterfacesList, i);
newClass->interfaces[i] = (ClassObject*)(u4) pType->typeIdx;
}
dvmLinearReadOnly(classLoader, newClass->interfaces);
}
//加載靜態(tài)字段
if (pHeader->staticFieldsSize != 0) {
/* static fields stay on system heap; field data isn't "write once" */
int count = (int) pHeader->staticFieldsSize;
u4 lastIndex = 0;
DexField field;
//靜態(tài)字段名
newClass->sfieldCount = count;
//遍歷加載字段
for (i = 0; i < count; i++) {
dexReadClassDataField(&pEncodedData, &field, &lastIndex);
loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
}
}
//實(shí)例字段
if (pHeader->instanceFieldsSize != 0) {
int count = (int) pHeader->instanceFieldsSize;
u4 lastIndex = 0;
DexField field;
newClass->ifieldCount = count;
//遍歷加載實(shí)例字段
newClass->ifields = (InstField*) dvmLinearAlloc(classLoader,
count * sizeof(InstField));
for (i = 0; i < count; i++) {
dexReadClassDataField(&pEncodedData, &field, &lastIndex);
loadIFieldFromDex(newClass, &field, &newClass->ifields[i]);
}
dvmLinearReadOnly(classLoader, newClass->ifields);
}
...
//加載類方法
if (pHeader->directMethodsSize != 0) {
int count = (int) pHeader->directMethodsSize;
u4 lastIndex = 0;
DexMethod method;
newClass->directMethodCount = count;
newClass->directMethods = (Method*) dvmLinearAlloc(classLoader,
count * sizeof(Method));
//遍歷加載類方法
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
if (classMapData != NULL) {
const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
newClass->directMethods[i].registerMap = pMap;
/* TODO: add rigorous checks */
assert((newClass->directMethods[i].registersSize+7) / 8 ==
newClass->directMethods[i].registerMap->regWidth);
}
}
}
dvmLinearReadOnly(classLoader, newClass->directMethods);
}
//加載虛方法
if (pHeader->virtualMethodsSize != 0) {
int count = (int) pHeader->virtualMethodsSize;
u4 lastIndex = 0;
DexMethod method;
newClass->virtualMethodCount = count;
newClass->virtualMethods = (Method*) dvmLinearAlloc(classLoader,
count * sizeof(Method));
//遍歷加載虛方法
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->virtualMethods[i]);
if (classMapData != NULL) {
const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
newClass->virtualMethods[i].registerMap = pMap;
/* TODO: add rigorous checks */
assert((newClass->virtualMethods[i].registersSize+7) / 8 ==
newClass->virtualMethods[i].registerMap->regWidth);
}
}
}
dvmLinearReadOnly(classLoader, newClass->virtualMethods);
}
//保存源文件信息
newClass->sourceFile = dexGetSourceFile(pDexFile, pClassDef);
}
以上,像一些 Method 具體是如何解析她渴,可以參見loadMethodFromDex()@Class.cpp达址。其他的解析也可以自行深入查看。
解析完畢后趁耗,將 clazz 加入到全局 hash表
bool dvmAddClassToHash(ClassObject* clazz){
void* found;
u3 hash;
hash = dvmComputeUtf8Hash(clazz->descriptor);
//加鎖
dvmHashTableLock(gDvm.loadedClasses);
//@dalvik/vm/Hash.cpp 具體不分析了沉唠,自行研究
found = dvmHashTableLookup(gDvm.loadedClasses, hash, clazz, hashcmpClassByClass, true);
//釋放鎖
//dvmHashTableUnlock(gDvm.loadedClasses);
}
其實(shí)在上面去加載 class 時(shí),會(huì)先從全局 hash 中搜索苛败。
ClassObject* dvmLookupClass(const char* descriptor, Object* loader, bool unprepOkay){
...
found = dvmHashTableLookup(gDvm.loaderClasses, hash, &crit, hashcmpClassByCrit, false);
...
}
看完后自己是有個(gè)疑問的满葛,在添加到全局 hash 的時(shí)候,添加的是 ClassObject 對象罢屈,但是在搜索的時(shí)候確實(shí)以一個(gè)ClassMatchCriteria去尋找的嘀韧。
struct ClassMatchCriteria {
const char* descriptor;
Object* loader;
}
再來看 dvmHashTableLookup()是如何判斷搜索目標(biāo)一致性的,中間有一行
//Hash.cpp
(*cmpFunc)(pEntry->data, item) == 0
而 cmpFunc 是一個(gè)函數(shù)指針缠捌,而我們知道 pEntry->data 就是 ClassObject 對象锄贷,而 item 就是 ClassMatchCriteria 對象,現(xiàn)在來看 cmpFunc 這個(gè)函數(shù)指針曼月。
//class.cpp
static int hashCmpClassByCrit(const void* vclazz, const void* vcrit){
const ClassObject* clazz = (const ClassObject*) vclazz;
const ClassMatchCriteria* pCrit = (const ClassMatchCriteria*) vcrit;
bool match;
match = (strcmp(clazz->descriptor, pCrit->descriptor) == 0 &&
(clazz->classLoader == pCrit->loader ||
(pCrit->loader !=NULL && dvmLoaderInInitiatingList(clazz, pCrit->loader))));
return !match;
}
于是從源碼可以看到肃叶,一個(gè)類在 dvm 中裝載,是由其類的簽名和加載類的類加載器決定的十嘿。如果有一個(gè)不一致因惭,則認(rèn)識是兩個(gè)不同的ClassObject。
雙親委派模型規(guī)定了加載一個(gè)類的順序绩衷,所謂的加載器對于 DVM 來說地位都是一樣的蹦魔,可以認(rèn)為是與 類的descriptor共同作為 key 來標(biāo)志一個(gè) ClassObject