ART學習總結(jié)


一、概述

ART是Android平臺上的新一代運行時,用來代替dalvik。它主要采用了AOT的方法,在apk安裝的時候?qū)alvikbytecode一次性編譯成arm本地指令(但是這種AOT與c語言等還是有本質(zhì)不同的,還是需要虛擬機的環(huán)境支持),這樣在運行的時候就無需進行任何解釋或編譯便可直接執(zhí)行,節(jié)省了運行時間,提高了效率,但是在一定程度上使得安裝的時間變長,空間占用變大。(本文所有時序圖均基于Android M)


二、OAT文件

簡單的說,oat文件是嵌套在一個elf文件的格式中的。在elf文件的動態(tài)符號表中有三個重要的符號:oatdata、oatexec、oatlastword,分別表示oat的數(shù)據(jù)區(qū),oat文件中的native code和結(jié)束位置。

guoqifa@guoqifa:~$ readelf -s system@priv-app@Mms@Mms.apk@classes.dex
Symbol table '.dynsym' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000001000 0x95b000 OBJECT  GLOBAL DEFAULT    4 oatdata
     2: 000000000095c000 0xb3a4c0 OBJECT  GLOBAL DEFAULT    5 oatexec
     3: 00000000014964bc     4 OBJECT  GLOBAL DEFAULT    5 oatlastword

這些關(guān)系結(jié)構(gòu)在圖中說明的很清楚,簡單理解就是在oatdata中,保存有原來的dex文件內(nèi)容,在頭部還保留了尋址到dex文件內(nèi)容的偏移地址和指向?qū)?yīng)的oat class偏移,oat class中還保存了對應(yīng)的native code的偏移地址,這樣也就間接的完成了dexbytecode和native code的對應(yīng)關(guān)系。具體請參考:Android ART Oat文件格式簡析(上)Android ART Oat文件格式簡析(下)Android運行時ART加載OAT文件的過程分析. 也可自行分析 art\runtime\Oat_file.cc文件中OatFile::Setup()函數(shù)來進一步學習OAT文件。(下圖來源老羅博客)

oat文件格式

三、編譯

apk在安裝時使用dex2oat來編譯。大概流程如下圖所示,有兩種后端編譯模式,可選的是所謂快模式(Quick)或優(yōu)化模式(Optimizing)。如果沒有特別指定的話,編譯鏡像image使用快模式,而編譯一般的應(yīng)用程序則使用優(yōu)化模式。

dex2oat compile

什么是編譯器的后端呢?其實這是LLVM引入的概念。所有的程序先用前端翻譯成中間表示層,然后進行優(yōu)化,最后用后端將優(yōu)化過的中間表示層代碼編譯成平臺相關(guān)的代碼。Android雖然沒有直接用LLVM編譯器(以前也確實用過,但從6.0開始就廢棄掉了),但是借鑒了這種編譯器的設(shè)計結(jié)構(gòu)。值得一提的是,如果使用優(yōu)化模式,則一定是用PIC模式進行編譯。

更具體的compile時序圖如下(該時序圖只繪出quick編譯模式),可自行分析該流程。


Compile Image

四、類加載

ART類的加載通過ClassLinker::DefineClass()函數(shù)來完成。該函數(shù)會分別調(diào)用InsertClass()、LoadClass()、LinkClass()來執(zhí)行類的加載。

InsertClass()主要是把該類插入class_table_中,方便下次FindClass時直接從LookupClass()中返回結(jié)果。LoadClass()用來從指定的DEX文件中加載指定的類,并初始化一個Class對象,Class對象包含了一系列的ArtField對象和ArtMethod對象。LinkClass()用來動態(tài)綁定虛函數(shù)和接口函數(shù)。

類加載完成后,得到的是一個Class對象。這個Class對象關(guān)聯(lián)有一系列的ArtField對象和ArtMethod對象。其中,ArtField對象描述的是成員變量,而ArtMethod對象描述的是成員函數(shù)。對于每一個ArtMethod對象,它都有一個解釋器入口點和一個本地機器指令入口點。這樣,無論一個類方法是通過解釋器執(zhí)行,還是直接以本地機器指令執(zhí)行,我們都可以以統(tǒng)一的方式來進行調(diào)用。

關(guān)于類的加載可參考Android運行時ART加載類和方法的過程分析

Load Class

五、方法調(diào)用

Zygote孵化應(yīng)用進程后便會從入口AndroidRuntime.start()進入運行時,進入Java世界。

CallStaticVoidMethod

ART方法調(diào)用如上圖所示,最終調(diào)用到ArtMethod::Invoke()。ArtMethod正是前面類加載章節(jié)中提到的ArtMethod對象,“它都有一個解釋器入口點和一個本地機器指令入口點”,Invoke()函數(shù)正是通過art_quick_invoke_stub()或art_quick_invoke_static_stub()來調(diào)用oat文件中的native code的。art_quick_invoke_stub()是平臺相關(guān)的匯編函數(shù),比如我的機器該函數(shù)定義在art/runtime/arch/arm64/quick_entrypoints_arm64.S文件中。更多方法調(diào)用的分析請參考Android運行時ART執(zhí)行類方法的過程分析.

總結(jié):通過查找相關(guān)的oat文件,得到所需要的類和方法,并將其對應(yīng)的native code的位置放入ArtMethod結(jié)構(gòu),最后通過Invoke成員完成調(diào)用。


六、JNI調(diào)用

1. Java調(diào)用native方法

ArtMethod對象與真實執(zhí)行的代碼鏈接的過程主要是通過LinkCode()函數(shù)執(zhí)行的。

void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class,
                           uint32_t class_def_method_index) {
  ......
  if (method->IsNative()) {
    // Unregistering restores the dlsym lookup stub.
    method->UnregisterNative();
   ......
}
void ArtMethod::UnregisterNative() {
  CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
  // restore stub to lookup native pointer via dlsym
  RegisterNative(GetJniDlsymLookupStub(), false);
}

GetJniDlsymLookupStub()函數(shù)返回平臺相關(guān)的art_jni_dlsym_lookup_stub()匯編函數(shù)指針,RegisterNative()將該匯編函數(shù)指針注冊到ArtMethod中,以上是鏈接過程。

待JNI調(diào)用時便會執(zhí)行到匯編art_jni_dlsym_lookup_stub()函數(shù),該函數(shù)會繼續(xù)調(diào)用artFindNativeMethod()函數(shù)。

art_jni_dlsym_lookup_stub
extern "C" void* artFindNativeMethod(Thread* self) {
  DCHECK_EQ(self, Thread::Current());
#endif
  Locks::mutator_lock_->AssertNotHeld(self);  // We come here as Native.
  ScopedObjectAccess soa(self);

  ArtMethod* method = self->GetCurrentMethod(nullptr);
  DCHECK(method != nullptr);

  // Lookup symbol address for method, on failure we'll return null with an exception set,
  // otherwise we return the address of the method we found.
  void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
  if (native_code == nullptr) {
    DCHECK(self->IsExceptionPending());
    return nullptr;
  } else {
    // Register so that future calls don't come here
    method->RegisterNative(native_code, false);
    return native_code;
  }
}

artFindNativeMethod()函數(shù)就是查找到相應(yīng)方法的native code,然后再次注冊到ArtMethod中,這樣以后再執(zhí)行的時候就直接跳到了native code執(zhí)行了。

2. native調(diào)用Java

native調(diào)用Java是通過JNIEnv->FindClass()、JNIEnv->GetStaticMethodID()、JNIEnv->CallVoidMethod()來查找類,得到相應(yīng)的方法的ID,然后通過此ID去調(diào)用。最終如上面第五章方法調(diào)用時序圖所示,調(diào)用的是ArtMethod::Invoke()。即JNI的這些API其實還是做了一遍ART的類加載和初始化及調(diào)用的過程。


七、參考文章

1.也來看看Android的ART運行時
2.Android運行時ART簡要介紹和學習計劃
3.Android ART Oat文件格式簡析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

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