第十四章 android啓動過程詳解
14.1 系統的啓動過程
在android中,在Bootloader記載系統映像後,會通過 system\core\rootdir\ 目錄下的 init.rc 腳本進行初始化配置。
在init.rc中可以配置系統時區,設置日誌等級,設置全局環境變量,掛載文件系統,初始化網絡配置,配置系統屬性,啓動守護進程等,具體過程如下:
啓動過程中的配置是系統正常運行的基本保證。
14.1.1 系統屬性配置
系統屬性包括多個方面,在開機啓動時,android將進行一系列的配置:
》配置系統時區。android默認設置系統時區爲GMT 0。設置系統時區的方法如下: sysclktz 0 //東8區
》設置日誌等級。在android中,日誌分爲多個等級,設置控制檯輸出的日誌等級,默認爲3,設置方法: loglevel 3
》設置全局變量。系統啓動過程中,android需設置全局變量,具體入下:
》初始化網路配置。在android中,網絡配置包括對lo和其他網絡接入點的信息進行配置,配置網絡參數的工具是 ifup, 具體如下:
ifup lo
hostname localhost
demainname localdomain
》配置系統屬性。可在編譯腳本中對其進行設置。ActivityManagerSerivice中用到的一些配置 oom_adj 值的系統屬性如下:
oom_adj值通常被android特有的內存管理驅動 Low memory killer使用,它會在系統內存低於設定值時釋放響應的進程,保證系統的穩定運行。 Low memory
killer 根據兩個原則(進程的重要性和釋放這個進程可獲取的空閒內存數量)來決定釋放的進程。 oom_adj 值越小,表示該類型的重要性越高。 oom_adj 相同的情況下,佔用內存到的進程有限被撤銷,進程佔用的內存可用 get_mm_rss 進行判斷。
14.1.2 文件系統掛載
配置好文件系統分區並設置好分區表後,在設備實際啓動前,需要掛載文件系統。
1. 創建掛載點並設置權限
完成環境變量設置後,接下來就是創建掛載點並根據安全需要設置相應的權限。對於敏感信息,應避免普通用於對其用於可寫甚至可讀的權限。權限的主要設置方法如下;
以上可看出,android 有兩個比較重要的用戶權限,即 root, system ,其中root 權限最高,對於系統和讀寫的路徑至少應設置system權限。
2. 掛載文件系統
掛載點配置完成後,掛載文件系統。目前android默認的幾個文件系統爲system, data, cache等。掛載方法如下:
默認情況下,android支持的問價系統類型爲 yaffs2 。
14.1.3 守護進程啓動
守護進程是運行在後臺的android核心進程,主要包括 servicemanager, vold, netd, debuggerd, ril-daemon, zygote, drm, drmio, media, bootanim, dbus, bluetoothd, hfag, hsag, opush, pbap, installd, falsh_recovery, ravonn, mtpd, keystore, dumpstate 等。
1. 守護進程的配置(在init.rc中完成)
由於守護進程之間可能存在依賴關係,或守護進程對其他配置存在依賴,在啓動進程時,需要做些配置。 在system\core\init\目錄下的 readme.txt 中介紹了包括守護進程在內的啓動項配置方法,其中守護進程的配置方法如下:
service <name> <pathname> [<argument>] *
<option>
......
上述代碼中,option有多種情況:
2. 守護進程的啓動
下面介紹各守護進程的啓動和配置和作用。
(1)servicemanager
系統服務的管理器,通過一個HashMap<String, IBinder>來管理系統服務,當servicemanager重啓時,會導致zygote和media重啓。 下面是servicemanager的啓動配置:
(2)vold的配置
vold主要用來處理熱插拔,其實際上就是負責完成系統的CDROM, USB大容量存儲和MMC卡等擴展存儲的掛載任務的守護進程。vold和linux標準的udev類似,均通過sysfs爲內核和用於層提供通信。下面是vold的啓動配置:
熱插拔的處理框架:
和vold相關的代碼主要位於 system/vold目錄下。
(3)netd
主要用來監控網絡狀態,進行網絡管理,其實現位於system\netd目錄下,其啓動配置如下:
(4)debuggerd
主要用於調試,啓動後會監聽UNIX套接字 android:debuggerd, 其實現位於system\core\debuggerd目錄下, 其啓動配置如下:
(5)ril-daemon
RIL守護進程會初始化芯片廠商的RIL, 管理所有來自Android通信服務的通信,通過套件字實現與芯片廠商的RIL的通信,其實現與hardware/ril/rild無關,配置過程如下:
Android的RIL位於
應用程序框架與
內核之間,分成了兩個部分,一個部分是rild,它負責socket與應用程序框架進行通信。另外一個部分是Vendor
RIL,這個部分負責向下是通過兩種方式與radio進行通信,它們是直接與radio通信的AT指令通道和用於傳輸包數據的通道,數據通道用於手機的
上網功能。
對於RIL的java框架部分,也被分成了兩個部分,一個是RIL模塊,這個模塊主要用於與下層的rild進行通信,另外一個是Phone模塊,這個模塊直接暴露電話功能接口給應用開發用戶,供他們調用以進行電話功能的實現。
(6)zygote
是android啓動後啓動的第一個linux進程,其他的linux進程,比如各個應用,均是由zygote產生的。關於zygote的實現可參考ZygoteInit.java。zygote服務的重啓會導致media和netd服務的重啓,其啓動配置如下:
(7)drm
用於數字版權保護,其啓動配置如下:
(8)drmio
同樣用於數字版權保護,配置如上
(9)media
提供多媒體服務的守護進程,它會啓動 AudioFlinger, MediaPlayerSerivce, CameraService, AudioPolicySerivce等服務。media服務的入口實現如下:
media服務的啓動配置如下:
(10)bootanim
即所謂的開機動畫服務,其具體實現位於BootAnimation.cpp中。 SurfaceFlinger 在完成準備工作後會在reayToRun()方法中,通過 porperty_set("ctl.start", "bootanim") 啓動bootanim服務。在bootanim服務啓動過程中,會加載用戶開機動畫和系統開機動畫,均爲zip格式,所在的位置爲
data\local\bootanimation.zip, 和 \system\media\bootanimation.zip。動畫中圖片的格式應爲RGB565,其實現位於frameworks\base\cmds\bootanimation目錄中,bootanim服務的啓動配置如下:
(11)dbus
dbus和OpenBinder一樣都是進程間的通信機制,android進程間通信主要利用的是OpenBinder, dbus僅用於藍牙協議棧Bluez中。啓動配置如下:
(12)bluetoothd
爲bluez的守護進程,默認是不啓動的。啓動配置入下:
(13)hfag
也用於Bluez, 作用是啓動藍牙免提音頻網關,默認不啓動。
(14) hsag
也用於Bluez, 作用是啓動藍牙耳機音頻網關,默認不開啓
(15)opush
實現 Exchange ActiveSync服務器協議,同樣也用於Bluez。默認不啓動
(16)installd
安裝守護線程,用於apk的安裝
(17)flash_recovery
用於系統發生故障時的恢復。
(18)racoon
是VPN的守護進程。
14.2 應用的啓動過程
AAPT允許開發者查看,創建,更新與ZIP箭筒的壓縮文件(ZIP, JAR, APK),同時還將資源編譯到斷言(asset)中。
APK包中,通常可以看到res, AndroidManifest.xml, classes.dex, resource.arsc, META-INF 和libs等幾項。其中 META-INF 中存放的是Android的數字簽名證書。
需要說明的是,在android中,採用的java混淆器爲開源的ProGuard4.4。ProGuard可以在一定程度上防止別人的窺視,但對於需要保護的敏感信息,其安全性是無法保證的。
android生成的java字節碼爲DEX字節碼,而非傳統的CLASS字節碼,但編譯過程中,是先將java 文件編譯爲 CLASS字節碼,然後將 CLASS字節碼轉化爲 DEX字節碼。
14.2.1 應用的啓動配置
android應用由一個繼承了ContextWrapper的Application構成,其中Application由 Activity, Service, Receiver, Provider, uses-library等組件構成。組件之間的關係:
需要注意的是,應用程序並非必須具有activity,如果僅是後臺程序,僅有application也是可以的。
如果不希望應用在系統低內存時被系統銷燬,需將application標籤的 android:persistent 屬性設置爲 true.
14.2.2 應用的啓動過程
要啓動一個應用,首先要創建一個進程,然後啓動UI主線程,接着打開Activity,具體流程如下:
android進程分爲zygote進程和普通進程。當啓動一個應用時,Dalvik虛擬機會先通過 NativeStart 接口初始化JNI,爲通過 zygote進程創建新進程做好準備。原生代碼的啓動位於: app_main.app中
第十五章 深入解析android系統管理
15.1 內存管理
在創建進程時,Dalvik虛擬機會爲每個進程分配一定量的堆內存。佔用內存較多的程序很容易引起OutOfMemoryError等異常。
在數據交換比較頻繁的場景中,多用SQLite來進行緩存。
15.1.1 對應引用
java對象的引用被分爲 強引用(HardReference), 弱引用(WeakReference), 軟引用(SoftReference)和 虛引用(PhantomReference)等4個級別。
強引用表示 即使虛擬機內存“喫緊”拋出了 OutOfMemoryError 異常,該類型的對象也不會被回收;
軟引用表示 在虛擬機內存“喫緊”拋出了 OutOfMemoryError 異常前,該類型對象會被回收;
弱引用 更適合那些數量不多,但體積較龐大的對象,弱引用對象最容易被回收
虛引用一般沒有實際意義,僅觀察GC的活動狀態,對於 測試比較實用,必須和引用隊列(ReferenceQueue)一起使用。
弱引用,軟引用,虛引用均可與引用隊列聯合使用,當引用的對象被回收時,Dalvik會把該引用對象加入到與之關聯的引用隊列。
默認情況下,創建的java對象均爲強引用。創建引用隊列的方法如下:
ReferenceQueue<String> rq = new ReferenceQueue<String>()
創建一個弱引用,並將對象和引用對象關聯的方法如下:
WeakReference<String> wf = new WeakReference<String>( str, rq );
15.1.2 垃圾回收策略
android中,每個應用佔據一個虛擬機,所以android的垃圾回收是基於應用進行的。
在應用層,通過調用 System.gc() 可以調用垃圾回收器回收垃圾。
事實上,在android的原生代碼層,通過引入引用計數機制,Android 同樣實現了自動垃圾回收機制,相關的實現位於 \frameworks\base\include\utils\RefBase.h 中。幾乎所有的原生類均繼承了
RefBase類,RefBase類會維護對象的強引用和弱引用計數,一旦強引用計數爲0, 對象自動釋放自己。原生代碼的垃圾回收機制如下圖所示:
其中維護強引用的指針爲 sp, 維護弱引用的指針爲 wp(weak pointer), sp 和 wp 均依賴於 RefBase類,因此繼承與RefBase類的原生類才具有自動垃圾回收的能力。
1. sp 的實現
待完善