init進程詳細分析
概述
android設備上電,引導程序引導進入boot(通常是uboot),加載initramfs、kernel鏡像,啓動kernel後,進入用戶態程序。第一個用戶空間程序是init,PID固定是1.在android系統上,init的代碼位於/system/core/init下,基本功能有:
- 管理設備
- 解析並處理啓動腳本init.rc
- 實時維護這個init.rc中的服務
流程分析
這些init.rc只是語法文件,並不是程序,真正的入口則是上面提到的system/core/init/init.cpp .
對比老版本差異
在Android Q中,對該機制做了一些改變 。
單一的init.rc,被拆分,服務根據其二進制文件的位置(/system,/vendor,/odm)定義到對應分區的etc/init目錄中,每個服務一個rc文件。與該服務相關的觸發器、操作等也定義在同一rc文件中。
/system/etc/init,包含系統核心服務的定義,如SurfaceFlinger、MediaServer、Logcatd等。
/vendor/etc/init, SOC廠商針對SOC核心功能定義的一些服務。比如高通、MTK某一款SOC的相關的服務。
/odm/etc/init,OEM/ODM廠商如小米、華爲、OPP其產品所使用的外設以及差異化功能相關的服務。
這樣的目錄結構拆分,也與Android產品的開發流程相吻合,減輕了維護的負擔。下圖爲Android Q 中定義的所有服務。
k62v1_64_bsp$ find ./ -name "*.rc"
:
```
./recovery/root/init.rc
./recovery/root/ueventd.rc
./recovery/root/init.recovery.mt6762.rc
./recovery/root/init.recovery.mt6765.rc
./vendor/ueventd.rc
./vendor/etc/init/init.wmt_drv.rc
./vendor/etc/init/init.volte_imsm_93.rc
./vendor/etc/init/mtk_agpsd_p.rc
./vendor/etc/init/bootperf.rc
./vendor/etc/init/audiocmdservice_atci.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/init.volte_stack.rc
./vendor/etc/init/init_connectivity.rc
./vendor/etc/init/init.fmradio_drv.rc
./vendor/etc/init/netdagent.rc
./vendor/etc/init/atcid_eng.rc
./vendor/etc/init/init.vtservice_hidl.rc
./vendor/etc/init/mtkrild.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/init.wfca.rc
./vendor/etc/init/modemdbfilter_service.rc
./vendor/etc/init/init.bt_drv.rc
./vendor/etc/init/init.gps_drv.rc
./vendor/etc/init/aee_aedv64.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/init.thermal_manager.rc
./vendor/etc/init/init.bip.rc
./vendor/etc/init/init.cccimdinit.rc
./vendor/etc/init/md_monitor.rc
./vendor/etc/init/muxreport.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/init.wlan_drv.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/wlan_assistant.rc
./vendor/etc/init/camerahalserver.rc
./vendor/etc/init/atci_service.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/ipsec_mon.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/init.thermalloadalgod.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/lbs_hidl_service.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/hostapd.android.rc
./vendor/etc/init/init.thermal.rc
./vendor/etc/init/fuelgauged_nvram_init.rc
./vendor/etc/init/em_hidl_eng.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/init.cccirpcd.rc
./vendor/etc/init/init.volte_md_status.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/aee_aedv.rc
./vendor/etc/init/init.cccifsd.rc
./vendor/etc/init/gsm0710muxd.rc
./vendor/etc/init/loghidlvendorservice.rc
./vendor/etc/init/fuelgauged_init.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/ppl_agent.rc
./vendor/etc/init/hw/init.project.rc
./vendor/etc/init/hw/init.sensor_1_0.rc
./vendor/etc/init/hw/init.mt6765.rc
./vendor/etc/init/hw/meta_init.connectivity.rc
./vendor/etc/init/hw/meta_init.project.rc
./vendor/etc/init/hw/multi_init.rc
./vendor/etc/init/hw/factory_init.project.rc
./vendor/etc/init/hw/factory_init.rc
./vendor/etc/init/hw/init.mt6762.rc
./vendor/etc/init/hw/init.mt6765.usb.rc
./vendor/etc/init/hw/factory_init.connectivity.rc
./vendor/etc/init/hw/init.connectivity.rc
./vendor/etc/init/hw/init.aee.rc
./vendor/etc/init/hw/init.modem.rc
./vendor/etc/init/hw/init.ago.rc
./vendor/etc/init/hw/meta_init.modem.rc
./vendor/etc/init/hw/meta_init.rc
./vendor/etc/init/init.md_apps.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/init.volte_ua.rc
./vendor/etc/init/nvram_daemon.rc
./vendor/etc/init/init.wod.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/init.volte_imcb.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./vendor/etc/init/vndservicemanager.rc
./vendor/etc/init/[email protected]
./vendor/etc/init/[email protected]
./system/apex/com.android.media.swcodec/etc/init.rc
./system/etc/init/mdlogger.rc
./system/etc/init/atrace.rc
./system/etc/init/mediaextractor.rc
./system/etc/init/surfaceflinger.rc
./system/etc/init/ashmemd.rc
./system/etc/init/[email protected]
./system/etc/init/uncrypt.rc
./system/etc/init/camerapostalgo.rc
./system/etc/init/bootlogoupdater.rc
./system/etc/init/art_apex_boot_integrity.rc
./system/etc/init/usbd.rc
./system/etc/init/modemdbfilter_client.rc
./system/etc/init/atci_service_sys.rc
./system/etc/init/drmserver.rc
./system/etc/init/recovery-persist.rc
./system/etc/init/aee_aed64.rc
./system/etc/init/keystore.rc
./system/etc/init/wait_for_keymaster.rc
./system/etc/init/mobile_log_d.rc
./system/etc/init/mediaserver.rc
./system/etc/init/hwservicemanager.rc
./system/etc/init/init-debug.rc
./system/etc/init/gpuservice.rc
./system/etc/init/logd.rc
./system/etc/init/incidentd.rc
./system/etc/init/servicemanager.rc
./system/etc/init/lpdumpd.rc
./system/etc/init/idmap2d.rc
./system/etc/init/bootstat.rc
./system/etc/init/blank_screen.rc
./system/etc/init/bootstat-debug.rc
./system/etc/init/storaged.rc
./system/etc/init/netd.rc
./system/etc/init/mediametrics.rc
./system/etc/init/mediadrmserver.rc
./system/etc/init/wificond.rc
./system/etc/init/vdc.rc
./system/etc/init/cameraserver.rc
./system/etc/init/gsid.rc
./system/etc/init/consyslogger.rc
./system/etc/init/logtagd.rc
./system/etc/init/malloc_debug_option.rc
./system/etc/init/bootanim.rc
./system/etc/init/logcatd.rc
./system/etc/init/batterywarning.rc
./system/etc/init/statsd.rc
./system/etc/init/perfetto.rc
./system/etc/init/init.connectivity.rc
./system/etc/init/flags_health_check.rc
./system/etc/init/mtpd.rc
./system/etc/init/init.thermald.rc
./system/etc/init/mdnsd.rc
./system/etc/init/duraspeed.rc
./system/etc/init/emdlogger3.rc
./system/etc/init/audioserver.rc
./system/etc/init/terserver.rc
./system/etc/init/heapprofd.rc
./system/etc/init/netdiag.rc
./system/etc/init/bpfloader.rc
./system/etc/init/init.vtservice.rc
./system/etc/init/hw/init.aee.rc
./system/etc/init/hw/vendor_init_as_system.rc
./system/etc/init/emdlogger5.rc
./system/etc/init/iorapd.rc
./system/etc/init/wifi-events.rc
./system/etc/init/tombstoned.rc
./system/etc/init/kpoc_charger.rc
./system/etc/init/apexd.rc
./system/etc/init/traceur.rc
./system/etc/init/[email protected]
./system/etc/init/gatekeeperd.rc
./system/etc/init/atrace_userdebug.rc
./system/etc/init/lmkd.rc
./system/etc/init/rss_hwm_reset.rc
./system/etc/init/installd.rc
./system/etc/init/racoon.rc
./system/etc/init/emdlogger2.rc
./system/etc/init/emdlogger1.rc
./system/etc/init/em_svr.rc
./system/etc/init/dumpstate.rc
./system/etc/init/aee_aed.rc
./system/etc/init/vold.rc
./root/init.rc
./root/init.zygote32.rc
./root/init.environ.rc
./root/ueventd.rc
./root/init.zygote64_32.rc
./root/init.preload.rc
./root/init.usb.configfs.rc
./root/init.usb.rc
```
init.rc定位
- init的源碼位於system/core/init包下,我們先從入口類main.cpp來看
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
__asan_set_error_report_callback(AsanReportCallback);
#endif
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv); //ueventd.cpp入口函數,初始化uevent
}
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap function_map;
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
// This function initializes SELinux then execs init to run in the init SELinux context.
return SetupSelinux(argv); //對SELinux進行初始化,並通過execs的系統調用開啓init進程
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv); //第二階段 init.cpp入口函數
}
}
return FirstStageMain(argc, argv); //第一階段
}
複製代碼可以看到main.cpp的函數跟之前版本有了很大的區別,拿Android9.0的源碼androidxref.com/9.0.0_r3/xr…來說,Android10中並不只是調用init::main,而是把部分流程性的判斷放到的mian.cpp中來做,所以這裏如果按照書上或者文章中所說的,直接去找init.cpp中的main函數,其實是找不到入口的。
當入口函數Init.cpp啓動加載第一個init.rc如下:
/system/core/rootdir/init.rc
/bootable/recovery/etc/init.rc
從目錄上大致可以猜測,這兩個init.rc使用場景不一樣,一個是刷機用到的,也就是進入recorvery模式,一個是正常啓動用到的;我們這裏重點分析的是正常啓動用的,也是init.c關聯的那個;
device/mediatek/mt6765/device.mk
7: PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.vendor.rc=/vendor/etc/init/hw/
919: PRODUCT_COPY_FILES += device/mediatek/mt6765/init.recovery.mt6765.rc:recovery-vendor/init.recovery.mt6765.rc
/system/core/rootdir/init.rc
:
···
import /vendor/etc/init/hw/init.${ro.hardware}.rc
···
/device/mediatek/mt6765/init.mt6765.rc
:
···
import /vendor/etc/init/hw/init.project.rc
···
device/mediateksample/k62v1_64_bsp/device.mk
:
16:PRODUCT_COPY_FILES += $(LOCAL_PATH)/init.project.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/hw/init.project.rc
根據以上內容,我們可以判斷我們OEM/ODM廠商主要修改文件是device/mediateksample/k62v1_64_bsp/init.project.rc
,而在recovery模式下主要修改init.recovery.mt6765.rc
文件。
init.rc修改規則
rc規則主要包含了四種類型的語句:
- Action
- Commands
- Services
- Options.
以下做具體詳解:
動作(Action)
動作表示了一組命令(commands)組成.動作包括一個觸發器,決定了何時運行這個動作。
注意:當觸發器的條件滿足時,這個動作會被增加到已被運行的隊列尾。假設此動作在隊列中已經存在,那麼它將不會運行.
一個動作所包括的命令將被依次運行。
on <trigger> ## 觸發條件
<command> ##執行命令
<command1> ##可以執行多個命令
- 觸發器(trigger)
在"動作"(action)裏面的,on後面跟着的字符串是觸發器(trigger),trigger是一個用於匹配某種事件類型的字符串,它將對應的Action的執行。
觸發器(trigger)有幾種格式:
1、最簡單的一種是一個單純的字符串。比如“on boot”。這種簡單的格式可以使用命令"trigger"來觸發。
2、還有一種常見的格式是"on property<屬性>=<值>"。如果屬性值在運行時設成了指定的值,則"塊"(action)中的命令列表就會執行。
常見的格式:
格式 | 含義 |
---|---|
on early-init | 在初始化早期階段觸發 |
on init | 在初始化階段觸發 |
on late-init | 在初始化晚期階段觸發 |
on boot/charger | 當系統啓動/充電時觸發 |
on property | 當屬性值滿足條件時觸發 |
commands(命令)
command是action的命令列表中的命令,或者是service中的選項 onrestart 的參數命令.
命令將在所屬事件發生時被一個個地執行.
常見命令:
命令 | 描寫敘述 |
---|---|
exec |
運行指定路徑下的程序,並傳遞參數. |
export | 設置全局環境參數。此參數被設置後對全部進程都有效. |
ifup | 使指定的網絡接口"上線",相當激活指定的網絡接口 |
import | 導入一個額外的init配置文件. |
hostname | 設置主機名 |
chdir | 改變工作文件夾. |
chmod |
改變指定文件的讀取權限. |
chown |
改變指定文件的擁有都和組名的屬性. |
chroot | 改變進行的根文件夾. |
class_start <serviceclass | 啓動指定類屬的全部服務,假設服務已經啓動,則不再反覆啓動. |
class_stop | 停止指定類屬的所胡服務. |
domainname | 設置域名 |
insmod |
安裝模塊到指定路徑. |
mkdir |
[mode] [owner] [group] 用指定參數創建一個文件夾,在默認情況下,創建的文件夾讀取權限爲755.username爲root,組名爲root. |
mount |
類似於linux的mount指令setkey TBD(To Be Determined), 待定. |
setprop | 設置屬性及相應的值. |
setrlimit | 設置資源的rlimit(資源限制),不懂就百度一下rlimit |
start | 假設指定的服務未啓動,則啓動它. |
stop | 假設指定的服務當前正在執行。則停止它. |
symlink |
創建一個符號鏈接. |
sysclktz <mins_west_of_gmt> | 設置系統基準時間. |
trigger | Trigger an event. Used to queue an action from another action. 這名話沒有理解,望高手指點. |
write |
往指定的文件寫字符串. |
服務(services)
服務是指那些須要在系統初始化時就啓動或退出時自己主動重新啓動的程序.
service <name><pathname> [ <argument> ]*
<option>
<option>
解釋一下各個參數:
參數 | 含義 |
---|---|
表示此服務的名稱 | |
此服務所在路徑因爲是可執行文件,所以一定有存儲路徑。 | |
啓動服務所帶的參數 | |
對此服務的約束選項 |
選項(option)
options是Service的修訂項。它們決定一個服務何時以及如何運行.
選項 | 描述 |
---|---|
critical | 據設備相關的關鍵服務,如果在4分鐘內,此服務重複啓動了4次,那麼設備將會重啓進入還原模式。 |
disabled | 服務不會自動運行,必須顯式地通過服務器來啓動。 |
setenv | 設置環境變量 |
socket | [ [ ] ] 在/dev/socket/下創建一個unix domain的socket,並傳遞創建的文件描述符fd給服務進程.其中type必須爲dgram或stream,seqpacket. |
user | 在執行此服務之前先切換用戶名。當前默認爲root. |
group [ ]* | 類似於user,切換組名 |
oneshot | 當此服務退出時不會自動重啓. |
class | 給服務指定一個類屬,這樣方便操作多個服務同時啓動或停止.默認情況下爲default. |
onrestart | 當服務重啓時執行一條指令, |
使用例子:
service bootanim /system/bin/bootanimation
class core //給服務指定一個類屬,這樣方便操作多個服務同時啓動或停止
user graphics //在執行此服務之前先切換用戶名
group graphics audio
disabled //服務不會自動運行
oneshot //當此服務退出時不會自動重啓
啓動順序
下面爲各個section的執行順序,英文編號的section是系統內建的(寫死在init.cpp中的命令)
1) early-init
a) wait_for_coldboot_done
b) property_init
c) keychord_int
d) console_init
2) init
3) early-fs (sys.boot_from_charger_mode=1)
4) fs
5) post-fs
6) late-fs
7) post-fs-data
8) load_persist_props_action
9) zygote-start
10) firmware_mounts_complete
11) early-boot
12) boot
13) service
所有的action運行於service之前。