詳解 Android 是如何啟動(dòng)的

本文是 Android 系統(tǒng)學(xué)習(xí)系列文章中的第一章節(jié),從大體上說明 Android 系統(tǒng)是如何啟動(dòng)的?從開機(jī)到程序啟動(dòng),發(fā)生了那些步驟,這些步驟意味著什么?歡迎進(jìn)入今天的「走進(jìn)科學(xué)」,逃 :)。對(duì)此系列感興趣的同學(xué),可以收藏這個(gè)鏈接 Android 系統(tǒng)學(xué)習(xí),也可以使用 RSS 進(jìn)行訂閱。


系統(tǒng)分區(qū)劃分

Android 達(dá)人都經(jīng)歷過刷機(jī)的體驗(yàn),如果通過 fastboot 來進(jìn)行刷機(jī)的話,會(huì)在刷機(jī)界面看到如下的幾個(gè)步驟。這些步驟是做什么用的?就是通過 fastboot 協(xié)議更新和燒錄到 Android 手機(jī)對(duì)應(yīng)的分區(qū)上。對(duì) fastboot 感興趣的同學(xué),可以點(diǎn)擊這個(gè) 鏈接 進(jìn)行查看。

fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash userdata userdata.img
fastboot flash cache cache.img
fastboot flash recovery recovery.img
fastboot reboot

從 fastboot 的燒錄過程中可以看出 Android 系統(tǒng)的大致分區(qū),這里我也通過 adb shell 中的 df 命令查看了小米手機(jī)中的系統(tǒng)分區(qū),如下圖所示。

小米系統(tǒng)分區(qū)

一般而言,雖然各個(gè)手機(jī)廠商在在系統(tǒng)上的實(shí)現(xiàn)不一致,Android 系統(tǒng)分為下面表格中的幾個(gè)部分。

Android 系統(tǒng)分區(qū)
分區(qū) 功能
boot 系統(tǒng)引導(dǎo)分區(qū),包含著android 內(nèi)核,系統(tǒng)沒有這個(gè)無法啟動(dòng)。這一部分的鏡像在 boot unlocked 時(shí),也能夠被擦除,但在這個(gè)過程中,不能被打斷,關(guān)機(jī)等等,否者會(huì)導(dǎo)致系統(tǒng)無法啟動(dòng)。
system Android 整個(gè)系統(tǒng)所在地,也包含預(yù)裝的應(yīng)用(這是預(yù)裝的APP,手機(jī)廠商盈利的一種渠道),
recovery 備份分區(qū),啟動(dòng)時(shí)可進(jìn)入 recovery ,然后在這個(gè)模式下進(jìn)行相應(yīng)的 recovery 操作。
data 應(yīng)用程序相關(guān)的數(shù)據(jù),例如你安裝的豌豆莢,數(shù)據(jù)就放在 /data/data/com.wandoujia.phoenix2 下面,當(dāng)進(jìn)行恢復(fù)出廠設(shè)置時(shí),這部分?jǐn)?shù)據(jù)會(huì)被擦除掉。
cache 用于存放緩存相關(guān)的數(shù)據(jù)。
misc 存放一些硬件配置、USB 配置等等信息,如果被擦除可能會(huì)導(dǎo)致某些系統(tǒng)設(shè)備無法正常工作。

Android 系統(tǒng)啟動(dòng)

如我們所知,Android 系統(tǒng)是基于 Linux 系統(tǒng)開發(fā)而成,在其中針對(duì)移動(dòng)設(shè)備的特性進(jìn)行了相應(yīng)的調(diào)整,所以 Android 系統(tǒng)大體上可以分為 Linux 內(nèi)核部分和 應(yīng)用系統(tǒng)部分。在 Android 系統(tǒng)啟動(dòng)的時(shí)候,也會(huì)先啟動(dòng) Linux 內(nèi)核,然后再啟動(dòng)應(yīng)用系統(tǒng)。整個(gè)啟動(dòng)步驟分為 6 個(gè)部分,在下面進(jìn)行詳細(xì)的描述。

Android 系統(tǒng)啟動(dòng)
Android 系統(tǒng)啟動(dòng)

啟動(dòng)電源以及系統(tǒng)啟動(dòng)

當(dāng)電源按下,引導(dǎo)芯片代碼開始從預(yù)定義的地方(固化在ROM)開始執(zhí)行。加載引導(dǎo)程序到RAM,然后執(zhí)行。

Boot Loader

Android系統(tǒng)是基于Linux操作系統(tǒng)的,所以它最初的啟動(dòng)過程跟Linux一樣。當(dāng)設(shè)備通電時(shí),首先執(zhí)行BootLoader引導(dǎo)裝載器,BootLoader是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一小段程序。BootLoader 的概念在各個(gè)操作系統(tǒng) windows, mac, Android 中都存在。通過這段小程序初始化硬件設(shè)置,建立內(nèi)存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境導(dǎo)入到合適的狀態(tài),以使為最終調(diào)用操作系統(tǒng)內(nèi)核準(zhǔn)備好正確的運(yùn)行環(huán)境。

BootLoader 在任何軟件之前執(zhí)行,因而也沒有類似于虛擬機(jī)那樣的概率來屏蔽不同運(yùn)行環(huán)境的差異,因而某個(gè)主板都有特定的BootLoader。另一方面,iOS 系統(tǒng)由于其各個(gè)版本間的穩(wěn)定性,因而不同版本件的 BootLoader 差異不大。另一方面,Android OS 是開源系統(tǒng),其可以運(yùn)行在不同的硬件上,這些硬件千差萬別,因而在 Android 上的 BootLoader 也各有不同。

一般而言 BootLoader 出于鎖閉狀態(tài),畢竟廠商開發(fā)出系統(tǒng)后,還是希望在 ROM 上的 Android 系統(tǒng)保持不變。因而刷機(jī)的第一步,往往是解鎖 BootLoader.

總結(jié)起來,BootLoader 完成的工作是:

  1. 初始化 RAM
  2. 初始化基礎(chǔ)硬件,例如 WIFI
  3. 加載內(nèi)核和內(nèi)存空間映射圖
  4. 跳轉(zhuǎn)到內(nèi)核中

內(nèi)核模塊

內(nèi)核模塊,負(fù)責(zé)了大部分的硬件、驅(qū)動(dòng)和文件系統(tǒng)的初始化,這部分都在內(nèi)核空間完成,不涉及用戶空間的內(nèi)容。內(nèi)核模塊的初始化是非常硬件相關(guān)的,目的就是使得 CPU 能夠更快地執(zhí)行 C 代碼,然后在這執(zhí)行完畢后,初始化各個(gè)子系統(tǒng),來執(zhí)行 init 進(jìn)程。

Init 進(jìn)程

Init 進(jìn)程作為第一個(gè)執(zhí)行的進(jìn)程,開天辟地。這個(gè)進(jìn)程主要做兩件事情,掛在相應(yīng)的目錄(/sys,/dev 等等),另一方面是執(zhí)行 init.rc 腳本,可通過 init.rc 源碼 查看相應(yīng)的鏈接。

Init 進(jìn)程會(huì)啟動(dòng) Runtime 運(yùn)行時(shí)服務(wù),所謂的 Runtime 服務(wù)就是將中間代碼靜態(tài)編譯成本地代碼。而 Android 所使用的 Java 動(dòng)態(tài)執(zhí)行,所依附的正式這個(gè) Runtime 環(huán)境。

其后,Init 進(jìn)程會(huì)啟動(dòng)一些本地守護(hù)進(jìn)程,這些守護(hù)進(jìn)程啟動(dòng)后,會(huì)初始化其相應(yīng)的模塊,在其中最特別的就是 Zygote。不過 Init 進(jìn)程不會(huì)直接啟動(dòng) Zygote 進(jìn)程,而是使用 app_process 命令來通過 Android Runtime 來啟動(dòng),Android Runtime 會(huì)啟動(dòng)第一個(gè) Davlik 虛擬機(jī),并調(diào)用 Zygote 的 main 方法。

Zygote and Dalvik

對(duì)于每一個(gè)運(yùn)行的程序,Android 都會(huì)賦予其單獨(dú)的虛擬機(jī),以支持其運(yùn)行,但每一次新建虛擬機(jī)的開銷都不小,那么如何來縮短這個(gè)時(shí)間了?尤其是針對(duì)嵌入式設(shè)備,都希望相應(yīng)速度能夠達(dá)到理想的狀況。Zyogte 就是用來解決這個(gè)問題的,其中文意思是受精卵。從這個(gè)名字上可以看出,其余的應(yīng)用進(jìn)程都是通過 fork 這個(gè)進(jìn)程來實(shí)現(xiàn)的,他們共享相同的內(nèi)存區(qū)域,這樣能減少不少的內(nèi)存占用開銷和應(yīng)用啟動(dòng)時(shí)間。

為了加速 App 的啟動(dòng),Zygote 進(jìn)程會(huì)預(yù)先加載 App 在運(yùn)行時(shí)所需的資源和 Class 文件到系統(tǒng) RAM 中。Zygote 會(huì)監(jiān)聽其 Socket (/dev/socket/zygote) 來判斷是否需要啟動(dòng) App。每當(dāng)監(jiān)聽到需要?jiǎng)?chuàng)建 App 的請(qǐng)求時(shí),就 fork 一個(gè)進(jìn)程即可。這樣的好處在于最初始的 Zygote 進(jìn)程,保有所有的系統(tǒng) Class 和 App 啟動(dòng)可能需要的資源,這樣一來,就不需要啟動(dòng)一個(gè) App 時(shí),動(dòng)態(tài)去加載相應(yīng)的資源。

監(jiān)聽 /dev/socket/zygote socket.

/**
 * Registers a server socket for zygote command connections
 *
 * @throws RuntimeException when open fails
 */
private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }

        try {
            sServerSocket = new LocalServerSocket(
                    createFileDescriptor(fileDesc));
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

為何在 Android 中 fork Zygote 進(jìn)程如此高效了?Linux Kernel 采用了 Copy-On-Write 的技術(shù),Copy-On-Write 的意思是只有在寫的時(shí)候才單獨(dú)復(fù)制一份,而讀的時(shí)候不進(jìn)行操作。 換而言之 fork zygote 實(shí)際上并未實(shí)際復(fù)制什么東西,只有在發(fā)生寫操作時(shí),才單獨(dú)復(fù)制一份。而另一方面,class 和 Resource 資源文件并不需要重新寫,這些文件在絕大多數(shù)時(shí)候都是只讀的。最后,實(shí)際的效果就是盡管運(yùn)行著多個(gè) APP,但實(shí)際只有一份 class 和 resource 文件在 Zygote 進(jìn)程中。

System Server 和 系統(tǒng)服務(wù)

絕大多數(shù) App 都是通過 fork Zygote 進(jìn)程來完成了,只有一個(gè)例外,那就是 System Sever。在啟動(dòng) System Server 之后,其他系統(tǒng)服務(wù)將自己注入到 System Server 中,同時(shí)其他系統(tǒng)服務(wù)也完成啟動(dòng)。這些服務(wù)主要包括,Power Manager,Telephony Registry,Battery Service,Window Manager等等。在這其中也包括我們熟知的 Activity Manager,Activity Manager在啟動(dòng)完成后,會(huì)發(fā)送一個(gè) Intent.CATEGORY_HOME 的 intent,從而我們就能看到我們熟知的桌面。

Android 桌面

由于之前對(duì) System Server 進(jìn)行過詳細(xì)的講解,這里就不在贅述,感興趣的同學(xué)可以查看這篇文章 Android Binder 全解析(2) -- 設(shè)計(jì)詳解

總結(jié)

上述章節(jié)把 Android 啟動(dòng)中發(fā)生的事情表述完畢,現(xiàn)在沒有什么比下面這張圖更能總結(jié)觀點(diǎn)了。


Android 啟動(dòng)

參考文獻(xiàn)


文檔信息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,934評(píng)論 25 709
  • 1:InputChannel提供函數(shù)創(chuàng)建底層的Pipe對(duì)象 2: 1)客戶端需要新建窗口 2)new ViewRo...
    自由人是工程師閱讀 5,707評(píng)論 0 18
  • 女主為全世界最大財(cái)團(tuán)的繼承人 從小被拋棄 自己闖蕩 美貌 性格復(fù)雜 家里人找不到她 她知道家在哪里卻不想回 有一身...
    羽喬毛球閱讀 673評(píng)論 0 3
  • 練習(xí)內(nèi)容 小球運(yùn)動(dòng)代碼練習(xí)5遍 scan 第一章文字內(nèi)容 感想 抄了4遍就可以默寫了 默寫出來就可以不用抄了 附件
    周偉誠閱讀 165評(píng)論 0 0
  • 今天有些累,來例假,又上了三節(jié)課,下午回來,飯也不想做,就攤在床上休息了一會(huì)。 生活讓我們有時(shí)清閑,有時(shí)累,只有這...
    清空妙有閱讀 167評(píng)論 1 1

友情鏈接更多精彩內(nèi)容