Android系統啟動:init程式與init語言
面向新的一年,我們可能啟動了許多有意義的計劃,在這個有著特殊意義的日子裡,讓我們來一起學習一下Android系統是如何啟動的。
init程式與init.rc
init程式是一切的開始,在Android系統中,所有程式的程式號都是不確定的,唯獨init程式的程式號一定是1。因為這個程式是系統起來的第一個程式。並且,init程式掌控了整個系統的啟動流程。
我們知道,Android可能執行在各種不同的平臺,不同的裝置上。因此,啟動的邏輯是不盡相同的。 為了適應各種平臺和裝置的需求,init程式的初始化工作通過init.rc
配置檔案來管理。init.rc以Android Init Language作為語法,下文我們簡稱Android Init Language為init語言。配置檔案的主入口檔案是/init.rc,這個檔案會通過import
關鍵字引入其他的配置檔案。在這裡,我們統稱這些檔案為init.rc
。
/init.rc可能import
以下路徑中的.rc檔案:
- /init.${ro.hardware}.rc 硬體廠商提供的主配置檔案
- /system/etc/init/ 核心系統模組的配置檔案
- /vendor/etc/init/ SoC廠商提供的配置檔案
- /odm/etc/init/ 裝置製造商提供的配置檔案
init語法說明
init語言,以換行為語句分隔,以空格來為符號分隔,以“#“為註釋開始。配置檔案中支援五種型別的表示式:
- Action: 包含了一系列的Command
- Command: init語言中的命令
- Service: init程式啟動的服務
- Option: 對於服務的配置選項
- Import: 引入其他配置檔案
這其中,Action和Service需要保證名稱唯一。
Action與Command
Action表示式的語法如下:
on <trigger> [&& <trigger>]* <command> <command> <command>
這裡的Trigger是Action執行的觸發器,當觸發器條件滿足時,command會被執行。觸發器有兩類:
- 事件觸發器: 事件可以由”trigger”命令發出,也可以是init程式通過
QueueEventTrigger()
函式發出 - 屬性觸發器: 當指定的屬性滿足時觸發
一個Action可以有多個屬性觸發器,但是隻能包含一個事件觸發器。下面是一些例子:
on boot && property:a=b
在”boot”事件發生時,並且屬性a的值是b時觸發on property:a=b && property:c=d
在屬性a的值是b並且屬性c的值是d時觸發
Action中的Command是init語言定義的命令,所有支援的命令如下表所示:
Command | 引數格式 | 說明 |
---|---|---|
bootchart_init | - | 啟動bootchart |
chmod | octal-mode path | 改變檔案的訪問許可權 |
chown | owner group path | 改變檔案的擁有者和組 |
class_start | serviceclass | 啟動指定類別的服務 |
class_stop | serviceclass | 停止並disable指定類別的服務 |
class_reset | serviceclass | 停止指定類別的服務,但是不disable它們 |
copy | src dst | 拷貝檔案 |
domainname | name | 設定域名 |
enable | servicename | enable一個被disable的服務 |
exec | [seclabel[user[group]]] – command [argument]* | fork一個子程式來執行指定的命令 |
export | name value | 匯出環境變數 |
hostname | name | 設定host名稱 |
ifup | iterface | 使網路卡線上 |
insmod | path | 安裝指定路徑的模組 |
load_all_props | - | 從/system, /vendor等路徑載入屬性 |
load_persist_props | - | 載入持久化的屬性 |
loglevel | level | 設定核心的日誌級別 |
mkdir | path [mode] [owner] [group] | 建立目錄 |
mount_all | fstab [ path ]* [--option] | 掛載檔案系統並且匯入指定的.rc檔案 |
mount | type device dir [ flag ]* [options] | 掛載一個檔案系統 |
powerctl | - | 內部實現使用 |
restart | service | 重啟服務 |
restorecon | path [ path ]* | 設定檔案的安全上下文 |
restorecon_recursive | path [ path ]* | restorecon的遞迴版本 |
rm | path | 對於指定路徑呼叫unlink(2) |
rmdir | path | 刪除資料夾 |
setprop | name value | 設定屬性值 |
setrlimit | resource cur max | 指定資源的rlimit |
start | service | 啟動服務 |
stop | service | 停止服務 |
swapon_all | fstab | 在指定檔案上呼叫fs_mgr_swapon_all |
symlink | target path | 建立符號連結 |
sysclktz | mins_west_of_gmt | 指定系統時鐘基準 |
trigger | event | 觸發一個事件 |
umount | path | unmount指定的檔案系統 |
verity_load_state | - | 內部實現使用 |
verity_update_state | mount_point | 內部實現使用 |
wait | path [ timeout ] | 等待某個檔案存在直到超時,若存在則直接返回 |
write | path content | 寫入內容到指定檔案 |
Service與Option
Service是init程式啟動的可執行程式。服務可以選擇在自己退出之後,由init將其重啟。
Service表示式的語法如下:
service <name> <pathname> [ <argument> ]* <option> <option>
Option是對服務的修飾,它們影響著init程式如何以及何時啟動服務。所有支援的option如下表所示:
option | 引數格式 | 說明 |
---|---|---|
critical | - | 標識為系統關鍵服務,該服務若退出多次將導致系統重啟到recovery模式 |
disabled | - | 不會隨著類別自動啟動,必須明確start |
setenv | name value | 為啟動的程式設定環境變數 |
socket | name type perm [user [group [seclabel]]] | 建立Unix Domain Socket |
user | username | 在執行服務之前切換使用者 |
group | groupname [ groupname]* | 在執行執行之前切換組 |
seclabel | seclabel | 在執行服務之前切換seclabel |
oneshot | - | 一次性服務,死亡之後不用重啟 |
class | name | 指定服務的類別 |
onrestart | - | 當服務重啟時執行指定命令 |
writepid | file… | 寫入子程式的pid到指定檔案 |
Import
import是一個關鍵字,並不是一個命令。可以在.rc檔案中通過這個關鍵字來載入其他的.rc檔案。它的語法很簡單:
import path
path可以是另外一個.rc檔案,也可以是一個資料夾。如果是資料夾,那麼這個資料夾下面的所有檔案都會被匯入,但是它不會迴圈載入子目錄中的檔案。
init.rc程式碼例項
AOSP中包含了Android系統需要的最基本的.rc檔案,它們位於這個路徑:/system/core/rootdir/ 。
我們選取其中了一兩個程式碼片段來了解一下:
# /system/core/rootdir/init.rc import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000 # Disable sysrq from keyboard write /proc/sys/kernel/sysrq 0 # Set the security context of /adb_keys if present. restorecon /adb_keys # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628. mkdir /mnt 0775 root system # Set the security context of /postinstall if present. restorecon /postinstall start ueventd on init sysclktz 0 # Mix device-specific information into the entropy pool copy /proc/cmdline /dev/urandom copy /default.prop /dev/urandom # Backward compatibility. symlink /system/etc /etc symlink /sys/kernel/debug /d # Link /vendor to /system/vendor for devices without a vendor partition. symlink /system/vendor /vendor ...
這是根目錄/init.rc檔案中一開始的程式碼片段。有了前面的講解之後,這段程式碼應當還是比較好理解的。在這段程式碼中:
- 通過import關鍵字引入了其他幾個.rc檔案
- 設定了一個事件為early-init的Action
- 設定了一個事件init的Action
“eraly-init”和”init”這兩個事件都是由init程式發出的。
下面,我們再來看另外一個程式碼片段:
這段程式碼定義了一個名稱為zygote
的Service,這個服務是通過可執行命令/system/bin/app_process啟動的,啟動的時候傳遞了引數:-Xzygote /system/bin --zygote --start-system-server
。
Zygote是Android系統中一個非常重要的服務,zygote的中文意思是“受精卵“。這是一個很有寓意的名稱:所有的應用程式都是由zygote
fork出來的子程式,因此zygote程式是所有應用程式的父程式。
關於Zygote,我們已經在另外一篇文章中講解過了,參見這裡Zygote程式,有興趣的讀者可以再次回顧一下。
結束語
Android系統是一個跨越了多種裝置的作業系統,從最初的系統的研發到最終終端使用者的使用,這其中經歷了許多道的開發流程。而每一道流程的開發者都有可能對系統做不同程度的定製。
Android系統的設計者從一開始就考慮到了這種複雜性,這一點從很多系統模組的設計中很能看得出來。系統啟動的機制便是一個很好的範例:這裡在保證系統核心服務啟動順序的前提下,還為不同階段的開發者預留好了便於調整和擴充套件的機制,並且不用修改任何的原始碼。
這種對於“開閉原則”的遵守,是非常值得我們學習的。
相關文章
- 【Android】【init】解析init程式啟動過程Android
- 系統啟動, init
- Android系統啟動流程(一)解析init程式Android
- OpenHarmony的init程式、init配置與啟動項配置
- (連載)Android 8.0 : 系統啟動流程之init程式(二)Android
- (連載)Android 8.0 : 系統啟動流程之init程式(一)Android
- Android 9.0 init 啟動流程Android
- UNIX/LINUX 系統啟動方式INITLinux
- Android 系統開發_啟動階段篇 — 深入鑽研 initAndroid
- Android 啟動過程簡析(一)之 init 程式Android
- init.cssd程式啟動失敗CSS
- Linux的啟動過程及init程式Linux
- Linux系統 init 6 重啟不了,reboot -n 卻可以重新啟動Linuxboot
- Linux 系統下 init 程式的前世今生Linux
- Debian init 開機啟動管理
- Android 4.4 的 init 程式詳解Android
- CentOS的System V init啟動指令碼CentOS指令碼
- Slackware的啟動(init)過程(轉)
- 圖解 Android 系列(二)深入理解 init 與 zygote 程式圖解AndroidGo
- OpenHarmony系統使用gdb除錯init除錯
- 系統初始化之sys init
- Init
- Linux init程式分析Linux
- __new()__ 與 __init()__的區別
- init sys
- Linux init程式詳解Linux
- Go 常量、init、陣列、型別轉換與斷言、RecoverGo陣列型別
- Android系統啟動流程(四)Launcher啟動過程與系統啟動流程Android
- 淺析 Linux 初始化 init 系統: SystemdLinux
- 【轉】Linux初始化init系統[sysvinitsystemdupstart]Linux
- 國產系統級程式語言與編譯器,輕鬆與 C 語言進行互動編譯
- git init 命令Git
- ora_init
- __init__.py
- Linux基礎命令---init程式Linux
- Tomcat 7 啟動分析(四)各元件 init、start 方法呼叫Tomcat元件
- spring的延遲初始化bean (default-lazy-init 與 lazy-init )SpringBean
- 淺析 Linux 初始化 init 系統(1):sysvinitLinux