ART學(xué)習(xí)總結(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ù)來進一步學(xué)習(xí)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簡要介紹和學(xué)習(xí)計劃
3.Android ART Oat文件格式簡析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市魂务,隨后出現(xiàn)的幾起案子曼验,更是在濱河造成了極大的恐慌泌射,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鬓照,死亡現(xiàn)場離奇詭異熔酷,居然都是意外死亡,警方通過查閱死者的電腦和手機豺裆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進店門拒秘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臭猜,你說我怎么就攤上這事躺酒。” “怎么了蔑歌?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵羹应,是天一觀的道長。 經(jīng)常有香客問我次屠,道長园匹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任劫灶,我火速辦了婚禮裸违,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浑此。我一直安慰自己累颂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布凛俱。 她就那樣靜靜地躺著紊馏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蒲犬。 梳的紋絲不亂的頭發(fā)上朱监,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天,我揣著相機與錄音原叮,去河邊找鬼赫编。 笑死,一個胖子當(dāng)著我的面吹牛奋隶,可吹牛的內(nèi)容都是我干的擂送。 我是一名探鬼主播,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼唯欣,長吁一口氣:“原來是場噩夢啊……” “哼嘹吨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起境氢,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蟀拷,失蹤者是張志新(化名)和其女友劉穎碰纬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體问芬,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡悦析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了此衅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片强戴。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖炕柔,靈堂內(nèi)的尸體忽然破棺而出酌泰,到底是詐尸還是另有隱情,我是刑警寧澤匕累,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站默伍,受9級特大地震影響欢嘿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜也糊,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一炼蹦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狸剃,春花似錦掐隐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至僧凰,卻和暖如春探颈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背训措。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工伪节, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绩鸣。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓怀大,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呀闻。 傳聞我的和親對象是個殘疾皇子化借,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,442評論 2 359

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