Android dex在內(nèi)存中的存放位置

Dalvik虛擬機(jī)對(duì)dex的加載過(guò)程的基礎(chǔ)上,我們來(lái)分析下面代碼中的第三步州袒。

/dalvik/vm/native/dalvik_system_DexFile.cpp

static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args,
    JValue* pResult)
{
    StringObject* sourceNameObj = (StringObject*) args[0];
    StringObject* outputNameObj = (StringObject*) args[1];
    DexOrJar* pDexOrJar = NULL;
    JarFile* pJarFile;
    RawDexFile* pRawDexFile;
    char* sourceName;
    char* outputName;

    sourceName = dvmCreateCstrFromString(sourceNameObj);
    if (outputNameObj != NULL)
        outputName = dvmCreateCstrFromString(outputNameObj);
    else
        outputName = NULL;
     
    // 1卓箫、嘗試把它當(dāng)做一個(gè)后綴為.dex的DEX文件進(jìn)行打開(kāi)厘贼,得到RawDexFile結(jié)構(gòu)數(shù)據(jù)
    // 2颂龙、如果打開(kāi)失敗,則把它當(dāng)做一個(gè)包含有classes.dex文件的Zip文件進(jìn)行打開(kāi)旺隙,得到JarFile結(jié)構(gòu)數(shù)據(jù)
    if (hasDexExtension(sourceName)
            && dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = true;
        pDexOrJar->pRawDexFile = pRawDexFile;
        pDexOrJar->pDexMemory = NULL;
    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
        ALOGV("Opening DEX file '%s' (Jar)", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = false;
        pDexOrJar->pJarFile = pJarFile;
        pDexOrJar->pDexMemory = NULL;
    }

    if (pDexOrJar != NULL) {
        pDexOrJar->fileName = sourceName;
        // 3、把pDexOrJar這個(gè)結(jié)構(gòu)體中的內(nèi)容加到gDvm中的userDexFile結(jié)構(gòu)的hash表中浆洗,以便dalvik以后的查找
        addToDexFileTable(pDexOrJar);
    } else {
        free(sourceName);
    }

    free(outputName);
    RETURN_PTR(pDexOrJar);
}

可以看到DexOrJar文件最終添加到gDvm中的userDexFile結(jié)構(gòu)的hash表中催束,下面我們來(lái)具體查看addToDexFileTable方法。

static void addToDexFileTable(DexOrJar* pDexOrJar) {
    /*
     * Later on, we will receive this pointer as an argument and need
     * to find it in the hash table without knowing if it's valid or
     * not, which means we can't compute a hash value from anything
     * inside DexOrJar. We don't share DexOrJar structs when the same
     * file is opened multiple times, so we can just use the low 32
     * bits of the pointer as the hash.
     */
    u4 hash = (u4) pDexOrJar;
    void* result;

    dvmHashTableLock(gDvm.userDexFiles);
    result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
            hashcmpDexOrJar, true);
    dvmHashTableUnlock(gDvm.userDexFiles);

    if (result != pDexOrJar) {
        ALOGE("Pointer has already been added?");
        dvmAbort();
    }

    pDexOrJar->okayToFree = true;
}

需要說(shuō)明的是伏社,gDvm是一個(gè)DvmGlobals結(jié)構(gòu)的全局變量抠刺。在DvmGlobals結(jié)構(gòu)中有一個(gè)成員HashTable* userDexFiles;

DvmGlobals在/dalvik/vm/Globals.h中

也就是說(shuō),userDexFiles是一個(gè)HashTabled的引用摘昌,HashTabled的結(jié)構(gòu)為:

/dalvik/vm/Hash.h

struct HashTable {
    int         tableSize;          /* must be power of 2 */
    int         numEntries;         /* current #of "live" entries */
    int         numDeadEntries;     /* current #of tombstone entries */
    HashEntry*  pEntries;           /* array on heap */
    HashFreeFunc freeFunc;
    pthread_mutex_t lock;
};

HashEntry* pEntries指向一個(gè)HashEntry的數(shù)組,HashEntry結(jié)構(gòu)體中的data變量存放的就是pDexOrJar速妖。

/dalvik/vm/Hash.h

struct HashEntry {
    u4 hashValue;
    void* data; //DexOrJar *pDexOrJar
};

上面代碼的關(guān)鍵就是dvmHashTableLookup方法,所以我們繼續(xù)查看該方法聪黎。

/dalvik/vm/Hash.cpp

void* dvmHashTableLookup(HashTable* pHashTable, u4 itemHash, void* item,
    HashCompareFunc cmpFunc, bool doAdd)
{
    HashEntry* pEntry;
    HashEntry* pEnd;
    void* result = NULL;

    assert(pHashTable->tableSize > 0);
    assert(item != HASH_TOMBSTONE);
    assert(item != NULL);

    /* jump to the first entry and probe for a match */
    pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)];
    pEnd = &pHashTable->pEntries[pHashTable->tableSize];
    while (pEntry->data != NULL) {
        if (pEntry->data != HASH_TOMBSTONE &&
            pEntry->hashValue == itemHash &&
            (*cmpFunc)(pEntry->data, item) == 0)
        {
            /* match */
            //ALOGD("+++ match on entry %d", pEntry - pHashTable->pEntries);
            break;
        }

        pEntry++;
        if (pEntry == pEnd) {     /* wrap around to start */
            if (pHashTable->tableSize == 1)
                break;      /* edge case - single-entry table */
            pEntry = pHashTable->pEntries;
        }

        //ALOGI("+++ look probing %d...", pEntry - pHashTable->pEntries);
    }

    if (pEntry->data == NULL) {
        if (doAdd) {
            pEntry->hashValue = itemHash;
            pEntry->data = item;
            pHashTable->numEntries++;

            /*
             * We've added an entry.  See if this brings us too close to full.
             */
            if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM
                > pHashTable->tableSize * LOAD_NUMER)
            {
                if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) {
                    /* don't really have a way to indicate failure */
                    ALOGE("Dalvik hash resize failure");
                    dvmAbort();
                }
                /* note "pEntry" is now invalid */
            } else {
                //ALOGW("okay %d/%d/%d",
                //    pHashTable->numEntries, pHashTable->tableSize,
                //    (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM);
            }

            /* full table is bad -- search for nonexistent never halts */
            assert(pHashTable->numEntries < pHashTable->tableSize);
            result = item;
        } else {
            assert(result == NULL);
        }
    } else {
        result = pEntry->data;
    }

    return result;
}

上面的操作就是將pDexOrJar以及它對(duì)應(yīng)的hashValue封裝到一個(gè)HashEntry罕容,然后將這個(gè)HashEntry存放到HashEntry* pEntries指向的HashEntry數(shù)組中去。

他們之間的整個(gè)引用過(guò)程如下圖所示:

dexlocation.png

也就是說(shuō)我們可以通過(guò)gDvm.userDexFiles找到具體DexOrJar的位置稿饰,然后通過(guò)DexOrJar的pRawDexFile定位到RawDexFile的位置锦秒,進(jìn)而通過(guò)RawDexFile的pDvmDex找到DvmDex的位置,最終就可以通過(guò)DvmDex的pDexFile來(lái)定位到DexFile的位置喉镰,它就是內(nèi)存中的.odex文件內(nèi)容旅择,它里面同時(shí)也包含了.dex的內(nèi)容。

參考文章:
http://bbs.pediy.com/thread-207190.htm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侣姆,一起剝皮案震驚了整個(gè)濱河市生真,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捺宗,老刑警劉巖柱蟀,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蚜厉,居然都是意外死亡长已,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門弯囊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)痰哨,“玉大人,你說(shuō)我怎么就攤上這事匾嘱〗锔” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵霎烙,是天一觀的道長(zhǎng)撬讽。 經(jīng)常有香客問(wèn)我蕊连,道長(zhǎng),這世上最難降的妖魔是什么游昼? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任甘苍,我火速辦了婚禮,結(jié)果婚禮上烘豌,老公的妹妹穿的比我還像新娘载庭。我一直安慰自己,他們只是感情好廊佩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布囚聚。 她就那樣靜靜地躺著,像睡著了一般标锄。 火紅的嫁衣襯著肌膚如雪顽铸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天料皇,我揣著相機(jī)與錄音谓松,去河邊找鬼。 笑死践剂,一個(gè)胖子當(dāng)著我的面吹牛鬼譬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逊脯,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拧簸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了男窟?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贾富,失蹤者是張志新(化名)和其女友劉穎歉眷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體颤枪,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汗捡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了畏纲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扇住。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盗胀,靈堂內(nèi)的尸體忽然破棺而出艘蹋,到底是詐尸還是另有隱情,我是刑警寧澤票灰,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布女阀,位于F島的核電站宅荤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏浸策。R本人自食惡果不足惜冯键,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庸汗。 院中可真熱鬧惫确,春花似錦、人聲如沸蚯舱。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晓淀。三九已至所袁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凶掰,已是汗流浹背燥爷。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懦窘,地道東北人前翎。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像畅涂,于是被迫代替她去往敵國(guó)和親港华。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容