前一篇主要講解了init進程如何建立套接字以處理子進程終止,接下來咱們繼續分析init進程啓動屬性服務,以及分析init.rc的過程。linux
接下來init進程須要設置系統屬性,如代碼3-16所示。socket
property_load_boot_defaults(); export_oem_lock_status();
代碼 3-16 main()-設置系統屬性函數
property_load_boot_defaults()函數實際上就是調用load_properties_from_file()[1]函數解析「/default.prop」配置文件,而後根據解析的結果設置系統屬性。export_oem_lock_status()函數根據系統狀態設置「ro.boot.flash.locked」屬性。這部分代碼較爲簡單,不深刻分析。ui
而後啓動屬性服務,它是init進程最主要的功能之一。init進程在共享內存區域中,建立並初始化屬性域。其它進程能夠訪問屬性域中的值,但更改屬性值僅能在init進程中進行。其它進程修改屬性值時,要預先向init進程提交屬性值變動申請,而後init進程處理該申請並修改屬性值。在訪問和修改屬性時,init進程均可以進行權限控制。code
start_property_service();
代碼 3-17 main()-啓動屬性服務隊列
如前所述,屬性值的更改僅能在init進程中進行,爲此init進程生成「/dev/socket/property_service」套接字,以接收其它進程提交的申請。進程
接下來init進程開始解析init.rc文件並執行相關的命令。init.rc文件大體分爲兩大部分,一部分是以「on」關鍵字開頭的動做列表(Action List),另外一部分是以「service」關鍵字開頭的服務列表(Service List)。動做列表用於建立所需目錄,以及爲某些特定文件指定權限,而服務列表用來記錄init進程須要啓動的一些子進程。此外,還有一個關鍵字「import」,用於導入另一個.rc文件,解析生成動做列表和服務列表,這些列表會分別被添加到init.rc文件已生成的服務列表和動做列表中。事件
代碼3-18所示建立了init.rc所需的解析器(Parser),用於解析「service」、「on」、「import」等關鍵字開始的列表。內存
const BuiltinFunctionMap function_map; Action::set_function_map(&function_map); Parser& parser = Parser::GetInstance(); parser.AddSectionParser("service",std::make_unique<ServiceParser>()); parser.AddSectionParser("on", std::make_unique<ActionParser>()); parser.AddSectionParser("import", std::make_unique<ImportParser>());
代碼 3-18 main()-建立init.rc解析器cmd
而後便開始解析init.rc文件。init.rc文件是在init進程啓動後執行的啓動腳本,文件中記錄着init進程執行的功能。在Linux系統中,它被定義在根文件系統的「/etc/rc.d/」目錄下,是啓動時的可執行文件,在「/etc」目錄下保存着設置環境變量的腳本。但在Android系統中,僅使用init.rc與init.{hardware}.rc兩個文件,init.rc文件在Android系統運行過程當中用於通用的環境設置及進程相關的定義,init.{hardware}.rc用於定義Android在不一樣平臺下的特定進程和環境設置等。
parser.ParseConfig("/init.rc");
代碼 3-19 main()-解析init.rc文件
ParseConfig()方法傳入參數是「/init.rc」,解析運行時與init進程同在根目錄下的init.rc[2]文件。ParseConfig()方法實質上是調用ParseData()方法進行解析。執行該方法,讀取並分析init.rc文件後,生成服務列表與動做列表。相對之前的代碼,在Android 7.0的代碼中,init.rc文件的解析已經作了較好的封裝,動做列表解析後保存在ActionManager[3]類的actions_向量中,相似的,服務列表保存到ServiceManager[4]類的services_向量中。
init進程會依次執行「early-init,init,late-init」片斷中的命令,如代碼3-20所示,init進程利用參數構造EventTrigger,而後加入到trigger_queue_中,後續init進程處理trigger事件時,將會觸發相應的操做。init進程在後續代碼依次構造了「early-init」、「init」、「late-init」的事件觸發器,代碼僅以構造「early-init」觸發器爲例。
am.QueueEventTrigger("early-init");
代碼 3-20 main()-向執行隊列中添加命令
下面的代碼構造新的action加入到actions_中,第一個參數做爲新建action攜帶cmd的執行函數;第二個參數既做爲action的trigger name,也做爲action攜帶cmd的參數。
// Queue an action that waits for coldboot done so we know ueventd has set up all of /dev... am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done"); // ... so that we can start queuing up actions that require stuff from /dev. am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits"); am.QueueBuiltinAction(keychord_init_action, "keychord_init"); am.QueueBuiltinAction(console_init_action, "console_init");
代碼 3-21 main()-構造新的Action
init進程在緊接着還會構造幾個action,使用方法與上述代碼很是相似,此處再也不贅述。下一篇咱們將講解init進程如何處理上文構造出來的這些trigger、action和service。
[1] load_properties_from_file()函數定義在system/core/init/property_service.cpp。
[2] init.rc文件在編譯前,定義在system/core/rootdir/init.rc中。
[3] ActionManager定義在system/core/init/action.h中。
[4] ServiceManager定義在system/core/init/service.h中。