學習這個玩意兒就是由於以前遇到的DAC配置問題,翻譯init/README.md文件,之後在遇到此類問題就能夠修改相應的rc文件便可html
Android初始化語言linux
Android初始語言由五大類語句組成:操做,命令,服務,選項和導入。android
全部這些都是面向行的,由用空格分隔的標記組成。c風格的反斜槓轉義符可用於將空格插入到令牌中。雙引號也可用於防止空格將文本分紅多個標記。反斜槓,當它是一行上的最後一個字符時,可用於行摺疊。web
以#(之前容許的空格)開頭的行是註釋。shell
可使用語法擴展系統屬性${property.name}。這也適用於須要鏈接的上下文,例如import /init.recovery.${ro.hardware}.rc。安全
操做和服務隱式聲明一個新部分。全部命令或選項都屬於最近聲明的部分。忽略第一部分以前的命令或選項。網絡
服務有獨特的名稱。若是定義的第二個服務名稱與現有服務名稱相同,則會忽略該服務並記錄錯誤消息。app
Init .rc文件dom
init語言用於帶.rc文件擴展名的純文本文件。在系統上的多個位置一般存在多個這些.rc文件,以下所述。socket
/init.rc是主.rc文件,在執行開始時由init可執行文件加載。它負責系統的初始設置。
經過第一階段安裝機制掛載/ system,/ vendor的設備在加載主/init.rc後當即加載/ {system,vendor,odm} / etc / init /目錄中包含的全部文件。在此文件的「導入」部分中對此進行了更詳細的說明。
沒有第一階段安裝機制的舊設備執行如下操做:
能夠在mount_all命令行中指定路徑,使其在指定的路徑中導入.rc文件,而不是上面列出的默認路徑。這主要用於支持工廠模式和其餘非標準引導模式。應該將三個默認路徑用於正常引導過程。
這些目錄的意圖是:
二進制文件駐留在系統,供應商或odm分區上的全部服務都應將其服務條目放入相應的init .rc文件中,該文件位於它們所在分區的/ etc / init /目錄中。有一個構建系統宏LOCAL_INIT_RC,能夠爲開發人員處理這個問題。每一個init .rc文件還應包含與其服務相關的任何操做。
一個示例是位於system / core / logcat目錄中的logcatd.rc和Android.mk文件。Android.mk文件中的LOCAL_INIT_RC宏在構建過程當中將logcatd.rc放在/ system / etc / init /中。Init在mount_all命令期間加載logcatd.rc並容許運行服務並在適當時排隊操做。
根據其守護進程分解init .rc文件比之前使用的單片init .rc文件更受歡迎。這種方法確保init讀取的惟一服務條目和init執行的惟一操做對應於其二進制文件實際存在於文件系統上的服務,而單片init .rc文件則否則。當將多個服務添加到系統時,這另外將有助於合併衝突解決,由於每一個服務將進入單獨的文件。
mount_all命令中有兩個選項「early」和「late」,能夠在可選路徑以後設置。設置「--early」後,init可執行文件將跳過帶有「latemount」標誌的掛載條目並觸發fs加密狀態事件。設置「--late」後,init可執行文件只會掛載帶有「latemount」標誌的條目,但會跳過導入rc文件。默認狀況下,不設置任何選項,mount_all將處理給定fstab中的全部條目。
Actions
actions由一系列命令組成。actions具備觸發器,用於肯定什麼時候執行操做。當一個事件與一個actions的觸發器匹配時,該action被添加到一個待執行隊列的尾部(除非它已經在隊列中)。
隊列中的每一個操做都按順序出列,而且該操做中的每一個命令都按順序執行。Init處理活動中命令執行之間的其餘活動(設備建立/銷燬,屬性設置,進程重啓)。
Actions採起如下形式:
在<trigger> [&& <trigger>] *
<命令>
<命令>
<命令>
操做將添加到隊列中,並根據解析包含它們的文件的順序執行(請參閱「導入」部分),而後按順序在單個文件中執行。
例如,若是文件包含:
on boot
setprop a 1
setprop b 2
on boot && property:true = true
setprop c 1
setprop d 2
on boot
setprop e 1
setprop f 2
而後當boot觸發器發生而且假設屬性true等於時true,執行的命令的順序將是:
setprop a 1
setprop b 2
setprop c 1
setprop d 2
setprop e 1
setprop f 2
Services
服務是init退出時啓動和(可選)從新啓動的程序。服務採起如下形式:
service <name> <pathname> [<argument>] *
<選項>
<選項>
...
Options
選項是服務的修飾符。它們會影響init運行服務的方式和時間。
capabilities <capability> [ <capability>\* ]
執行此服務時設置功能。'capability'應該是沒有「CAP_」前綴的Linux功能,如「NET_ADMIN」或「SETPCAP」。有關Linux功能的列表,請參見http://man7.org/linux/man-pages/man7/capabilities.7.html。
class <name> [ <name>\* ]
指定服務的類名。命名類中的全部服務能夠一塊兒啓動或中止。若是未經過class選項指定服務,則服務在「默認」類中。除了(必需的)第一個以外的其餘類名用於對服務進行分組。該animation級應包括全部必要的兩種開機動畫和關機動畫服務。因爲這些服務能夠在啓動期間很早啓動,而且能夠運行到關閉的最後階段,所以沒法保證對/ data分區的訪問。這些服務能夠檢查/ data下的文件,但它不該該保持文件打開,而且在/ data不可用時應該工做。
console [<console>]
此服務須要一個控制檯。可選的第二個參數選擇特定的控制檯而不是默認控制檯。能夠經過設置「androidboot.console」內核參數來更改默認的「/ dev / console」。在全部狀況下,應省略前導「/ dev /」,所以「/ dev / tty0」將被指定爲「console tty0」。
critical
這是一項設備關鍵型服務。若是它在四分鐘內退出四次以上,設備將重啓進入恢復模式。
disabled
此服務不會自動從其類開始。它必須經過名稱或接口名稱顯式啓動。
enter_namespace <type> <path>
輸入位於path的類型類型的命名空間。類型設置爲「net」時僅支持網絡命名空間。請注意,只能輸入給定類型的一個名稱空間。
file <path> <type>
打開文件路徑並將其fd傳遞給已啓動的進程。type必須是「r」,「w」或「rw」。對於本機可執行文件,請參閱libcutils android_get_control_file()。
group <groupname> [ <groupname>\* ]
在執行此服務以前更改成「groupname」。除了(必需的)第一個以外的其餘組名用於設置進程的補充組(經過setgroups())。目前默認爲root。(???可能默認爲沒人)
interface <interface name> <instance name>
將此服務與其提供的HIDL服務列表相關聯。接口名稱必須是徹底限定名稱,而不是值名稱。這用於容許hwservicemanager懶洋洋地啓動服務。例如:interface vendor.foo.bar@1.0 :: IBaz默認值
ioprio <class> <priority>
經過SYS_ioprio_set系統調用爲此服務設置IO優先級和IO優先級。class必須是「rt」,「be」或「idle」之一。priority必須是0到7範圍內的整數。
keycodes <keycode> [ <keycode>\* ]
設置將觸發此服務的密鑰代碼。若是同時按下與傳遞的鍵碼對應的全部鍵,則服務將開始。這一般用於啓動錯誤報告服務。
memcg.limit_in_bytes <value>
將子目錄的memory.limit_in_bytes設置爲指定值(僅當安裝了memcg時),該值必須等於或大於0。
memcg.soft_limit_in_bytes <value>
將子節點的memory.soft_limit_in_bytes設置爲指定的值(僅當安裝了memcg時),該值必須等於或大於0。
memcg.swappiness <value>
將子目錄的memory.swappiness設置爲指定值(僅當安裝了memcg時),該值必須等於或大於0。
namespace <pid|mnt>
在分叉服務時輸入新的PID或mount命名空間。
oneshot
退出時不要從新啓動服務。
onrestart
服務從新啓動時執行命令(見下文)。
oom_score_adjust <value>
將子項的/ proc / self / oom_score_adj設置爲指定值,該值必須介於-1000到1000之間。
override
表示此服務定義旨在覆蓋具備相同名稱的服務的先前定義。這一般意味着/ odm上的服務能夠覆蓋/ vendor上定義的服務。init使用此關鍵字解析的最後一個服務定義是服務定義將用於此服務。請密切關注init.rc文件的解析順序,由於它具備一些特性,以便向後兼容。此文件的「導入」部分提供了有關訂單的更多詳細信息。
priority <priority>
調度服務進程的優先級。該值必須在-20到19的範圍內。默認優先級爲0.優先級經過setpriority()設置。
rlimit <resource> <cur> <max>
這將給定的rlimit應用於服務。rlimits由子進程繼承,所以這有效地將給定的rlimit應用於此服務啓動的進程樹。它的解析相似於下面指定的setrlimit命令。
seclabel <seclabel>
在執行此服務以前更改成「seclabel」。主要供從rootfs運行的服務使用,例如ueventd,adbd。系統分區上的服務能夠基於其文件安全上下文使用策略定義的轉換。若是未指定且策略中未定義轉換,則默認爲init上下文。
setenv <name> <value>
在啓動的進程中將環境變量名稱設置爲value。
shutdown <shutdown_behavior>
設置服務進程的關閉行爲。若是未指定,則在關閉過程當中使用SIGTERM和SIGKILL終止服務。shutdown_behavior爲「critical」的服務在關閉期間不會被終止,直到關閉超時。當關機超時時,即便標記爲「關鍵關鍵」的服務也將被終止。當關閉開始時標記爲「關鍵關鍵」的服務未運行時,將啓動它。
sigstop
在調用exec以前當即將SIGSTOP發送到服務。這是用於調試。請參閱如下有關如何使用它的調試部分。
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
建立名爲/ dev / socket / name的unix域套接字,並將其fd傳遞給已啓動的進程。 type必須是「dgram」,「stream」或「seqpacket」。用戶和組默認爲0.'seclabel'是套接字的SELinux安全上下文。它默認爲服務安全性上下文,由seclabel指定或基於服務可執行文件安全性上下文計算。對於本機可執行文件,請參閱libcutils android_get_control_socket()。
user <username>
在執行此服務以前更改成「用戶名」。目前默認爲root。(???可能默認爲nobody)從Android M開始,進程應該使用此選項,即便它們須要Linux功能。之前,要得到Linux功能,進程須要以root身份運行,請求功能,而後轉到所需的uid。經過fs_config有一種新機制允 許設備製造商將Linux功能添加到應該使用的文件系統上的特定二進制文件中。http://source.android.com/devices/tech/config/filesystem.html上介紹了此機制。使用此新機制時,進程可使用user選項選擇所需的uid,而無需以root身份運行。從Android O開始,進程也能夠直接在.rc文件中請求功能。請參閱下面的「功能」選項。
writepid <file> [ <file>\* ]
在分叉時將孩子的pid寫入給定的文件。意味着cgroup / cpuset的使用。若是沒有指定/ dev / cpuset /下的文件,可是系統屬性'ro.cpuset.default'被設置爲非空的cpuset名稱(例如'/ foreground'),則pid被寫入文件/ dev / cpuset / cpuset_name / tasks。
Triggers
觸發器是一些字符串,可用於匹配某些類型的事件並用於致使Action發生。
觸發器細分爲事件觸發器和屬性觸發器。
事件觸發器是由「trigger」命令或init可執行文件中的QueueEventTrigger()函數觸發的字符串。它們採用簡單字符串的形式,例如'boot'或'late-init'。
屬性觸發器是當命名屬性將值更改成給定新值或命名屬性將值更改成任何新值時觸發的字符串。它們分別採用'property:='和'property:= *'的形式。在init的初始引導階段,還會相應地評估和觸發屬性觸發器。
Action能夠有多個屬性觸發器,但可能只有一個事件觸發器。
例如:on boot && property:a=b定義僅在「boot」事件觸發器發生且屬性a等於b時執行的操做。
on property:a=b && property:c=d 定義了三次執行的操做:
Commands
bootchart [start|stop]
啓動/中止啓動。這些文件存在於默認的init.rc文件中,但只有文件/ data / bootchart / enabled存在時,纔會激活啓動圖; 不然bootchart start / stop是no-ops。
chmod <octal-mode> <path>
更改文件訪問權限。
chown <owner> <group> <path>
更改文件全部者和組。
class_start <serviceclass>
若是還沒有運行,則啓動指定類的全部服務。有關啓動服務的更多信息,請參閱開始條目。
class_stop <serviceclass>
若是當前正在運行,則中止並禁用指定類的全部服務。
class_reset <serviceclass>
若是當前正在運行,則中止指定類的全部服務,而不由用它們。它們能夠在之後從新啓動class_start。
class_restart <serviceclass>
從新啓動指定類的全部服務。
copy <src> <dst>
複製文件。與write相似,但對二進制/大量數據有用。關於src文件,不容許從符號連接文件和世界可寫或組可寫文件進行復制。關於dst文件,若是不存在,則建立的默認模式爲0600。若是dst文件是普通的常規文件而且已經存在,它將被截斷。
domainname <name>
設置域名。
enable <servicename>
將已禁用的服務轉換爲已啓用的服務,就像服務未指定已禁用同樣。若是該服務應該正在運行,它將當即啓動。一般在引導加載程序設置指示特定服務的變量時使用,以便在須要時啓動。例如
在屬性上:ro.boot.myfancyhardware = 1
啓用my_fancy_service_for_my_fancy_hardware
exec [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]
使用給定參數fork和execute命令。該命令在「 - 」以後開始,以即可以提供可選的安全上下文,用戶和補充組。在此完成以前,不會運行任何其餘命令。seclabel能夠是 - 表示默認值。屬性在參數內擴展。Init中止執行命令,直到分叉進程退出。
exec_background [ <seclabel> [ <user> [ <group>\* ] ] ] -- <command> [ <argument>\* ]
使用給定參數fork和execute命令。這與exec命令相似地處理。區別在於init在進程退出以前不會暫停執行命令exec_background。
exec_start <service>
啓動給定服務並中止處理其餘init命令,直到它返回。該命令的功能與exec命令相似,但使用現有的服務定義來代替exec參數向量。
export <name> <value>
在全局環境中將環境變量名稱設置爲value(將在執行此命令後由全部進程繼承)
hostname <name>
設置主機名。
ifup <interface>
使網絡接口接口聯機。
insmod [-f] <path> [<options>]
使用指定選項在路徑中安裝模塊。-f:強制安裝模塊,即便正在運行的內核的版本和編譯模塊的內核版本不匹配。
load_all_props
從/ system,/ vendor等加載屬性。這包含在默認的init.rc中。
load_persist_props
在解密/ data時加載持久性屬性。這包含在默認的init.rc中。
loglevel <level>
將內核日誌級別設置爲level。屬性在級別內擴展。
mkdir <path> [mode] [owner] [group]
在路徑中建立目錄,可選擇使用給定模式,全部者和組。若是未提供,則使用權限755建立目錄,並由root用戶和根組擁有。若是提供,則若是目錄已存在,則將更新模式,全部者和組。
mount_all <fstab> [ <path> ]\* [--<option>]
在給定的fs_mgr-format fstab上調用fs_mgr_mount_all並在指定的路徑上導入.rc文件(例如,在剛安裝的分區上),並選擇「early」和「late」選項。有關詳細信息,請參閱「Init .rc文件」部分。
mount <type> <device> <dir> [ <flag>\* ] [<options>]
嘗試將命名設備掛載到目錄dir _flag_s包括「ro」,「rw」,「remount」,「noatime」,... 選項包括「barrier = 1」,「noauto_da_alloc」,「discard」,...做爲逗號分隔的字符串,例如:barrier = 1,noauto_da_alloc
restart <service>
中止並從新啓動正在運行的服務,若是服務當前正在從新啓動,則不執行任何操做,不然,它只會啓動該服務。
restorecon <path> [ <path>\* ]
將path命名的文件還原到file_contexts配置中指定的安全上下文。init.rc建立的目錄不須要,由於init會自動標記這些目錄。
restorecon_recursive <path> [ <path>\* ]
遞歸地將path命名的目錄樹恢復到file_contexts配置中指定的安全上下文。
rm <path>
在給定路徑上調用unlink(2)。您可能但願使用「exec - rm ...」(假設系統分區已經安裝)。
rmdir <path>
在給定路徑上調用rmdir(2)。
readahead <file|dir> [--fully]
在給定目錄中的文件或文件上調用readahead(2)。使用選項--fully讀取完整的文件內容。
setprop <name> <value>
將系統屬性名稱設置爲value。屬性在值內擴展。
setrlimit <resource> <cur> <max>
設置資源的rlimit。這適用於設置限制後啓動的全部進程。它旨在早期在init中設置並在全球範圍內應用。資源最好使用其文本表示('cpu','rtio'等或'RLIM_CPU','RLIM_RTIO'等)指定。它也能夠指定爲資源枚舉對應的int值。
start <service>
若是服務還沒有運行,請啓動它。請注意,這不是同步的,即便它是,也不能保證操做系統的調度程序將充分執行服務以保證服務狀態的任何信息。
這將建立一個重要的後果是,若是該服務提供的功能的其餘服務,如提供通訊通道,只需啓動該服務以前,這些服務是不足夠的,以保證通道已經創建這些服務提出要求以前。必須有一個單獨的機制來作出任何此類保證。
stop <service>
若是服務當前正在運行,請中止運行。
swapon_all <fstab>
在給定的fstab文件上調用fs_mgr_swapon_all。
symlink <target> <path>
在路徑上使用值target建立符號連接
sysclktz <mins_west_of_gmt>
設置系統時鐘基準(若是系統時鐘以GMT爲單位,則爲0)
trigger <event>
觸發事件。用於對來自其餘操做的操做進行排隊。
umount <path>
卸載在該路徑上安裝的文件系統。
verity_load_state
用於加載dm-verity狀態的內部實現細節。
verity_update_state <mount-point>
內部實現細節用於更新dm-verity狀態並設置分區。adb remount使用的mount-point .verified屬性,由於fs_mgr沒法直接設置它們。
wait <path> [ <timeout> ]
輪詢存在給定文件並在找到時返回,或者已達到超時。若是未指定超時,則當前默認爲五秒。
wait_for_prop <name> <value>
等待系統屬性名稱爲值。屬性在值內擴展。若是屬性名稱已設置爲值,請當即繼續。
write <path> <content>
在路徑中打開文件,並使用write(2)向其寫入一個字符串。若是該文件不存在,則將建立該文件。若是確實存在,則會被截斷。屬性在內容中擴展。
Imports
import <path>
解析init配置文件,擴展當前配置。若是path是目錄,則將目錄中的每一個文件解析爲配置文件。它不是遞歸的,不會解析嵌套目錄。
import關鍵字不是命令,而是它本身的部分,這意味着它不會做爲Action的一部分發生,而是在解析文件時處理導入並遵循如下邏輯。
init可執行文件導入.rc文件的次數只有三次:
因爲遺留緣由並保持向後兼容性,導入文件的順序有點複雜。它沒有嚴格的保證。
保證在另外一個命令以前運行命令的惟一正確方法是:1)將其置於具備較早執行觸發器的Action中,或者2)將其置於具備相同觸發器的Action中早先的一行。
儘管如此,第一階段安裝設備的實際訂單是:
下面的僞代碼能夠更清楚地解釋這個:
fn Import(file)
Parse(file)
for(import:file.imports)
Import(import)
Import(/init.rc)
Directories = [/ system / etc / init,/ vendor / etc / init,/ odm / etc / init]
for(directories:Directories)
files = <Alphabetical order of directory's contents>
for(file:files)
Import(file)
Properties
Init經過如下屬性提供有關其負責的服務的信息。
init.svc.<name>
命名服務的狀態(「中止」,「中止」,「運行」,「從新啓動」)
Boot timing
Init在系統屬性中記錄一些啓動時序信息。
ro.boottime.init
在ns中啓動後的時間(經過CLOCK_BOOTTIME時鐘),init的第一個階段開始。
ro.boottime.init.selinux
第一階段初始化SELinux須要多長時間。
ro.boottime.init.cold_boot_wait
init等待ueventd的冷啓動階段結束的時間。
ro.boottime.<service-name>
在ns中啓動後的時間(經過CLOCK_BOOTTIME時鐘)服務首次啓動。
Bootcharting
此版本的init包含執行「bootcharting」的代碼:生成日誌文件,之後能夠經過http://www.bootchart.org/提供的工具進行處理。
在模擬器上,使用-bootchart timeout選項以在超時秒激活的bootcharting的狀況下引導。
在設備上:
adb shell'touch / data / bootchart / enabled'
完成數據收集後,別忘了刪除此文件!
日誌文件寫入/ data / bootchart /。提供了一個腳原本檢索它們並建立一個bootchart.tgz文件,該文件能夠與bootchart命令行實用程序一塊兒使用:
sudo apt-get install pybootchartgui
#grab-bootchart.sh使用$ ANDROID_SERIAL。
$ ANDROID_BUILD_TOP /系統/核心/ INIT / grab-bootchart.sh
須要注意的一點是,啓動圖將顯示init,就好像它開始在0運行同樣。當內核實際啓動init時,你必須查看dmesg才能解決問題。
比較兩個引導圖
名爲compare-bootcharts.py的便捷腳本可用於比較所選進程的開始/結束時間。前面提到的grab-bootchart.sh將在/ tmp / android-bootchart中留下名爲bootchart.tgz的bootchart tarball。若是在主機上在不一樣目錄下保留了兩個這樣的barball,則腳本能夠列出時間戳差別。例如:
用法:system / core / init / compare-bootcharts.py base-bootchart-dir exp-bootchart-dir
process:baseline(delta) - Unit is ms(系統上jiffy爲10 ms)
------------------------------------
/ init:50 40(-10)
/ system / bin / surfaceflinger:4320 4470(+150)
/ system / bin / bootanimation:6980 6990(+10)
zygote64:10410 10640(+230)
zygote:10410 10640(+230)
system_server:15350 15150(-200)
bootanimation ends at:33790 31230(-2560)
Systrace
Systrace(http://developer.android.com/tools/help/systrace.html)可用於在userdebug或eng版本的引導期間獲取性能分析報告。
如下是「wm」和「am」類別的跟蹤事件示例:
$ ANDROID_BUILD_TOP / external / chromium-trace / systrace.py \
wm am --boot
此命令將致使設備從新啓動。從新啓動設備並完成引導順序後,將從設備獲取跟蹤報告,並經過按Ctrl + C將其寫爲主機上的trace.html。
限制:在加載持久屬性後啓動記錄跟蹤事件,所以不記錄在此以前發出的跟蹤事件。vold,surfaceflinger和servicemanager等幾個服務受此限制的影響,由於它們是在加載持久屬性以前啓動的。Zygote初始化和從受精卵分叉的進程不受影響。
調試init
建議不使用init啓動init服務,由於init會設置難以手動複製的大量環境(用戶,組,安全標籤,功能等)。
若是須要從一開始就調試服務,sigstop則添加服務選項。此選項將在調用exec以前當即將SIGSTOP發送到服務。這給出了一個窗口,開發人員能夠在使用SIGCONT繼續服務以前附加調試器,strace等。
也能夠經過ctl.sigstop_on和ctl.sigstop_off屬性動態控制此標誌。
下面是經過上面的動態調試logd的示例:
stop logd
setprop ctl.sigstop_on logd
start logd
ps -e | grep logd
> logd 4343 1 18156 1684 do_signal_stop 538280 T init
gdbclient.py -p 4343
b main
C
C
C
>breakpoint 1,main(argc = 1,argv = 0x7ff8c9a488)at system / core / logd / main.cpp:427
如下是使用strace執行相同操做的示例
stop logd
setprop ctl.sigstop_on logd
start logd
ps -e | grep logd
> logd 4343 1 18156 1684 do_signal_stop 538280 T init
strace -p 4343
(From different shell)
kill -SIGCONT 4343
> strace runs
主機Init腳本驗證
在構建期間檢查Init腳本的正確性。具體來講,檢查如下內容。
init腳本的其餘部分僅在運行時解析,所以在構建期間不進行檢查,其中包括如下內容。