|
鴻蒙OS開源代碼精要解讀之——init,
說明: 中科創(chuàng)達(dá)OpenHarmony研究組第一時(shí)間對(duì)https://codechina.csdn.net/openharmony上開源的代碼進(jìn)行了詳盡的代碼研讀和學(xué)習(xí)。為此,我們打算編寫一系列篇幅中等,內(nèi)容精煉的源碼分析文章來引領(lǐng)大家更進(jìn)一步的走進(jìn)鴻蒙OS。隨著對(duì)代碼的了解,廣大開發(fā)者想親自動(dòng)手參與的意愿和信心也會(huì)隨之增強(qiáng)——這也是鴻蒙OS開源的意義所在。
本篇內(nèi)容摘要: 本篇以O(shè)penHarmony中ipcamera_hi3518ev300為編譯目標(biāo),介紹init進(jìn)程的相關(guān)代碼。
寫在前面的話 我們對(duì)OpenHarmony的代碼進(jìn)行了一個(gè)簡單粗略的統(tǒng)計(jì)。除去所有的third_party代碼(即OpenHarmony使用的第三方開源庫),其他剩余的代碼中,以.c、.h文件為統(tǒng)計(jì)入口,總有效代碼行數(shù)(不含注釋、空行等,統(tǒng)計(jì)工具為tSourceCounter)為325627行。其中,歸屬kernel目錄下的總有效代碼行數(shù)為74150行。整個(gè)OpenHarmony中,kernel部分占比為22.8%左右,代碼量上占大頭的還在于kernel之上的、我們稱之為Framework的部分。根據(jù)我們?cè)贏ndroid系統(tǒng)上多年的摸索和經(jīng)驗(yàn),F(xiàn)ramework恰恰是Android OS的精髓。所以,以O(shè)penHarmony目前才20多萬行的Framework代碼量來看,感興趣的開發(fā)者在這塊參與共建、獻(xiàn)策獻(xiàn)力的機(jī)會(huì)非常大。
1. OpenHarmony
源碼的下載和編譯 先介紹代碼的下載和編譯。我們研究組用得是ubuntu 19.10的主機(jī)環(huán)境。
1.1
源碼下載 按照Codechina.csdn官網(wǎng)的源碼下載指南:https://codechina.csdn.net/openh ... 8%8E%B7%E5%8F%96.md 我們使用的是第四種方式“獲取方式4:從代碼倉庫獲取”。執(zhí)行這一節(jié)中的幾個(gè)命令,即可得到整個(gè)源碼倉庫。
1.2
編譯源碼 我們選擇的編譯目標(biāo)是“Hi3518解決方案”,其編譯后的輸出目錄名為ipcamera_hi3518ev300。ipcamera_hi3518ev300是一個(gè)基于海思的ip攝像頭設(shè)備。相關(guān)的介紹文檔入口在https://codechina.csdn.net/openh ... 8E%AF%E5%A2%83-2.md。 注意,編譯不同的解決方案需要建立對(duì)應(yīng)的編譯環(huán)境。對(duì)hi3518來說,開發(fā)者需要按照上述鏈接里的“搭建環(huán)境”來下載和配置。 一切就緒后,在源碼根目錄下執(zhí)行 python build.py。如果不帶參數(shù)的話,它會(huì)提醒你指定編譯目標(biāo),截圖如下: 圖1 python build.py不帶參數(shù)的執(zhí)行結(jié)果 這次,我們通過python build.py ipcamera_hi3518ev300即可編譯“Hi3518解決方案”。編譯耗時(shí)10幾分鐘。
注意,編譯過程中可能出現(xiàn)找不到<valgrind/valgrind.h>的錯(cuò)誤。這是因?yàn)槟壳拔覀兿螺d的代碼中沒有包含valgrind的頭文件。開發(fā)者可以手動(dòng)將/usr/include/valgrind目錄拷貝到prebuilts/lite/sysroot/usr/include下即可(僅限Ubuntu平臺(tái),需提前安裝好valgrind工具)。
1.3 OpenHarmony編譯相關(guān)小知識(shí)介紹 OpenHarmony源碼編譯系統(tǒng)使用了google開發(fā)的gn工具以及ninjia。這二者結(jié)合起來比傳統(tǒng)的makefile編譯系要高效,尤其適合大系統(tǒng)的并行編譯。對(duì)開發(fā)者而言,如果要參與OpenHarmony的開發(fā),需要對(duì)gn的語法有些了解。本文僅做一些最基本的介紹:
- 使用gn工具的話,開發(fā)者將編譯規(guī)則寫在名為BUILD.gn文件中。和Makefile一樣,gn文件有自己的語法規(guī)則,屬于領(lǐng)域語言(Domain Specific Language,DSL)。gn語法不難,但編譯規(guī)則本身有很多內(nèi)容,所以一下子要掌握全部內(nèi)容也不容易。
- gn支持自定義模板函數(shù),可放在名為.gni的文件中。OpenHarmony中最常見到的gn模板文件為./build/lite/config/component/lite_component.gni。.gn文件中通過import可導(dǎo)入gni模板文件。OpenHarmony定義了lite_component、lite_library等模板函數(shù)。
- gn中,可執(zhí)行文件的編譯函數(shù)入口為exectuable(“文件名“),共享庫的編譯規(guī)則函數(shù)為shared_library(“文件名“)。所以,如果要搜索某個(gè)文件對(duì)應(yīng)的編譯規(guī)則,可以先搜索所有的BUILD.gn文件,然后grep executable。以下是我們grep所有的executable的結(jié)果截圖。
圖2 grep BUILD.gn中executable的結(jié)果示意 通過這種方式,我們能很快定位到比如init對(duì)應(yīng)的代碼在什么地方。
最后,我們?cè)俸唵谓榻B下OpenHarmony編譯系統(tǒng)中和底層OS有關(guān)的一個(gè)條件編譯控制變量ohos_kernel_type。目前,該變量有四個(gè)取值,分別為“l(fā)iteos_a“、“l(fā)iteos_m“、“l(fā)iteos_riscv“和“l(fā)inux“:
- “l(fā)iteos_a“和“l(fā)inux“經(jīng)常做為一組進(jìn)行判斷。liteos_a實(shí)際對(duì)應(yīng)的是Cortex-A系列,其性能相對(duì)較高,可以跑Linux系統(tǒng)。
- “l(fā)iteos_m“和“l(fā)iteos_riscv“往往是一組的。liteos_m對(duì)應(yīng)的是Cortex-M系列,liteos_riscv是Riscv芯片的表示,二者可能都是針對(duì)性能一般,功耗較低的設(shè)備。
ohos_kernel_type的取值由build/lite/product/解決方案名.json文件中的product字段決定。例如,我們選擇的ipcamera_hi3518ev300的配置文件內(nèi)容截圖如下,它的kernel字段值為“l(fā)iteos_a“。 圖3 build/lite/product/ ipcamera_hi3518ev300.json配置文件示意圖 編譯完成后,所有編譯生成物都在out/ipcamera_hi3518ev300目錄下。
2 init
源碼精要解析 init是Linux系統(tǒng)上的第一個(gè)應(yīng)用進(jìn)程,是其它進(jìn)程的源頭。對(duì)ipcamera_hi3518ev300來說,它的編譯產(chǎn)物中也有一個(gè)init進(jìn)程。 在上面提到的out/ipcamera_hi3518ev300目錄下,有一個(gè)rootfs.tar文件。這個(gè)文件里就是設(shè)備上根文件系統(tǒng)的內(nèi)容。打開其中的/rootfs/bin目錄,可以看到此次編譯的可執(zhí)行程序如下截圖所示: 圖4 out/ipcamera_hi3518ev300/rootfs.tar/bin內(nèi)容示意 借助圖2里提到的辦法,我們可以定位到init對(duì)應(yīng)的代碼路徑為base/startup/services/init_lite/。其內(nèi)容如下圖所示: 圖5 init_lite源碼文件示意圖 main.c是整個(gè)init的入口。我們簡單看一下它的代碼,如下所示。 圖6 init_lite/main.c init main函數(shù)非常精簡,非常符合“l(fā)ite“輕量簡便的風(fēng)格。當(dāng)然,也不排除未來init的代碼會(huì)越來越復(fù)雜。我們?cè)贏OSP上觀察到的情況就是一個(gè)例子——AOSP里現(xiàn)在的init的相關(guān)代碼非常復(fù)雜)。
我們對(duì)InitReadCfg比較感興趣,這個(gè)函數(shù)內(nèi)部將讀取/etc/init.cfg文件。這個(gè)文件在圖4中提到的rootfs.tar中可以找到,下圖是其內(nèi)容的示意: 圖7 rootfs.tar/etc/init.cfg init.cfg本質(zhì)上是一個(gè)json格式的文件。它包括一個(gè)名為“jobs“的數(shù)組和一個(gè)名為“services“的數(shù)組。
- 對(duì)“jobs“來說:內(nèi)部分別包含“pre-init“、“init“和“post-init“三個(gè)元素。從上面的截圖中可以看出,這三個(gè)元素對(duì)應(yīng)的就是設(shè)置掛載一些設(shè)備、設(shè)置好路徑,啟動(dòng)服務(wù)等工作。
- 對(duì)“services“來說:它包含一組服務(wù)的定義。所謂的服務(wù),就是系統(tǒng)里的關(guān)鍵進(jìn)程?梢圆聹y(cè)到,init將根據(jù)service的配置來啟動(dòng)對(duì)應(yīng)的服務(wù)程序,并設(shè)置它的uid、gid、進(jìn)程優(yōu)先級(jí)和權(quán)限等。
如果開發(fā)者對(duì)Android系統(tǒng)有一定了解的話,會(huì)發(fā)現(xiàn)OpenHarmony和AOSP在init的工作流程上有著相似的設(shè)計(jì)思路。不過,對(duì)OpenHarmony目標(biāo)設(shè)備來說,使用json格式無疑是比較簡單且方便的。
最后,我們?cè)倏匆幌耰nit的另外一個(gè)重要職能——服務(wù)進(jìn)程狀況監(jiān)控。init.cfg中的那些服務(wù)屬于系統(tǒng)關(guān)鍵進(jìn)程。運(yùn)行過程中如果它們出現(xiàn)異常導(dǎo)致進(jìn)程退出,需要有個(gè)辦法將它們重新啟動(dòng)以保證業(yè)務(wù)連續(xù)性。
這個(gè)功能的實(shí)現(xiàn)就是利用Linux系統(tǒng)的SIGCHILD信號(hào)。init在SignalInitModule中監(jiān)聽了該信號(hào)并設(shè)置了對(duì)應(yīng)的信號(hào)處理函數(shù)——SigHandler。SigHandler函數(shù)的具體處理過程則比此處說得要更復(fù)雜一點(diǎn)。現(xiàn)在,這部分內(nèi)容就留給讀者們自行探索了。
文章轉(zhuǎn)自: 阿拉神農(nóng)(中科創(chuàng)達(dá)OpenHarmony研究組) |
|