歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android app啟動過程

Native進程的運行過程

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

 

 

通常,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進程的啟動比較特殊,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字節碼)而引起的。

上圖中,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的別名)

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved