电竞比分网-中国电竞赛事及体育赛事平台

分享

Kitkat系列文章—OAT文件分析—Part2

 老匹夫 2014-02-22

Kitkat系列文章—OAT文件分析—Part2

分享到: 1


本文由 ImportNew - Peter Pan 翻譯自 google。如需轉(zhuǎn)載本文,請(qǐng)先參見(jiàn)文章末尾處的轉(zhuǎn)載要求。

這是關(guān)于最新Android版本Kitkat系列文章中的第二部分,我把它們寫在了+inovex GmbH上。在這一部分,我們將進(jìn)一步查看這種新的文件格式:ART運(yùn)行時(shí)的OAT,并且簡(jiǎn)要看一下它的垃圾回收機(jī)制(可以在這查看第一部分)。

3、進(jìn)一步挖掘:OAT文件分析

目前為止我們發(fā)現(xiàn)系統(tǒng)在設(shè)備上執(zhí)行了一些編譯。不僅是應(yīng)用,而且還有Android框架層的很大一部分被ART轉(zhuǎn)化成了oat文件。在這篇文章中,我們會(huì)努力找出oat到底是什么東西以及oat文件是如何生成的。

正如前提到的,所有已安裝應(yīng)用通過(guò)dex2oat編譯從而得已運(yùn)行?,F(xiàn)在讓我們進(jìn)一步查看一下這些生成的文件。那么,讓我們通過(guò)adb分析dex2oat后的一個(gè)結(jié)果,例如這個(gè)由SystemUI.apk轉(zhuǎn)化后的結(jié)果:

1
/data/dalvik-cache/system@priv-app@SystemUI.apk@classes.dex

便捷的“file”命令會(huì)返回:

1
2
3
4
5
6
7
8
9
10
11
12
system@priv-app@SystemUI.apk@classes.dex: ELF 32-bit LSB shared object, ARM, version 1 (GNU/Linux), dynamically linked, stripped
Wow.. that escalated quickly! With ART we go from java -> class -> dex -> oat, which is a shared object!
Further analysis with objdump shows the following:
system@priv-app@SystemUI.apk@classes.dex:
file format elf32-little
DYNAMIC SYMBOL TABLE:
00001000 g DO .rodata 0007d000 oatdata
0007e000 g DO .text 000a9f8f oatexec
00127f8b g DO .text 00000004 oatlastword

這里只確定了三個(gè)標(biāo)識(shí):元數(shù)據(jù)、執(zhí)行的起始與終止地址。很明顯的,新的運(yùn)行時(shí)把應(yīng)用當(dāng)作共享對(duì)象來(lái)進(jìn)行處理(!)。共享對(duì)象被動(dòng)態(tài)加載到虛擬機(jī)的上下文(很可能是先前解釋過(guò)的啟動(dòng)鏡像)中。通過(guò)查看源可以知道:實(shí)際上在運(yùn)行時(shí)調(diào)動(dòng)dlopen()來(lái)加載這些庫(kù)。

現(xiàn)在讓我們使用新的oatdump來(lái)獲取更多關(guān)于oat文件格式的知識(shí)。我的首次嘗試是在啟動(dòng)鏡像文件“/data/dalvik-cache/system@framework@boot.art@classes.dex”中使用oatdump。但是結(jié)果顯示這個(gè)文件的整個(gè)dump文件有1.6GB大小,這對(duì)于我將嘗試的這種分析而言是十分不方便,
所以我寫了一個(gè)小程序,雖然幾乎談不上有什么具體的功能,但是卻簡(jiǎn)單到足以理解這個(gè)OAT是如何工作的。源代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package de.inovex.arttest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int a = 100;
        a = foo(a);
    }
    private int foo(int a) {
        return a + 4711;
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

安裝之后,我們能夠在主機(jī)上查看它的編譯版本并在其上執(zhí)行objdump:

1
2
3
4
5
6
data@app@de.inovex.arttest.apk@classes.dex: file format elf32-little
DYNAMIC SYMBOL TABLE:
00001000 g DO .rodata 00001000 oatdata
00002000 g DO .text 00000238 oatexec
00002234 g DO .text 00000004 oatlastword

目前而言沒(méi)什么驚喜…它顯然是一個(gè)幾乎沒(méi)有任何功能、有0×238字節(jié)的應(yīng)用程序;-)

所以,讓我在文件”oatdump –oat-file= data@app@de.inovex.arttest.apk@classes.dex”上使用oatdump:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MAGIC:
oat
007
CHECKSUM:
0x7fcf3941
INSTRUCTION SET:
Thumb2
DEX FILE COUNT:
1
EXECUTABLE OFFSET:
0x00001000
IMAGE FILE LOCATION OAT CHECKSUM:
0xd950003d
IMAGE FILE LOCATION OAT BEGIN:
0x60a95000
...

這個(gè)header向我們展示了一些信息,包括文件內(nèi)容、體系結(jié)構(gòu)、一些完整性檢測(cè)值和一些想必是用來(lái)正確地移動(dòng)該庫(kù)的地址。有意思的部分在于這個(gè)dump輸出體中的方法名、dex碼和這個(gè)方法的ARM拆解碼。例如:foo方法的oat-dump輸出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1: int de.inovex.arttest.MainActivity.foo(int) (dex_method_idx=5)
DEX CODE:
0x0000: add-int/lit16 v0, v2, #+4711
0x0002: return v0
OAT DATA:
frame_size_in_bytes: 32
core_spill_mask: 0x00008060 (r5, r6, r15)
fp_spill_mask: 0x00000000
vmap_table: 0xf73b00da (offset=0x000010da)
v0/r5, v2/r6, v65535/r15
mapping_table: 0xf73b00d8 (offset=0x000010d8)
gc_map: 0xf73b00e0 (offset=0x000010e0)
CODE: 0xf73b00bd (offset=0x000010bd size=28)...
0xf73b00bc: e92d4060 push {r5, r6, lr}
0xf73b00c0: b085 sub sp, sp, #20
0xf73b00c2: 9000 str r0, [sp, #0]
0xf73b00c4: 9109 str r1, [sp, #36]
0xf73b00c6: 1c16 mov r6, r2
0xf73b00c8: f2412267 movw r2, #4711
0xf73b00cc: eb160502 adds.w r5, r6, r2
0xf73b00d0: 1c28 mov r0, r5
0xf73b00d2: b005 add sp, sp, #20
0xf73b00d4: e8bd8060 pop {r5, r6, pc}

DEXCODE部分體現(xiàn)的信息十分明顯:Java源碼中的整型a映射到虛擬寄存器v2中,加上常量4711,然后在v0上存儲(chǔ)結(jié)果并返回。

OAT DATA還沒(méi)完全被處理,但明顯的是“core_spill_mask”描述了被用在那個(gè)ARM方法里面?zhèn)鬟f數(shù)據(jù)的寄存器,“vmap_table”顯示出虛擬寄存器與真實(shí)寄存器的映射關(guān)系。

CODE區(qū)域顯示處理器事實(shí)上將要執(zhí)行的東西:起初,r2持有整型a;在新的棧楨創(chuàng)建之后,常量4711回到家整型a上;之后,結(jié)果被傳回來(lái)。然見(jiàn)到這些雖然不是驚喜,但也令人印象深刻!

同時(shí)還提示:上述過(guò)程中幾乎沒(méi)有任何優(yōu)化,更像是一個(gè)“gcc-00”。顯然不需要新的棧楨,整個(gè)“計(jì)算”通過(guò)單獨(dú)的一條指令完成:adds.w r0, r2, #4711。

最后,讓我們來(lái)總結(jié)一下OAT文件是什么:OAT是類似APK的一種預(yù)編譯文件,像共享庫(kù)一樣被正在運(yùn)行的進(jìn)程加載。OAT包含了APK中所有類的信息,比如方法、方法名、描述信息和偏移列表,可以在二進(jìn)制中定位這些方法。

4、留意堆處理:ART中的GC

ATR中的垃圾回收機(jī)制跟Dalvik極其相似,兩者都采用“標(biāo)記—清除”的方式保持堆清潔。詐一看令人十分驚奇,但事實(shí)上卻十分容易理解。從Java源碼,到類、dex,再到機(jī)器碼都可以追蹤。盡管代碼執(zhí)行的方式已經(jīng)改變,但數(shù)據(jù)結(jié)構(gòu)和對(duì)象引用卻依然保持不變。因此,垃圾回收進(jìn)程可以用Dalvik相同的方式進(jìn)行回收。

對(duì)源art/runtime/gc的簡(jiǎn)單了解可以發(fā)現(xiàn)ART使用了4種不同類型的GC。它們可以并行,也可以被列舉出來(lái)釋放堆空間:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// The type of collection to be performed. The ordering of the enum matters, it
// is used to
// determine which GCs are run first.
enum GcType {
    // Placeholder for when no GC has been performed.
    kGcTypeNone,
    // Sticky mark bits GC that attempts to only free objects allocated since
    // the last GC.
    kGcTypeSticky,
    // Partial GC that marks the application heap but not the Zygote.
    kGcTypePartial,
    // Full GC that marks and frees in both the application and Zygote heap.
    kGcTypeFull,
    // Number of different GC types.
    kGcTypeMax,
};

GC通過(guò)上面枚舉的次序進(jìn)行循環(huán),直到有足夠可用的空間來(lái)分配需要的內(nèi)存:

1
2
3
4
art/runtime/gc/heap.cc
// Loop through our different Gc types and try to Gc until we get enough free memory.
for (size_t i = static_cast<size_t>(last_gc) + 1;
i < static_cast<size_t>(collector::kGcTypeMax); ++i) {...

如果這個(gè)程序失敗了,系統(tǒng)會(huì)通過(guò)增大堆空間等方式再次嘗試分配。但這完全是一個(gè)標(biāo)準(zhǔn)程序,沒(méi)有任何不同于Dalvik垃圾回收的地方,至少我沒(méi)有發(fā)現(xiàn)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多