天天看點

android app啟動過程(轉)Native程序的運作過程

一般程式的啟動步驟,可以用下圖描述。程式由核心加載分析,使用linker連結需要的共享庫,然後從c運作庫的入口開始執行。

android app啟動過程(轉)Native程式的運作過程

通常,native程序是由shell或者init啟動,啟動的過程如下:

Shell接收到指令,啟動一個程式,此時shell首先會fork一個新的程序

新fork的程序,通過execve系統調用,陷入到核心中,核心檢查和加載需要執行的二進制映像檔案,檢驗其合法性及權限。通常使用者态程序要啟動一個新的程式(如shell),fork後,execve要緊跟着執行,這樣會有更好的效率(由于使用COW技術,這樣可以避免頁表複制,而execve後,之前程序中的所有内容都是無用的,若execve緊跟fork後,可以避免COW引起的拷貝);

通常二進制檔案都會要依賴一些系統動态庫,此時kernel會啟動加載器/system/bin/linker,執行linker的__linker_init()

Linker的linker_init(),會分析二進制的elf檔案,加載依賴的動态庫檔案,然後轉入二進制映像的入口函數__start中執行

__start會調用C庫的初始化函數__libc_init()

__libc_init()會調用映像的main函數,這個main函數也就是使用者app的入口函數

main() 函數執行完畢後,通過exit()退出程序執行

需要注意的是,android bionic提供的加載器是/system/bin/linker,而普通linux系統用的glibc是/lib/ld-linux-xx.so.2。這也是為何其他linux平台同指令架構的二進制檔案,不能在android上運作的原因之一:啟動使用者程序的加載器這個程式運作的第一步就出錯了。

Java程序的啟動比較特殊,Java程序是zygote啟動的,zygote在folk程序之後,并沒有執行execve指令,是以是共享了zygote的代碼段和資料段。其它的java程序,可以看做都是zygote的克隆,克隆之後的程序,各自根再據自己的需求(java代碼),解釋java語言。

也就是說:Android的所有程序,從native角度看都是zygote。 其對應的程式都是 /system/bin/app_process,虛拟機是運作在其中的。

那為何java程序又如此的不同呢? 實際上,從native的角度看,不同的各種java程式,可以如此了解:隻是/system/bin/app_process 這個程式,因為不同的輸入(Java dex位元組碼)而引起的。

android app啟動過程(轉)Native程式的運作過程

上圖中,user APK實際上市zygote的一個克隆(啟動->進入main等之前的流程沒有畫出, app程序沒有這個步驟,是從zygote程序中克隆過來),差别主要在dvm虛拟機執行的java代碼的不同導緻的表現的行為差異巨大。

Java程序沒有執行exec調用,這樣有一個很大的好處:使用linux的COW(copy on Write)技術,就可以在多個java程序間,共享記憶體資源——主要是java的核心庫。

Java程式也可以使用native庫,此時的native庫需要通過dlopen來打開(即java中,使用System.loadLibrary()方法加載so庫,虛拟機對應會調用的C庫方法),dlopen加載so庫的過程中,依舊會通過linker分析處理so庫的elf資訊,加載其它依賴的動态庫。

(注:zygote實際上是/system/bin/app_process,zygote隻是app_process的别名)

http://www.cnblogs.com/lanrenxinxin/p/4943632.html