1. 程式人生 > >Android培訓班 67 dex檔案開啟流程

Android培訓班 67 dex檔案開啟流程

               

從上面可知呼叫函式Dalvik_dalvik_system_DexFile_openDexFile來開啟Dex檔案,這個函式的原始碼如下:

staticvoid Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,

   JValue* pResult)

{

   StringObject* sourceNameObj =(StringObject*) args[0];

這行是輸入的Jar或Dex檔名引數。

   StringObject* outputNameObj =(StringObject*) args[1];

這行是輸出的檔名引數。

   int flags = args[2];

這行是處理的標示。

   DexOrJar* pDexOrJar = NULL;

   JarFile* pJarFile;

   RawDexFile* pRawDexFile;

   char* sourceName;

   char* outputName;

   if (sourceNameObj == NULL) {

       dvmThrowException("Ljava/lang/NullPointerException;",NULL);

       RETURN_VOID();

    }

這段程式碼是當輸入檔名稱為空物件時,就丟擲異常。

   sourceName =dvmCreateCstrFromString(sourceNameObj);

這行程式碼呼叫函式dvmCreateCstrFromStringjava字串轉換C字串,由於Java物件表示的字串並不能立即就使用到C語言裡,所以需要轉換才能使用。

   if (outputNameObj != NULL)

       outputName =dvmCreateCstrFromString(outputNameObj);

   else

       outputName = NULL;

這段程式碼是同樣把輸出字串轉換C字串。

   /*

    * We have to deal with the possibility thatsomebody might try to

    * open one of our bootstrap class DEXfiles.  The set of dependencies

    * will be different, and hence the resultsof optimization might be

    * different, which means we'd actually needto have two versions of

    * the optimized DEX: one that only knowsabout part of the boot class

    * path, and one that knows about everythingin it.  The latter might

    * optimize field/method accesses based on aclass that appeared later

    * in the class path.

    *

    * We can't let the user-defined classloader open it and start using

    * the classes, since the optimized form ofthe code skips some of

    * the method and field resolution that wewould ordinarily do, and

    * we'd have the wrong semantics.

    *

    * We have to reject attempts to manuallyopen a DEX file from the boot

    * class path.  The easiest way to do thisis by filename, which works

    * out because variations in name (e.g."/system/framework/./ext.jar")

    * result in us hitting a differentdalvik-cache entry.  It's also fine

    * if the caller specifies their own outputfile.

    */

   if(dvmClassPathContains(gDvm.bootClassPath, sourceName)) {

       LOGW("Refusing to reopen boot DEX'%s'\n", sourceName);

       dvmThrowException("Ljava/io/IOException;",

           "Re-opening BOOTCLASSPATH DEXfiles is not allowed");

       free(sourceName);

       RETURN_VOID();

    }

這段程式碼是判斷使用者是否載入系統目錄下面的Dex檔案,如果載入就要拒絕這樣的操作,因為系統啟動時已經載入了一份這樣的優化程式碼,沒有必要再次載入一次。

   /*

    * Try to open it directly as a DEX.  Ifthat fails, try it as a Zip

    * with a "classes.dex" inside.

    */

   if (dvmRawDexFileOpen(sourceName,outputName, &pRawDexFile, false) == 0) {

       LOGV("Opening DEX file '%s'(DEX)\n", sourceName);

       pDexOrJar = (DexOrJar*)malloc(sizeof(DexOrJar));

       pDexOrJar->isDex = true;

       pDexOrJar->pRawDexFile = pRawDexFile;

這段程式碼是嘗試載入Dex檔案,但基本不存在直接加Dex檔案的情況,因此在函式dvmRawDexFileOpen還是空函式,沒有實際的內容。

    }else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false)== 0) {

       LOGV("Opening DEX file '%s'(Jar)\n", sourceName);

       pDexOrJar = (DexOrJar*)malloc(sizeof(DexOrJar));

       pDexOrJar->isDex = false;

       pDexOrJar->pJarFile = pJarFile;

這段程式碼是載入Jar檔案,就是從這裡載入Dex檔案到快取裡。

    }else {

       LOGV("Unable to open DEX file'%s'\n", sourceName);

       dvmThrowException("Ljava/io/IOException;","unable to open DEX file");

    }

   if (pDexOrJar != NULL) {

       pDexOrJar->fileName = sourceName;

這行程式碼儲存檔名稱到Dex檔案物件裡。

       /* add to hash table */

       u4 hash = dvmComputeUtf8Hash(sourceName);

這行程式碼通過檔名稱計算HASH串,加速對檔案的查詢速度。

       void* result;

       dvmHashTableLock(gDvm.userDexFiles);

       result =dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,

                   hashcmpDexOrJar, true);

       dvmHashTableUnlock(gDvm.userDexFiles);

這段程式碼新增HASH表裡,以便後面查詢使用。

       if (result != pDexOrJar) {

           LOGE("Pointer has already beenadded?\n");

           dvmAbort();

       }

       pDexOrJar->okayToFree = true;

    }else

       free(sourceName);

   RETURN_PTR(pDexOrJar);

這行程式碼返回開啟的檔案物件。

}

這個函式是通過JAVA呼叫時輸入Dex檔名稱,然後載入Dex檔案,最後把這個檔名稱放到HASH表裡,然後返回開啟的物件。