1. 程式人生 > >Android系統啟動流程——init程序

Android系統啟動流程——init程序

配置檔案:system/rootdir/init.rc

    init程序是一個由核心啟動的使用者級程序。核心自行啟動之後(已經被載入記憶體,開始執行並已初始化所有裝置驅動程式和資料結構等),通過啟動一個使用者級程式init的方式完成引導過程。Init始終是第一個程序,可以說它是root程序或者說是後續所有程序的父程序。

    Init程序的作用包括:資料夾建立,掛載,rc檔案解析,屬性設定,啟動服務,執行動作,socket監聽……啟動過程就是程式碼init.c中main函式執行過程。

(1)   初始化log系統

(2)  解析/init.rc和/init.{hardware}.rc檔案

(3)  執行.rc檔案中的early-init action

(4)  裝置初始化,如/dev下建立所有裝置節點,下載firmwares

(5)   初始化屬性

(6)  執行init action

(7)   開啟屬性服務

(8)  執行early-boot和boot action

(9)  執行propertyaction

(10)  進入無限迴圈,等待device/property set/child process退出

rc檔案解析</system/core/init.rc >

Init程序啟動後,解析init.rc及init.{hardware}.rc初始化指令碼檔案。指令碼被直接安裝到目標系統的根檔案系統中,,使用方法參考system/core/init/readme.txt,關鍵字參考system/core/init/keyword.h。Android初始化語言由四大型別的宣告組成,即Commands(命令)、Actions(動作)、Services(服務)、以及Options(選項)。

  • Command(命令)

Command是一些基本的操作,主要有以下常用命令:

命令

說明

sysclktz <mins_west_of_gmt>

設定系統時鐘基準(0代表時鐘滴答以格林威治平均時(GMT)為準)

exec <path> [ <argument> ]*

建立和執行一個程式(<path>)。在程式完全執行前,init將會阻塞。

export <name><value>

在全域性環境變數中設在環境變數<name>為<value>,所有在這命令之後執行的程序所繼承

ifup <interface>

啟動網路介面<interface>

import <filename>

匯入一個init配置檔案。

hostname <name>

設定主機名。

chmod <octal-mode><path>

更改檔案訪問許可權。

chown <owner><group><path>

更改檔案的所有者和組。

class_start <serviceclass>

啟動所有指定服務類別下的未執行服務。

class_stop <serviceclass>

停止指定服務類下的所有已執行的服務。

domainname <name>

設定域名。

insmod <path>

載入<path>中的模組。

mkdir <path> [mode] [owner] [group]

建立一個目錄<path>,可以選擇性地指定mode、owner以及group。如果沒有指定,預設的許可權為755,並屬於root使用者和root組。

mount <type><device><dir> [ <mountoption> ]*

試圖在目錄<dir>掛載指定的裝置。<device>可以是以 [email protected] 的形式指定一個mtd塊裝置。<mountoption>包括 "ro"、"rw"、"remount"、"noatime"

setprop <name><value> 

設定系統屬性<name>為<value>值。

setrlimit <resource><cur><max>

設定<resource>的rlimit(資源限制)。

start <service>

啟動指定服務(如果此服務還未執行)。

stop <service>

停止指定服務(如果此服務在執行中)。

symlink <target><path>

建立一個指向<path>的軟連線<target>。

trigger <event>

觸發一個事件。

write <path><string> [ <string> ]*

開啟路徑為<path>的一個檔案,並寫入一個或多個字串。

  • Action(動作)

Actions的語法如下:

   on<trigger>
      <command1>
      <command2>
      <command3>

Actions其實就是一序列的Commands(命令)。每個Actions都有一個trigger(觸發器),用來決定action的執行時間。當trigger被觸發時,action會被加入到執行佇列的末尾,除非它已經在佇列裡了。佇列中的每一個action都被依次提取出,而這個action中的每個command(命令)將被依次執行。

  • Services(服務)

Services的語法如下:

service <name><pathname> [<argument> ]*

<option>

<option>

     ...

name:服務名

pathname:當前服務對應的程式位置

option:當前服務設定的選項

Services(服務)其實就是一個程式,一個本地守護程序,它被init程序啟動,並在退出時可選擇讓其重啟。

  • Options(選項)

Options(選項)是對Services(服務)的描述,決定了Services的執行機制,狀態和功能。它們影響Services(服務)在何時以何種方式執行。

Service Options

說明

critical

說明這是一個對於裝置關鍵的服務。如果他四分鐘內退出大於四次,系統將會重啟並進入recovery(恢復)模式。

disabled

說明這個服務不會同與他同trigger(觸發器)下的服務自動啟動。他必須被明確的按名啟動。

setenv <name><value>

在程序啟動時將環境變數<name>設定為<value>。

socket <name><type><perm> [ <user> [ <group> ] ]

建立一個Uinx域的名為/dev/socket/<name>的套接字,並傳遞它的檔案描述符給已啟動的程序。<type>必須是 "dgram"或"stream"。User 和 group預設為0。

user <username>

在啟動這個服務前改變該服務的使用者名稱。此時預設為root。(???有可能的話應該預設為nobody)。當前,如果你的程序要求Linux capabilities(能力),你無法使用這個命令。即使你是root,你也必須在程式中請求capabilities(能力)。然後降到你想要的 uid。

group <groupname> [ <groupname> ]*

在啟動這個服務前改變該服務的組名。除了(必需的)第一個組名,附加的組名通常被用於設定程序的補充組(通過setgroups())。此時預設為root。(???有可能的話應該預設為nobody)。

oneshot

服務僅執行一次,退出時不重啟。

class <name>

指定一個Service類別,name為類別名。所有同一類的服務可以同時啟動和停止。如果Service沒有顯式的指定類別,則預設為"default"服務。

onrestart

當服務重啟,執行後面的命令。

  • Properties(屬性)

是系統中使用的一些值,可以進行設定和讀取。

setpropro.FOREGROUND_APP_MEM 1536
setprop ro.sf.hwrotation 90   

onproperty:ro.kernel.qemu=1
    start adbd

setprop 用於設定屬性,on property可以用於判斷屬性,這裡的屬性在整個Android系統執行中都是一致的。

在init.rc中,定義了以下Actions:

Action

功能

early-init

在所有Action中最先啟動,用於啟動ueventd,設定init程序以及它建立的子程序的優先順序,設定init程序的安全環境。

init

設定全域性環境,為cpu accounting建立cgroup(資源控制)掛載點。匯出必要的環境變數、構建根檔案系統的目錄結構、配置核心屬性等一些和Android系統初始化化相關內容

fs

掛載Android的檔案系統,主要掛載system.img和userdata.img映像

post-fs

該Action會在檔案系統掛載完畢之後觸發執行,將根檔案系統掛載為只讀,用於保護系統檔案,修改檔案或目錄訪問許可權等

post-fs-data

改變/data目錄以及它的子目錄的訪問許可權。

boot

配置網路、配置系統程序的執行優先順序。用於記憶體管理、修改系統服務和守護程序的訪問許可權,啟動所有的預設Service。

property:ro.secure=0

屬性觸發器action,當屬性ro.secure值為0時觸發執行,用於在非安全系統模式時啟動console終端。

property:ro.kernel.qemu=1

屬性觸發器action,當屬性ro.kernel.qemu值為1時觸發執行,用於執行在模擬器時開啟adbd除錯橋服務端。

property:persist.service.adb.enable

屬性觸發器action,用於控制adbd除錯橋服務端。

除了上述在init.rc裡顯式定義的Action,在system/core/init/init.c中還定義了一些內建Action:

Action

功能

wait_for_coldboot_done

用於等待機器冷啟動完畢

property_init

初始化屬性儲存區及載入配置檔案中的屬性

keychord_init

初始化組合鍵服務

console_init

初始化console終端

set_init_properties

裝置property的一些初始值

property_service_init

初始化屬性服務

signal_init

Init程序訊號處理初始化

check_startup

檢測屬性服務及訊號處理已經就緒

queue_propety_triggers

將所有屬性觸發Action新增到Action列表中等待執行。

*  bootchart_init

根據核心配置決定是否會執行,bootchart是linux啟動過程效能分析工具

    上述Action依次被init程序解釋,放到action_list連結串列裡,每個action_list節點都有一個commands連結串列儲存所有Command,init程序從action_list依次觸發每一個action,該action裡的commands裡的命令依次被執行,init.rc中所有Actions如圖所示:

 

init.rc中Actions的執行流程

圖中queue_property_triggers觸發屬性Actions,即:on property:xxx=xxx形式的Action。boot是最後一個被執行的Action,在boot的commands連結串列裡,最後一個命令是class_startdefault,該命令用於啟動所有未設定class分類的Service。

服務啟動

    Init啟動各種服務:adbd, servicemanager, vold, ril-daemon,debuggerd, surfaceflinger, zygote, media……對於service,這裡會給每個服務建立一個struct service的結構體,全部掛入連結串列service_list之中,在init最後才啟動。

    此時,可以看到Android的logo了。