Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android資訊 >> Android系統啟動:init進程與init語言

Android系統啟動:init進程與init語言

編輯:Android資訊

面向新的一年,我們可能啟動了許多有意義的計劃,在這個有著特殊意義的日子裡,讓我們來一起學習一下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會被執行。觸發器有兩類:

  1. 事件觸發器: 事件可以由”trigger”命令發出,也可以是init進程通過QueueEventTrigger()函數發出
  2. 屬性觸發器: 當指定的屬性滿足時觸發

一個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系統的設計者從一開始就考慮到了這種復雜性,這一點從很多系統模塊的設計中很能看得出來。系統啟動的機制便是一個很好的范例:這裡在保證系統核心服務啟動順序的前提下,還為不同階段的開發者預留好了便於調整和擴展的機制,並且不用修改任何的源代碼。

這種對於“開閉原則”的遵守,是非常值得我們學習的。

  1. 上一頁:
  2. No
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved