AndroidInitLanguage(android初始化語言)

陳洪波發表於2017-02-21
版權宣告:您好,轉載請留下本人部落格的地址,謝謝 https://blog.csdn.net/hongbochen1223/article/details/56331690

d## Android Init Language

Android初始化語言


Android初始化語言包含四個廣泛的陳述類,為Actions(行為),Commands(命令),
Services(服務)和Options(選項)。

所有的這些都是基於行的,包括空格分隔符。C風格的反斜槓可以用來插入空格到一個
命令中。雙引號可以被用來阻止空格將文字分割成多個標記。當反斜槓為一行中的最後
一個字元的時候,可以被用於換行。

以#開始的行為註釋。

Actions和Services宣告一個新的部分。所有的commands和options屬於最近宣告
的那個部分。位於第一個部分之前的Commands和Actions是被忽略的。

Actions和Services用於獨一無二的名稱。如果有一個Action或Service被宣告瞭一個
和之前相同名稱,則他被忽略為一個錯誤。

行為


Actions是被命名的命令序列。Actions有一個觸發器用來決定什麼時候這個action應該發生。
當一個時間觸發了符合一個action的觸發器,那麼這個action將被新增到要處理佇列的
尾部(除非他已經在佇列中了)。

在佇列中的每一個action都是按照順序出列的,位於那個action中的每一個command
也是按照順序執行的。在活動中,初始化處理其他活動(裝置建立和銷燬,屬性設定,
程式重啟)介於commands的執行之間。

Actions組織形式位:


    on <trigger>
       <command>
       <command>
       <command>

服務


服務是,當他們退出的時候,init程式啟動和重新啟動(可選)的程式。Services的形式為:


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

選項


選項是服務的調節器。他們影響init程式如何並且何時執行這個服務。

critical
  這是一個裝置關鍵服務。如果他在四分鐘記憶體在超過四次,裝置將會重啟進入恢復模式。

disabled
  這個服務將不能與他的類自動啟動。他必須通過名稱被顯示啟動。

setenv <名稱> <值>
  在啟動程式中設定環境變數<名稱>到<數值>

socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
  建立一個unix域套接字,命名為 /dev/socket/<name>,並且傳遞他的檔案描述符fd到啟動程式中。
  <type>必須是"dgram","stream"或者是"seqpacket"。
  User和group預設為0。
  `seclabel`是這個套接字的SELinux安全上下文。
  他預設為服務安全上下文,由seclabel指定或者是基於服務可執行檔案安全上下文計算得來。

user <username>
  在執行這個服務之前改為username(使用者名稱稱)。
  當前預設為root.目前,如果你的程式需要linux功能,那麼你不能使用這個命令。你必須在程式中
  請求功能但依然root,然後降級到你期望的uid。

group <groupname> [ <groupname> ]*
  在執行這個服務之前修改為groupname。在第一個之前的組名稱被用來設定程式的追加的組(通過setgrooups())
  。目前預設為root。

seclabel <seclabel>
  在執行這個服務之前改為seclabel。主要是從rootfs等中被services使用。
  位於系統分割槽的services可以基於他們的檔案安全上下文使用策略定義的轉換。
  如果未被指定或者是在策略中沒有轉換被定義,預設為初始化上下文。

oneshot
  當他退出的時候不要重啟服務。

class <name>
  為服務指定一個類名稱。位於一個命名的類中的所有服務一起被啟動或停止。
  如果服務未被class選項指定,則該服務位於類`default`中。

onrestart
  當services重啟的時候執行一個命令。

writepid <file...>
  當子程式被建立的時候,將子程式的pid寫入到給定的檔案中。意味著cgroup/cpuset
  用法。

觸發器


觸發器是一系列字串,被用於匹配確定種類的事件,並且被用於出發一個行為。

boot
   這是第一個觸發器,當init程式啟動的時候被觸發(在/init.conf被載入之後)。

<name>=<value>
   當屬性<name>被設定為指定的值<value>的時候,這種形式的觸發器被觸發。
   這個可以測試多個屬性去執行一組命令。例如:

   on property:test.a=1 && property:test.b=1
       setprop test.c 1

   上面的一小段只有當test.a=1和test.b=1都被設定的時候,才會設定test.1為1。

命令


bootchart_init
   如果被配置的話,開啟bootcharting。他被預設包含在init.rc中。

chmod <octal-mode> <path>
   修改檔案訪問許可權。

chown <owner> <group> <path>
   修改檔案擁有者和組。

class_start <serviceclass>
   如果他們沒有執行的話,啟動所有指定類的服務。

class_stop <serviceclas
   如果他們當前正在執行的話,停止並且禁用所有指定類的服務。

class_reset <serviceclass>
   如果他們正在執行的話,停止所有指定類的服務,並不禁用他們。後期他們使用
   class_start被重新啟動。

copy <src> <dst>
   複製一個檔案。類似於寫,但是對二進位制/大數量資料是有用的。

domainname <name>
   設定域名稱。

enable <servicename>
   將一個禁用的服務轉換為可用,好像這個服務並沒有被指定禁用過。
   如果服務期望去執行,他將會現在被啟動。特別是當bootloader設定了一個變數來指示一個指定
   的服務應該在被需要的時候啟動。
      on property:ro.boot.myfancyhardware=1
        enable my_fancy_service_for_my_fancy_hardware

exec [ <seclabel> [ <user> [ <group> ]* ] ] -- <command> [ <argument> ]*
   使用給定的引數建立並且執行命令。這個命令在"--"之後執行,所以一個可選的安全上下文,使用者,
   和追加的組可以被提供。在這個結束之前沒有其他的命令可以被執行。<seclabel>可以被一個-來
   指定為預設。

export <name> <value> 
   在全域性環境中設定環境變數<name>等於<value>。(這個命令執行之後啟動的所有
   程式都將繼承他。)

hostname <name>
   設定主機名

ifup <interface>
   將網路介面<interface>聯機。

import <filename>
   解析一個初始化配置檔案,擴充套件當前的配置。

insmod <path>
   在<path>中安裝模組

load_all_props
   從/system,/vendor等中載入屬性。這個被包含在預設的init.rc中。

load_persist_props
   當/data被加密之後,載入持久化的屬性。
   這個被包含在預設的init.rc中。

loglevel <level>
   一層一層的設定核心日誌。屬性被擴充套件到<level>中。

mkdir <path> [mode] [owner] [group]
   在路徑<path>中建立一個目錄,可選的使用給定的模式,所有者和組。如果沒有提供,該目錄則
   以許可權755被建立並且以root使用者為擁有者和以root為組。如果提供了,模式,所有者和組將會被
   更新,如果該目錄已經存在的話。

mount_all <fstab>
   在給定的fs_mgr-format fstab中呼叫fs_mgr_mount_all。

mount <type> <device> <dir> [ <flag> ]* [<options>]
   嘗試在目錄<dir>中掛載命名的裝置。<device>可以是mtd@name的形式來通過名稱
   指定一個mtd塊裝置。
   <flag>s包含"ro","rw","remount","noatime"等。
   <options>包含"barrier=1", "noauto_da_alloc", "discard"等作為一個逗號分離的字串。例如,
    barrier=1,noauto_da_alloc

powerctl
   內部實現系統用來響應改變"sys.powerctl"屬性,用於實現重啟。

restart <service>
   類似於stop,但是並不禁用服務。

restorecon <path> [ <path> ]*
   重新以file_contexts配置中指定的安全上下文來將檔案重新以<path>儲存。
   不需要被init.rc建立的目錄,因為這些都是被init初始化程式自動正確標記的。

restorecon_recursive <path> [ <path> ]*
   遞迴的重新以名稱<path>將目錄樹儲存到安全上下文中,這個安全上下文由
   file_contexts配置指定。

rm <path>
   在指定的路徑呼叫unlink(2)。你可能想要使用"exec -- rm ..."(提供的系統
   分割槽已經被掛載了)。

rmdir <path>
   對給定的目錄呼叫rmdir(2)

setprop <name> <value>
   這是系統屬性<name>到<value>。屬性被擴充套件到<value>。

setrlimit <resource> <cur> <max>
   為一個資源設定rlimit。

start <service>
   開啟一個服務執行,如果這個服務沒有執行的話。

stop <service>
   從執行的服務中停止一個服務,如果這個服務正在執行的話。

swapon_all <fstab>
   對給定的fstab檔案執行fs_mgr_swapon_all

symlink <target> <path>
   使用值<target>在<path>中建立一個符號連結。

sysclktz <mins_west_of_gmt>
   設定系統時鐘基礎(如果系統時鐘在格林尼治時間為0)

trigger <event>
    觸發一個事件。用於從另一個動作中排隊一個動作。

verity_load_state
   內部實現細節用於載入dm-verity狀態。

verity_update_state <mount_point>
  內部實現細節用於更新dm-verity狀態並且設定分割槽。<mount_point>被adb remount
   使用來驗證屬性,因為fm_mgr不能直接自己設定他們。

wait <path> [ <timeout> ]
   輪詢給定檔案的存在性,並且當找到的時候返回,或者是到達超時狀態。
   如果超時未被指定,則預設為5秒。

write <path> <content>
   在路徑<path>中開啟檔案,並且使用write(2)寫一個字串進去。
   如果檔案不存在,他將被建立。如果檔案存在,他將被覆蓋。屬性在<content>
    被擴充套件。

屬性


init程式更新一些系統屬性,並且提供一些他要幹什麼的資訊:

init.action
   相當於當前被執行的action的名稱,如果不存在則為""。

init.command
   相當於當前被執行的command,如果沒有則為""。

init.svc.<name>
   一個被命名的服務的狀態("停止","執行","重啟")。

Bootcharting


init的這個版本包含執行”bootcharting”的程式碼:生成一個日誌檔案,後期能夠被 www.bootchart.org
提供的工具處理。

在虛擬機器中,使用-bootchart 選項來使啟動的時候帶有bootcharting持續秒。

在一個裝置中,使用命令建立 /data/bootchart/start:
  adb shell `echo $TIMEOUT > /data/bootchart/start`

$TIMEOUT的值對應著期望bootchart持續的秒數。當這些時間過後,Bootcharting將會停止。

你可以通過下面的命令在任何時候停bootcharting:
  adb shell `echo 1 > /data/bootchart/stop`

注意,/data/bootchart/stop會在bootcharting最後被init自動刪除。對於/data/bootchart/start
情況並非如此,所以當你收集完資料之後,不要忘記刪除他。

日誌檔案被寫入/data/bootchart中。一個指令碼被提供去恢復他們,並且建立一個bootchart.tgz檔案
,這個檔案可以被bootchart命令列工具使用:


      sudo apt-get install pybootchartgui
      # grab-bootchart.sh uses $ANDROID_SERIAL.
      $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh

一個需要注意的事情就是,bootchart將會顯示init好像是他從0s的時候開始執行。當核心
開始init的時候,你必須檢視dmesg的工作。

Debugging init


預設的,由init執行的程式將會把標準輸出和標準錯誤丟入到/dev/null。為了幫助除錯,
你可以通過安卓程式日誌封裝程式執行你的程式。這個將會重定向標準輸出/標準錯誤到
安卓日誌系統中。

例如
service akmd /system/bin/logwrapper /sbin/akmd

當在init中自己執行的時候,為了快速的轉變,使用:


      mm -j
      m ramdisk-nodeps
      m bootimage-nodeps
      adb reboot bootloader
      fastboot boot $ANDROID_PRODUCT_OUT/boot.img

可選的,使用虛擬機器:

emulator -partition-size 1024 -verbose -show-kernel -no-window

在klog_init()呼叫之後,你可能想要呼叫klog_set_level(6),所以你需要在
dmesg或者是虛擬機器輸出中檢視核心日誌。


相關文章