編輯:關於Android編程
邏輯上,可以把dex文件分成3個區,頭文件、索引區和數據區。索引區的ids後綴為identifiers的縮寫。
header
dex文件裡的header。除了描述.dex文件的文件信息外,還有文件裡其他各個區域的索引。
(1)magic value,這8個字節一般是常量,為了使.dex文件能夠被識別出來,它必須出現在.dex文件的最開頭的位置。
(2)checksum和signature.文件校驗碼,使用alder32算法校驗文件出去maigc,checksum外余下的所有文件區域,用於校驗文件錯誤。Signature,使用SHA-1算法hash除去magic,checksum和signature外余下的所有文件區域。
(3)file_size:Dex文件的大小。
其余的屬性,因為在加固中沒有用到。這裡就不對它們進行過多解釋。
odex是OptimizedDEX的縮寫,表示經過優化的dex文件。存放在/data/dalvik-cache目錄下。由於Android程序的apk文件為zip壓縮包格式,Dalvik虛擬機每次加載它們時需要從apk中讀取classes.dex文件,這樣會耗費很多cpu時間,而采用odex方式優化的dex文件,已經包含了加載dex必須的依賴庫文件列表,Dalvik虛擬機只需檢測並加載所需的依賴庫即可執行相應的dex文件,這大大縮短了讀取dex文件所需的時間。
不過,這個優化過程會根據不同設備上Dalvik虛擬機的版本、Framework庫的不同等因素而不同。在一台設備上被優化過的ODEX文件,拷貝到另一台設備上不一定能夠運行。
Odex文件的結構可以理解為dex文件的一個超集。它的結構如下圖所示,odex文件在dex文件頭部添加了一些數據,然後在dex文件尾部添加了dex文件的依賴庫以及一些輔助數據。
Dalvik虛擬機將dex文件映射到內存中後是Dalvik格式,在Android系統源碼的dalvik/libdex/DexFile.h文件中它的定義如下。
DexFile結構中存入的多為其他結構的指針。DexFile最前面的DexOptHeader就是odex的頭,DexLink以下的部分被成為auxillary section,即輔助數據段,它記錄了dex文件被優化後添加的一些信息。然而,DexFile結構描述的是加載進內存的數據結構,還有一些數據是不會加載進內存的,經過分析,odex文件結構定義整理如下.
Struct ODEXFile{
DexOptHeader header; /*odex文件頭*/
DEXFile dexfile; /*dex文件*/
Dependences deps; /*依賴庫列表*/
ChunkDexClassLookup lookup; /*類查詢結構*/
ChunkRegisterMapPool mappool; /*映射池*/
ChunkEnd end;/*結束標志*/
};
ODEXFile的文件頭DexOptHeader在DexFile.h文件中定義如下.
struct DexOptHeader{
u1 magic[8]; /*odex版本標識 */
u4 dexOffset; /* dex文件頭偏移*/
u4 dexLength;/* dex文件總長度*/
u4 depsOffset; /*odex依賴庫列表偏移*/
u4 depsLength;/*依賴庫列表總長度*/
u4 optOffset; /*輔助數據偏移*/
u4 optLength; /*輔助數據總長度*/
u4 flags ; /*標志*/
u4 checksum; /*依賴庫與輔助數據的校驗和*/
};
Android提供了一個專門驗證與優化dex文件的工具dexopt。其源碼位於Android系統源碼的dalvik/dexopt目錄下,Dalvik虛擬機在加載一個dex文件時,通過指定的驗證與優化選項來調用dexopt進行相應的驗證與優化操作。
dexopt的主程序為OptMain.cpp,其中處理apk/jar/zip文件中的classes.dex的函數為extractAndProcessZip(),extractAndProcessZip()首先通過dexZipFindEntry()函數檢查目標文件中是否擁有class.dex,如果沒有就失敗返回,成功的話就調用dexZipGetEntryInfo()函數來讀取classes.dex的時間戳與crc校驗值,如果這一步沒有問題,接著調用dexZipExtractEntryTo-File()函數釋放classes.dex為緩存文件,然後開始解析傳遞過來的驗證與優化選項,驗證選項使用“v=”指出,優化選項使用“o=”指出。所有的預備工作都做完後,調用dvmPrepForDexOpt()函數啟動一個虛擬機進程,在這個函數中,優化選項dexOptMode與驗證選項varifyMode被傳遞到了全局DvmGlobals結構gDvm的dexOptMode與classVerifyMode字段中。這時候所有的初始化工作已經完成,dexopt調用dvmContinueOptimization()函數開始真正的驗證和優化工作。
dvmContinueOptimization()函數的調用鏈比較長。首先從OptMain.cpp轉移到、dalvik/vm/analysis/DexPrepare.cpp,因為這裡有dvmContinueOptimization()函數的實現。函數首先對dex文件做簡單的檢查,確保傳遞進來的目標文件屬於dex或odex,接著調用mmap()函數將整個文件映射到內存中,然後根據gDvm的dexOptMode與classVerifyMode字段來設置doVarify與doOpt兩個布爾值,接著調用rewriteDex()函數來重寫dex文件,這裡的重寫內容包括字符調整、結構重新對齊、類驗證信息以及輔助數據。rewriteDex()函數調用dexSwapAndVerify()調整字節序,接著調用dvmDexFileOpenPartial()創建DexFile結構,dvmDexFileOpenPartial()函數的實現在Android系統源碼dalvik/vm/DvmDex.cpp文件中,該函數調用dexFileParse()函數解析dex文件,dexFileParse()函數讀取dex文件的頭部,並根據需要調用驗證dexComputeChecksum()函數或調用dexComputeOptChecksum()函數來驗證dex或odex文件愛你頭的checksum與signature字段。
接著回到DvmDex.cpp文件繼續看代碼,當驗證成功後,dvmDexFileOpenPartial()函數調用allocateAuxStructures()函數設置DexFile結構輔助數據的相關字段,最後執行完後返回到rewriteDex()函數。rewriteDex()接下來調用loadAllClasses()加載dex文件中所有的類,如果這一步失敗了,程序等不到後面的優化與驗證就退出了,如果沒有錯誤發生,會調用verifyAndOptimizeClasses()函數進行真正的驗證工作,這個函數會調用verifyAndOptimizeClass()函數來優化與驗證具體的類,而verifyAndOptimizeClass()函數會細分這些工作,調用dvmVerifyClass()函數進行驗證,再調用dvmOptimizeClass()函數進行優化。
dvmVerifyClass()函數的實現代碼位於Android系統源碼的dalvik/vm/analysis/DexVerify.cpp文件中。這個函數調用verifyMethod()函數對類的所有直接方法與虛方法進行驗證,verifyMethod()函數具體的工作是先調用verifyInstructions()函數來驗證方法中的指令及其數據的正確性,再調用dvmVerifyCodeFlow()函數來驗證代碼流的正確性。
dvmOptimizeClass()函數的實現代碼位於Android系統源碼的dalvik/vm/analysis/Optimize.cpp文件愛你中。這個函數調用optimizeMethod()函數對類的所有直接方法與虛方法進行優化,優化的主要工作是進行“指令替換”,替換原則的優先級為“volatile”替換-正確性替換-高性能替換。比如指令iget-wide會根據優先級替換為“volatile”形式的iget-wide-volatile,而不是高性能的iget-wide-quick.
rewriteDex函數返回後,會再次調用dvmDexFileOpenPartial()來驗證odex文件,接著調用dvmGenerateRegisterMaps()函數來填充輔助數據區結構,填充結構完成後,接下來調用updateChecksum()函數重寫dex文件愛你的checksum值,再往下就是writeDependencies()與writeOptData()了。
private TextView tvTime; private EditText inputTv; private Button btnHQ,btnBG,
在學習新內容之前,我們先來弄清楚兩個問題:1 . 什麼是ViewGroup?ViewGroup是一種容器。它包含零個或以上的View及子View。2 . ViewGrou
0.首先,先給出一張效果gif圖。1.貝塞爾曲線原理及相關公式參考:http://www.jianshu.com/p/c0d7ad796cee 作者:許方鎮。2.原理:計
這周繼續我的Blog,前面幾篇博文簡單的介紹了閱讀Android FW的源碼所需要的基礎知識,主要和C++相關。從這篇博文開始將會和大家一起學
效果圖:1、實現列表頭部的圖片輪播,方式:給RecyclerView添加