
移動安全的學習離不開對Android加載流程的分析,包括Android虛擬機,Android打包,啟動流程等...
這篇文章 就對Android的一些基本加載進行學習。
Android虛擬機
Android開發中接觸的是與Java虛擬機類似的的Dalvik虛擬機和ART虛擬機
Dalvik虛擬機
什么是Dalvik虛擬機
Dalvik虛擬機簡稱Dalvik VM或者DVM,是Google專門為Android平台開發的虛擬機,它運行在Android運行庫中,需要注意的是DVM並不是一個Java虛擬機(Jvm虛擬機)
DVM與JVM虛擬機的區別
1.基於的架構不同
Jvm基於棧,需要去棧中讀寫數據,所需要的指令會更多,這樣會導致速度慢,對於性能有限的移動設備,顯然不是很適合。
DVM基於寄存器,它沒有基於棧的虛擬機在拷貝數據而使用的大量的出入棧指令,同時指令更緊湊更簡潔。但是由於顯示指定了操作數,所以基於寄存器的指令會比基於棧的指令要大,但是由於指令數量的減少,總的代碼數不會增加多少。
2.執行的字節碼不同
JVM虛擬機中Java代碼從編寫到執行的過程:
1) 編寫Java代碼
2) 所有的Java代碼通過Java編譯器(javac)編譯成java字節碼,即.class文件
3) Java字節碼在Java虛擬機上被解釋成機器語言后,程序執行

DVM虛擬機Java代碼從編寫到執行的過程:
1) 編寫Java代碼
2) 所有的Java代碼通過Java編譯器(javac)編譯成java字節碼,即.class文件
3) Java字節碼通過Android的dx工具轉換成Dalvik字節碼,即.dex文件
4) Dalvik字節碼在Dalvik虛擬機上運行

文件結構對比圖

ART虛擬機
ART虛擬機是Android4.4發布的,用來替換Dalvik虛擬機,Android 4.4默認采用的還是DVM,不過系統會提供一個選項來開啟ART。在Android 5.0時,默認采用ART。
ART與DVM虛擬機的區別
1.DVM虛擬機中應用每次運行時,字節碼都需要通過即時編譯器轉換成機器碼,這會使應用的運行效率降低,而在ART中,系統在安裝應用時會進行一次預編譯,將字節碼預先編譯成機器碼並存儲在本地,這樣應用每次運行時就不需要執行編譯,提升了運行效率。
2.ART由於將字節碼預先編譯成機器碼存儲在本地,所以ART虛擬機占用空間比Dalvik大。
Apk打包流程
Android構建系統編譯的應用資源和源代碼,然后將它們打包成可測試、部署、簽署和分發的 APK。
一般使用 Android Studio開發的時候使用Gradle構建工具包來自動執行和管理構建流程,同時也可以靈活地自定義構建配置。
在了解Android打包流程之前,先查看一個apk包內容,可以知道它里面都有哪些文件組成:

| 文件或目錄 | 說明 |
|---|---|
| assets文件夾 | 存放需要打包到APK中的靜態文件 |
| lib文件夾 | 存放應用程序依賴的native庫文件 |
| META-INF文件夾 | 1.該目錄下存放的是簽名信息,用來保證apk包的完整性和系統的安全性 2.CERT.RSA 這個文件保存了簽名和公鑰證書 3.CERT.SF 這個是對每個文件的頭3行進行SHA1 hash 4.MANIFEST.MF 版本號以及每一個文件的哈希值(BASE64),包括資源文件。這個是對每個文件的整體進行SHA1(hash)。 |
| res文件夾 | 存放資源文件的目錄(圖片,文本,xml布局) |
| AndroidManifest.xml | 一個清單文件,它描述了應用的名字、版本、權限、注冊的服務等信息。 |
| classes.dex | java源碼編譯經過編譯后生成的dalvik字節碼文件,主要在Dalvik虛擬機上運行的主要代碼部分 |
| resources.arsc | 用來記錄資源文件和資源ID之間的映射關系,用來根據資源ID尋找資源 |
知道了apk包的內容,會更好的理解Android打包流程:

先了解一下各個步驟使用的工具(綠色框):
| 名稱 | 功能介紹 | 在操作系統中的路徑 |
|---|---|---|
| aapt | Android資源打包工具,並生成R.java和resources.arsc文件 | ${ANDROID_SDK_HOME}/platform-tools/appt |
| aidl | Android接口描述語言.aidl文件轉化為.java文件的工具 | ${ANDROID_SDK_HOME}/platform-tools/aidl |
| javac | Java Compiler(編譯器)將R.java、AIDL接口生成的java文件、應用代碼java文件編譯成.class文件。 |
${JDK_HOME}/javac或/usr/bin/javac |
| dex | 轉化.class文件為Davik VM能識別的.dex文件 | ${ANDROID_SDK_HOME}/platform-tools/dx |
| apkbuilder | 將資源文件和.dex文件生成未簽名的.apk文件 |
${ANDROID_SDK_HOME}/tools/opkbuilder |
| jarsigner | .jar文件的簽名工具 | ${JDK_HOME}/jarsigner或/usr/bin/jarsigner |
| zipalign | 字節碼對齊工具 |
${ANDROID_SDK_HOME}/tools/zipalign |
整個apk打包流程為:
- 通過aapt工具進行資源文件(包括AndroidManifest.xml、布局文件、各種xml資源等)的打包,生成R.java文件。
- 通過aidl工具處理AIDL文件,生成相應的Java文件。
- 通過Javac工具編譯項目源碼,生成Class文件。
- 通過dx工具將所有的Class文件轉換成DEX文件,該過程主要完成Java字節碼轉換成Dalvik字節碼,壓縮常量池以及清除冗余信息等工作。
- 通過apkbuilder工具將資源文件、DEX文件打包生成APK文件。
- 利用jarsigner對生成的APK文件進行簽名。
- 如果是正式版的APK,還會利用ZipAlign工具進行對齊處理,對齊的過程就是將APK文件中所有的資源文件舉例文件的起始距離都偏移4字節的整數倍,這樣通過內存映射訪問APK文件的速度會更快。
-------------------------------------------------------------------
具體每一步打包流程為:
1. aapt階段:
使用aapt來打包res資源文件,生成R.java、resources.arsc和res文件(二進制 & 非二進制如res/raw和pic保持原樣)
- res目錄,有9種子目錄
- R.java文件。里面擁有很多個靜態內部類,比如layout,string等。每當有這種資源添加時,就在R.java文件中添加一條靜態內部類里的靜態常量類成員,且所有成員都是int類型。
- resources.arsc文件。這個文件記錄了所有的應用程序資源目錄的信息,包括每一個資源名稱、類型、值、ID以及所配置的維度信息。我們可以將這個文件想象成是一個資源索引表,這個資源索引表在給定資源ID和設備配置信息的情況下,能夠在應用程序的資源目錄中快速地找到最匹配的資源。
2. aidl階段:
AIDL,Android接口定義語言,Android提供的IPC的一種獨特實現。這個階段處理.aidl文件,生成對應的Java接口文件。
3. Java Compiler階段:
通過Java Compiler編譯R.java、Java接口文件、Java源文件,生成.class文件。
4. dex階段:
通過dex命令,將.class文件和第三方庫中的.class文件處理生成classes.dex。
5. apkbuilder階段:
將 classes.dex,resources.arsc,res文件夾(res/raw資源被原裝不動地打包進APK之外,其它的資源都會被編譯或者處理)、Other Resources(assets文件夾),AndroidManifest.xml打包成apk文件。
6. Jarsigner階段
對apk進行簽名,可以進行Debug和Release 簽名。
7. zipalign階段
release mode 下使用 aipalign 進行align,即對簽名后的apk進行對齊處理。
Zipalign是一個android平台上整理APK文件的工具,它對apk中未壓縮的數據進行4字節對齊,對齊后就可以使用mmap函數讀取文件,可以像讀取內存一樣對普通文件進行操作。如果沒有4字節對齊,就必須顯式的讀取,這樣比較緩慢並且會耗費額外的內存。
在 Android SDK 中包含一個名為 zipalign 的工具,它能夠對打包后的 app 進行優化。 其位於 SDK 的 \build-tools\23.0.2\zipalign.exe 目錄下
Android啟動流程
這里不再多說,推一下大佬博客:
https://www.jianshu.com/p/9f978d57c683
講的很詳細
Android的通信方式
IPC(Inter-Process Communication, 進程間通信)分類:
Linux: 管道、消息隊列、共享內存、Socket、信號量、信號這些IPC機制。
Android:提供了Binder IPC機制。
對於Android來說:
1)同一進程內線程間通信:Handler消息機制。
2)進程間通信:Binder IPC機制,當然也包含有Socket通信。
system server、media server以及上層App之間更多的是采用Binder IPC方式來完成跨進程間的通信。
Zygote進程的IPC采用的是Socket機制。
如果想更了解Android的通信方式,請移步 https://www.jianshu.com/p/a4b2a3bc3cb2
APP啟動流程,從點擊桌面開始

啟動流程:
①點擊桌面App圖標,Launcher進程采用Binder IPC向system_server進程發起startActivity請求;
②system_server進程接收到請求后,向zygote進程發送創建進程的請求;
③Zygote進程fork出新的子進程,即App進程;
④App進程,通過Binder IPC向sytem_server進程發起attachApplication請求;
⑤system_server進程在收到請求后,進行一系列准備工作后,再通過binder IPC向App進程發送scheduleLaunchActivity請求;
⑥App進程的binder線程(ApplicationThread)在收到請求后,通過handler向主線程發送LAUNCH_ACTIVITY消息;
⑦主線程在收到Message后,通過發射機制創建目標Activity,並回調Activity.onCreate()等方法。
⑧到此,App便正式啟動,開始進入Activity生命周期,執行完onCreate/onStart/onResume方法,UI渲染結束后便可以看到App的主界面。
啟動流程:
(1)創建進程:
①先從Launcher的startActivity()方法,通過Binder通信,調用ActivityManagerService的startActivity方法。
②一系列折騰,最后調用startProcessLocked()方法來創建新的進程。
③該方法會通過前面講到的socket通道傳遞參數給Zygote進程。Zygote孵化自身。調用ZygoteInit.main()方法來實例化ActivityThread對象並最終返回新進程的pid。
④調用ActivityThread.main()方法,ActivityThread隨后依次調用Looper.prepareLoop()和Looper.loop()來開啟消息循環。
更直白的流程解釋:

①App發起進程:當從桌面啟動應用,則發起進程便是Launcher所在進程;當從某App內啟動遠程進程,則發送進程便是該App所在進程。發起進程先通過binder發送消息給system_server進程;
②system_server進程:調用Process.start()方法,通過socket向zygote進程發送創建新進程的請求;
③zygote進程:在執行ZygoteInit.main()后便進入runSelectLoop()循環體內,當有客戶端連接時便會執行ZygoteConnection.runOnce()方法,再經過層層調用后fork出新的應用進程;
④新進程:執行handleChildProc方法,最后調用ActivityThread.main()方法。
(2)綁定Application:
①上面創建進程后,執行ActivityThread.main()方法,隨后調用attach()方法。
②將進程和指定的Application綁定起來。這個是通過上節的ActivityThread對象中調用bindApplication()方法完成的。該方法發送一個BIND_APPLICATION的消息到消息隊列中, 最終通過handleBindApplication()方法處理該消息. 然后調用makeApplication()方法來加載App的classes到內存中。
更直白的流程解釋:

(3)顯示Activity界面:
經過前兩個步驟之后, 系統已經擁有了該application的進程。 后面的調用順序就是普通的從一個已經存在的進程中啟動一個新進程的activity了。
實際調用方法是realStartActivity(), 它會調用application線程對象中的scheduleLaunchActivity()發送一個LAUNCH_ACTIVITY消息到消息隊列中, 通過 handleLaunchActivity()來處理該消息。
在 handleLaunchActivity()通過performLaunchActiivty()方法回調Activity的onCreate()方法和onStart()方法,然后通過handleResumeActivity()方法,回調Activity的onResume()方法,最終顯示Activity界面。

Binder通信

