Android從開機到打開第一個應用發生了什麼?

本人如今每日一道算法題的Github地址。
https://github.com/Jensenczx/...
附帶OJ地址和本人的代碼
博客新址,這裏更有趣java

序言

昨日阿里二面,跪的很慘,項目,算法,計算機基礎不問,問Linux內核,我是投的android實習崗,要求是對於android底層有很深厚的基礎,問了binder的實現機制,activity棧的管理回退等等,這都是android高級工程師進階的書裏纔會講的東西,這讓我很慌呀。啃底層,再戰。
講底層,先從系統啓動流程開始,這個過程發生了什麼,而後逐步分析這個每一個流程又作了些什麼,在咱們的系統中起到一個什麼做用。不打算深刻代碼細節去看,固然能力也是不夠的,從總體上有個森林。android

啓動過程

圖片描述

先對啓動的過程來一個概覽,由於android是基於Linux,因此這裏從Linux內核的啓動開始到android中的相應服務的啓動,對於具體應用的開啓下面講。git

根據這個圖,講一下整個流程。github

  1. 當咱們開機的時候,此時通電了,此時會產生一個肯定的復位時序,保證CPU是第一個被複位的器件,而後CPU開始執行第一條指令,該指令是位於固定的內存地址上的,所謂的引導程序。算法

  2. BIOS從咱們的磁盤中尋找咱們操做系統引導程序,將引導程序加載到內存中,執行,而後將咱們的Linux內核加載到內存中。shell

  3. 啓動init進程,這個進程是用戶態全部進程的祖先,內核態是叫作內核線程和用戶進程差很少。()編程

  4. init進程首先經過fork建立子進程,首先是Daemon進程也就是守護進程,包括USB守護進程,Debug進程,無線通訊鏈接守護進程。網絡

  5. fork出Context Manager,經過上圖咱們能夠看出,android系統提供的服務都要向其進行註冊,而後其它的進程才能夠調用這個服務。框架

  6. Media Server,這個服務是本地服務,不是Java服務,不須要再經過dalvik虛擬機裝載執行,本地服務單獨開啓了一個進程。這裏包括Audio Flinger和Camera Service。socket

  7. Zygote,全部Android應用程序的祖先,其用來縮短應用程序的加載時間,具體怎麼節省,下面詳解。

  8. System Server是android系統中的一個核心進程,提供了管理應用程序生命週期,地理位置信息等各類服務。同時其須要將自身註冊到Context Manager.可是咱們的服務管理器是基於C語言的,因此咱們須要JNI本地編程接口。這個時候Activity Manager Service會運行HOME應用。

大體咱們已經瞭解了啓動的流程Linux內核,init進程fork出多個進程,zygote用來孵化Java系統服務,同時孵化應用程序。接下來,咱們再深刻的去看一下。init進程作了什麼?zygote是如何被建立出來的。

init進程

init進程是第一個啓動的用戶進程,其它用戶進程都是其子進程,或者其子進程的子進程,,

init進程做用

  • 子進程終止處理。

  • 應用程序訪問設備驅動時,生成設備結點文件。

  • 提供屬性服務,保存系統運行所須要的環境變量。

init運行

init進程會先註冊一些消息處理器,而後是建立並掛載啓動所須要的文件目錄(socket文件,虛擬內存文件),在dev目錄下生成設備節點文件,而後將標準輸入,輸出,錯誤輸出重定向到這裏。建立設備節點文件,建立輸出log的文件,同時將錯誤信息重定向到這裏,init進程生成輸出設備以後,開始解析init.rc腳本文件,記錄init進程執行的功能,init.rc用於通用的環境變量和進程相關的定義,經過函數 iparse_config_file來讀取其腳本,讀取分析以後,生成服務列表和動做列表。服務列表和動做列表會註冊到service_list和action_list中,其爲在init進程中聲明的全局結構體,調用device_init函數,生成靜態設別結點文件,以後,全局屬性值的生成在init進程中propertyinit函數中進行初始化,在共享內存區域,建立並初始化屬性值,對於全局屬性的修改,只有init進程能夠修改,當要修改的時候,須要預先向其提交申請,而後init進程經過以後,纔會去修改屬性值,提交申請的過程會建立一個socket用來接收提交的申請。執行到這系統將Android系統的Logo顯示在桌面上。這個時候設置事件處理循環的監視事件,註冊在POLL中的文件描述符會在poll函數中等待事件,事件發生,則從poll函數中跳出並處理事件。各類文件描述符都會前來註冊。

init.rc文件的處理過程

init.rc文件分析函數,經過read_file函數,parse_config函數,用來分析讀入的字符串。AIL ,Android Init Language編寫。
init.rc文件大體上分爲兩個部分,一部分是以「on」關鍵字開頭的動做列表,另外一部分是以」service」關鍵字開頭的服務服務列表。
動做列表:主要設置環境變量,生成系統運行所需的文件或目錄,修改相應的權限,並掛載和系統運行相關的目錄。在掛載文件的時候,主要掛載/system和/data兩個目錄,兩個目錄掛載完畢,android根文件系統準備好了。根文件系統大體可分爲shell使用程序,system目錄(提供庫和基礎應用),data目錄(保存用戶應用和數據),Android採用閃存設備,其採用了yaffs2文件系統,啓動的時候要掛載到/system和/data目錄下,而後是on boot段落,該部分設置應用程序終止條件,應用程序驅動目錄和文件權限。爲各應用制定OOM調整至,OOM用來監視內核分配給應用程序的內存,當內存不足的時候,應用程序會被終止執行。
服務列表:init.rc腳本文件,service段落用來記錄init進程啓動的進程,由init進程啓動的子進程或者是一次性程序,系統相關的Daemon進程

建立設別節點文件:

和Linux相同,應用程序經過驅動程序訪問硬件設備,設備節點文件是設備驅動的邏輯文件,應用程序經過設備節點文件來訪問設備驅動程序。

設備節點的兩種建立方式,一種,根據預先定義的設備信息,建立設備節點文件,第二種,在系統運行中,當設備插入時,init進程會接收這一事件,爲插入設備動態建立設備節點文件。

當設備插入的時候內核會加載相應的驅動程序,然後驅動程序會調用啓動函數probe,將主,次設備號類型保存到/sys文件系統中。而後發出uevent,並傳遞給守護進程,vevent,是內核向用戶控件進程傳遞信息的信號系統,內核經過uevent將信息傳遞到用戶空間,守護進程會根據uevent讀取設備信息,建立設備節點文件。對於一些設備,採用冷插拔的方式,監聽設備的uevent,而後調用其函數,建立設備節點文件。

何爲設備節點文件

Linux對於系統中的設備都會抽象成一個文件,內核爲了高效的管理已經被打開的文件,經過一個文件描述符來表示,在Linux中Everything is file,經過這種方式,對於啓動的時候,對於文件描述符,0表明標註輸入,1表示標準輸出,2是錯誤處理,而後設備文件,socket文件都會得到一個文件描述符來表述它。可是Linux會對其作相應的限制,同時可能會對一些進程進行限制,限制給進程分配多少個文件描述符。

Zygote建立過程

圖片描述

對於Service的建立,在後面講到Service的時候單獨再說,先講Zygote,由於這是咱們的全部應用開啓的基石。由於zygote是Java代碼,因此須要裝載到Dalvik VM上執行,因此在啓動Zygote以前要啓動Dalvik VM,因此這裏要分爲兩步了,第一步啓動Dalvik VM,第二步是啓動Zygote。

  1. 首先生成了一個AppRuntime對象,該類是繼承自AndroidRuntime的,該類用來初始化而且運行Dalvik 虛擬機,爲運行Android應用作好準備。接受main函數傳遞進來的參數,而後初始化虛擬機。

  2. 虛擬機初始化以後,運行ZygoteInit類,經過路徑查找找到,如今程序的執行轉向了虛擬機Java代碼的執行,首先執行器main函數,接下來就是Zygote的做用過程了,在下面部分。

Zygote啓動應用過程

圖片描述

  1. Zygote執行以後,首先是綁定一個套接字,用來接收從Activity Manager來的應用啓動請求(這裏咱們能夠想到網絡通信中的Socket通訊)

  2. 將應用程序框架中的類,平臺資源(圖像,XML信息,字符串)預先加載到內存中,藉此提高程序的執行速度。Android也是經過在Zygote建立的時候加載資源,生成信息連接等,之後再有應用啓動,fork出一個子進程和父進程共享這些信息,而不須要從新加載,同時也共享虛擬機,由於虛擬機在初始化和建立的過程是很耗時的。

  3. 前面也提到過一些system server也是java的,並且咱們的應用啓動等須要這些server的參與,因此在啓動應用以前先啓動了這些System server,而後啓動Server Thread來執行android framework的服務,同時這些服務在啓動的時候都是須要經過JNI向服務管理器Context Manager註冊。
    經歷了上述步驟的zygote處在輪詢監聽Socket,當有請求到達,讀取請求,fork出子進程,加載進程所須要的類,而後執行要執行程序的main函數,代碼轉給了Dalvik Vm,咱們的應用程序也就啓動起來了。這個時候,將關閉套接字,刪除請求描述符,防止出現重複啓動。

圖片描述

上面只是對總體流程進行了一個概述,細節涉及不深,這裏再提一下,虛擬機,到底是什麼呢?這裏的虛擬機能夠理解成,能夠解析Java字節碼的內存上的一條條指令,各個應用共享這個虛擬機,也就是都是知道虛擬機的內存中地址,傳遞進java字節碼,而後解析字節碼,將字節碼實際表明的操做反應出來,多個應用程序能夠交替使用,經過寄存器記錄彼此執行後的狀態。fork出一個進程以後,咱們裝載應用程序相應的類,而後執行。

相關文章
相關標籤/搜索