init進程詳細分析--基於android 10

init進程詳細分析

概述

android設備上電,引導程序引導進入boot(通常是uboot),加載initramfs、kernel鏡像,啓動kernel後,進入用戶態程序。第一個用戶空間程序是init,PID固定是1.在android系統上,init的代碼位於/system/core/init下,基本功能有:

  • 管理設備
  • 解析並處理啓動腳本init.rc
  • 實時維護這個init.rc中的服務

image

流程分析

這些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規則主要包含了四種類型的語句:

  1. Action
  2. Commands
  3. Services
  4. Options.

以下做具體詳解:

動作(Action)

動作表示了一組命令(commands)組成.動作包括一個觸發器,決定了何時運行這個動作。

注意:當觸發器的條件滿足時,這個動作會被增加到已被運行的隊列尾。假設此動作在隊列中已經存在,那麼它將不會運行.

一個動作所包括的命令將被依次運行。

on  <trigger>      ## 觸發條件
    <command>      ##執行命令
    <command1>     ##可以執行多個命令
  1. 觸發器(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之前。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章