Android 10.0系統啟動之init進程(一)-「Android取經之路」

[Android取經之路的源碼都基於Android-Q(10.0) 進行分析]

Android init 啟動進程主要分三個階段分析:

  • 概述,Init如何被啟動
  • Init進程啟動的源碼分析
  • 信號處理
  • rc語法分析
  • 啟動服務
  • 屬性服務

1.概述:

init進程是linux系統中用戶空間的第一個進程,進程號為1.

當bootloader啟動後,啟動kernel,kernel啟動完後,在用戶空間啟動init進程,再通過init進程,來讀取init.rc中的相關配置,從而來啟動其他相關進程以及其他操作。

init進程被賦予了很多重要工作,init進程啟動主要分為兩個階段:

第一個階段完成以下內容:

  • ueventd/watchdogd跳轉及環境變量設置
  • 掛載文件系統並創建目錄
  • 初始化日誌輸出、掛載分區設備
  • 啟用SELinux安全策略
  • 開始第二階段前的準備

第二個階段完成以下內容:

  • 初始化屬性系統
  • 執行SELinux第二階段並恢復一些文件安全上下文
  • 新建epoll並初始化子進程終止信號處理函數
  • 設置其他系統屬性並開啟屬性服務

2.架構

2.1 Init進程如何被啟動?

Android 10.0系統啟動之init進程(一)-「Android取經之路」

Init進程是在Kernel啟動後,啟動的第一個用戶空間進程,PID為1。

kernel_init啟動後,完成一些init的初始化操作,然後去系統根目錄下依次找ramdisk_execute_command和execute_command設置的應用程序,如果這兩個目錄都找不到,就依次去根目錄下找 /sbin/init,/etc/init,/bin/init,/bin/sh 這四個應用程序進行啟動,只要這些應用程序有一個啟動了,其他就不啟動了。

Android系統一般會在根目錄下放一個init的可執行文件,也就是說Linux系統的init進程在內核初始化完成後,就直接執行init這個文件。

2.2Init進程啟動後,做了哪些事?

Android 10.0系統啟動之init進程(一)-「Android取經之路」

Init進程啟動後,首先掛載文件系統、再掛載相應的分區,啟動SELinux安全策略,啟動屬性服務,解析rc文件,並啟動相應屬性服務進程,初始化epoll,依次設置signal、property、keychord這3個fd可讀時相對應的回調函數。進入無線循環,用來響應各個進程的變化與重建。


3.kernel啟動init進程 源碼分析

kernel/msm-4.19/init/main.c

kernel_init()
|
run_init_process(ramdisk_execute_command) //運行可執行文件,啟動init進程
static int __ref kernel_init(void *unused)
{
\tkernel_init_freeable(); //進行init進程的一些初始化操作
\t/* need to finish all async __init code before freeing the memory */
\tasync_synchronize_full();// 等待所有異步調用執行完成,,在釋放內存前,必須完成所有的異步 __init 代碼
\tfree_initmem();// 釋放所有init.* 段中的內存
\tmark_rodata_ro(); //arm64空實現
\tsystem_state = SYSTEM_RUNNING;// 設置系統狀態為運行狀態
\tnuma_default_policy(); // 設定NUMA系統的默認內存訪問策略
\tflush_delayed_fput(); // 釋放所有延時的struct file結構體
\tif (ramdisk_execute_command) { //ramdisk_execute_command的值為"/init"
\t\tif (!run_init_process(ramdisk_execute_command)) //運行根目錄下的init程序
\t\t\treturn 0;
\t\tpr_err("Failed to execute %s\\n", ramdisk_execute_command);

\t}
\t/*
\t * We try each of these until one succeeds.
\t *
\t * The Bourne shell can be used instead of init if we are
\t * trying to recover a really broken machine.
\t */
\tif (execute_command) { //execute_command的值如果有定義就去根目錄下找對應的應用程序,然後啟動
\t\tif (!run_init_process(execute_command))
\t\t\treturn 0;
\t\tpr_err("Failed to execute %s. Attempting defaults...\\n",
\t\t\texecute_command);
\t}
\tif (!run_init_process("/sbin/init") || //如果ramdisk_execute_command和execute_command定義的應用程序都沒有找到,
\t//就到根目錄下找 /sbin/init,/etc/init,/bin/init,/bin/sh 這四個應用程序進行啟動
\t !run_init_process("/etc/init") ||
\t !run_init_process("/bin/init") ||
\t !run_init_process("/bin/sh"))
\t\treturn 0;
\tpanic("No init found. Try passing init= option to kernel. "
\t "See Linux Documentation/init.txt for guidance.");
}
kernel_init_freeable()
|
do_basic_setup()
static void __init do_basic_setup(void)
{
\tcpuset_init_smp();//針對SMP系統,初始化內核control group的cpuset子系統。
\tusermodehelper_init();// 創建khelper單線程工作隊列,用於協助新建和運行用戶空間程序
\tshmem_init();// 初始化共享內存
\tdriver_init();// 初始化設備驅動
\tinit_irq_proc();//創建/proc/irq目錄, 並初始化系統中所有中斷對應的子目錄
\tdo_ctors();// 執行內核的構造函數
\tusermodehelper_enable();// 啟用usermodehelper
\tdo_initcalls();//遍歷initcall_levels數組,調用裡面的initcall函數,這裡主要是對設備、驅動、文件系統進行初始化,

\t//之所有將函數封裝到數組進行遍歷,主要是為了好擴展
\trandom_int_secret_init();//初始化隨機數生成池
}

小結:

本節主要介紹了Init進程的一些概況,包括啟動後的具體功能,下一節主要針對Init進程的源碼進行分析。

Android 10.0系統啟動之init進程(一)-「Android取經之路」


分享到:


相關文章: