Android系统init进程启动及init.rc全解析
這是一篇用心寫的博客,也希望大家用心看并幫忙找到文章的改進之處,謝謝;
服務(wù)啟動機制
system/core/init/init.c文件main函數(shù)中parse_config_file(init.rc)讀取并解析init.rc文件內(nèi)容。將service信息放置到system/core/init/init_parser.cpp的service_list中
system/core/init/init.c文件main函數(shù)繼續(xù)執(zhí)行restart_servie_if_needed(…) -> service_start(…) -> Execve(…)建立service進程;
為了讓大伙看得更明白,上個圖先《總體啟動框架圖》:?
init.rc 簡介
目前Linux有很多通訊機制可以在用戶空間和內(nèi)核空間之間交互,例如設(shè)備驅(qū)動文件(位于/dev目錄中)、內(nèi)存文件(/proc、/sys目錄等)。了解Linux的同學(xué)都應(yīng)該知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一個設(shè)備通常與一個或多個設(shè)備文件對應(yīng)。這些與內(nèi)核空間交互的文件都在用戶空間,所以在Linux內(nèi)核裝載完,需要首先建立這些文件所在的目錄。而完成這些工作的程序就是本文要介紹的init。Init是一個命令行程序。其主要工作之一就是建立這些與內(nèi)核空間交互的文件所在的目錄。當(dāng)Linux內(nèi)核加載完后,要做的第一件事就是調(diào)用init程序,也就是說,init是用戶空間執(zhí)行的第一個程序。
盡管init完成的工作不算很多,不過代碼還是非常復(fù)雜的。Init程序并不是由一個源代碼文件組成的,而是由一組源代碼文件的目標文件鏈接而成的。這些文件位于如下的目錄。
需要明白的是,這些init.rc只是語法文件,并不是程序,真正的入口則是上面提到的system/core/init/init.c?
因為init.c文件比較大,在文章的第二部分我會簡要的通過main函數(shù)分析init啟動流程;
init.rc有兩個,分別位于:?
./system/core/rootdir/init.rc?
./bootable/recovery/etc/init.rc?
從目錄上大致可以猜測,這兩個init.rc使用場景不一樣,一個是刷機用到的,也就是進入recorvery模式,一個是正常啟動用到的;我們這里重點分析的是上面那個,也是init.c關(guān)聯(lián)的那個;
init.rc語法結(jié)構(gòu)解析
要了解init.rc是怎么解析的,我們需要先看看說明文檔,說明文檔在,當(dāng)然也可以看下熱心網(wǎng)友的中文對照版本;?
init.rc位于/bootable/recovery/etc/init.rc
Android初始化語言包含了四種類型的聲明:?
Actions(行為)、Commands(命令)、Services(服務(wù))和Options(選項)
所有這些都是以行為單位的,各種記號由空格來隔開。?
C語言風(fēng)格的反斜杠號可用于在記號間插入空格。?
雙引號也可用于防止字符串被空格分割成多個記號。?
行末的反斜杠用于折行,注釋行以井號(#)開頭(允許以空格開頭)。
需要注意的是,這個只是一個語法文件,就像一個xml文件一樣,沒有執(zhí)行順序的,解析器通過讀這個文件獲取想要的數(shù)據(jù),包括service,action等
Actions和Services聲明一個新的分組Section。所有的命令或選項都屬于最近聲明的分組。位于第一個分組之前的命令或選項將會被忽略。?
Actions和Services有唯一的名字。如果有重名的情況,第二個申明的將會被作為錯誤忽略。
Actions
Actions(行為)是一系列命令的開始?
Actions代表一些Action.Action代表一組命令(Commands),Actions都有一個trigger(觸發(fā)器),該觸發(fā)器決定了何時執(zhí)行這個Action,即在什么情況下才能執(zhí)行該Action中的定義命令.當(dāng)一些條件滿足觸發(fā)器的條件時,該Action中定義的命令會被添加到要執(zhí)行命令隊列的尾部(如果這組命令已經(jīng)在隊列中,則不會再次添加).
隊列中的每一個action都被依次提取出,而這個action中的每個command(命令)在一個Action從隊列移除時,該Action定義的命令會依次被執(zhí)行.
Action的格式如下:
on <trgger> [&& <trigger>]*
? ?<command1>
? ?<command2>
? ?<command3>
? ?...
1
2
3
4
5
on后面跟著一個觸發(fā)器,當(dāng)trigger被觸發(fā)時,command1,command2,command3,會依次執(zhí)行,直到下一個Action或下一個Service。
簡單來說,Actions就是Android在啟動時定義的一個啟動腳本,當(dāng)條件滿足時,會執(zhí)行該腳本,腳本里都是一些命令commands,不同的腳本用on來區(qū)分。
Triggers(觸發(fā)器)
trigger即我們上面所說的觸發(fā)器,本質(zhì)上是一個字符串,能夠匹配某種包含該字符串的事件.?
trigger又被細分為事件觸發(fā)器(event trigger)和屬性觸發(fā)器(property trigger).?
Triggers(觸發(fā)器)是一個用于匹配特定事件類型的字符串,用于使Actions發(fā)生。
事件觸發(fā)器可由”trigger”命令或初始化過程中通過QueueEventTrigger()觸發(fā),通常是一些事先定義的簡單字符串,例如:boot,late-init?
屬性觸發(fā)器是當(dāng)指定屬性的變量值變成指定值時觸發(fā),其格式為property:=*
一個Action可以有多個屬性觸發(fā)器,但是最多有一個事件觸發(fā)器.下面我們看兩個例子:
on boot && property:a=b
1
該Action只有在boot事件發(fā)生時,并且屬性a和b相等的情況下才會被觸發(fā).
on property:a=b && property:c=d
1
該Action會在以下三種情況被觸發(fā):
在啟動時,如果屬性a的值等于b并且屬性c的值等于d
在屬性c的值已經(jīng)是d的情況下,屬性a的值被更新為b
在屬性a的值已經(jīng)是b的情況下,屬性c的值被更新為d
當(dāng)前AIL中常用的有以下幾種事件觸發(fā)器:
類型 ? ? ? ? ? ? ? ? ? ? ?說明
-------------------------------------------------
boot ? ? ? ? ? ? ? ? ? ?init.rc被裝載后觸發(fā)
device-added-<path> ? ? 指定設(shè)備被添加時觸發(fā)
device-removed-<path> ? 指定設(shè)備被移除時觸發(fā)
service-exited-<name> ? 在特定服務(wù)(service)退出時觸發(fā)
early-init ? ? ? ? ? ? ?初始化之前觸發(fā)
late-init ? ? ? ? ? ? ? 初始化之后觸發(fā)
init ? ? ? ? ? ? ? ? ? ?初始化時觸發(fā)(在 /init.conf (啟動配置文件)被裝載之后)
1
2
3
4
5
6
7
8
9
Init的觸發(fā)是由init.c里的函數(shù)action_for_each_trigger來決定的(在main函數(shù)中被調(diào)用)。
Services
Services(服務(wù))是一個程序,以 service開頭,由init進程啟動,一般運行于另外一個init的子進程,所以啟動service前需要判斷對應(yīng)的可執(zhí)行文件是否存在。init生成的子進程,定義在rc文件,其中每一個service,在啟動時會通過fork方式生成子進程。Services(服務(wù))的形式如下:
service <name> <pathname> [ <argument> ]*
? ? <option>
? ? <option>
? ? ...
1
2
3
4
其中:
name:服務(wù)名
pathname:當(dāng)前服務(wù)對應(yīng)的程序位置
option:當(dāng)前服務(wù)設(shè)置的選項
argument 可選參數(shù)
init.rc文件詳解
為了方便理解,我把整個init.rc解析一邊,便于大家了解整個流程;如果想要了解recovery下的init語法解析,參考這篇文章《recovery下的init.rc語法解析》?
代碼量比較大,如果覺得看起來費勁,可以挑綠色部分看;
# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#
"【import <filename>一個init配置文件,擴展當(dāng)前配置。】"
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.${ro.zygote}.rc
import /init.trace.rc
"【觸發(fā)條件early-init,在early-init階段調(diào)用以下行】"
on early-init
? ? # Set init and its forked children's oom_adj.
? ? write /proc/1/oom_score_adj -1000
? ? "【打開路徑為<path>的一個文件,并寫入一個或多個字符串】"
? ? # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
? ? write /sys/fs/selinux/checkreqprot 0
? ? # Set the security context for the init process.
? ? # This should occur before anything else (e.g. ueventd) is started.
? ? "【這段腳本的意思是init進程啟動之后就馬上調(diào)用函數(shù)setcon將自己的安全上下文設(shè)置為“u:r:init:s0”,即將init進程的domain指定為init。】"
? ? setcon u:r:init:s0
? ? # Set the security context of /adb_keys if present.
? ? "【恢復(fù)指定文件到file_contexts配置中指定的安全上線文環(huán)境】"
? ? restorecon /adb_keys
? ? "【執(zhí)行start ueventd的命令。ueventd是一個service后面有定義】 "
? ? start ueventd
? ? "【mkdir <path> [mode] [owner] [group] ? //創(chuàng)建一個目錄<path>,可以選擇性地指定mode、owner以及group。如果沒有指定,默認的權(quán)限為755,并屬于root用戶和root組。】"
? ? # create mountpoints
? ? mkdir /mnt 0775 root system
on init
? ? "【設(shè)置系統(tǒng)時鐘的基準,比如0代表GMT,即以格林尼治時間為準】"
? ? sysclktz 0
"【設(shè)置kernel日志等級】"
loglevel 6 ####
? ? write /proc/bootprof "INIT: on init start" ####
? ? "【symlink <target> <path> ? ?//創(chuàng)建一個指向<path>的軟連接<target>。】"
? ? # Backward compatibility
? ? symlink /system/etc /etc
? ? symlink /sys/kernel/debug /d
? ? # Right now vendor lives on the same filesystem as system,
? ? # but someday that may change.
? ? symlink /system/vendor /vendor
? ? "【創(chuàng)建一個目錄<path>,可以選擇性地指定mode、owner以及group。】"
? ? # Create cgroup mount point for cpu accounting
? ? mkdir /acct
? ? mount cgroup none /acct cpuacct
? ? mkdir /acct/uid
? ? "【mount <type> <device> <dir> [ <mountoption> ] ? //在目錄<dir>掛載指定的設(shè)備。<device> 可以是以 mtd@name 的形式指定一個mtd塊設(shè)備。<mountoption>包括 ro、rw、remount、noatime、 ...】"
? ? # Create cgroup mount point for memory
? ? mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
? ? mkdir /sys/fs/cgroup/memory 0750 root system
? ? mount cgroup none /sys/fs/cgroup/memory memory
? ? write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
? ? "【chown <owner> <group> <path> ? //改變文件的所有者和組。】"
? ? "【后面的一些行因為類似,就省略了】"
? ? .....
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
? ? "【停止指定類別服務(wù)類下的所有已運行的服務(wù)】"
? ? class_stop charger
? ? "【觸發(fā)一個事件,將該action排在某個action之后(用于Action排隊)】"
? ? trigger late-init
# Load properties from /system/ + /factory after fs mount.
on load_all_props_action
? ? "【從/system,/vendor加載屬性。默認包含在init.rc】"
? ? load_all_props
# Indicate to fw loaders that the relevant mounts are up.
on firmware_mounts_complete
? ? "【刪除指定路徑下的文件】"
? ? rm /dev/.booting
# Mount filesystems and start core system services.
on late-init
? ? "【觸發(fā)一個事件。用于將一個action與另一個 action排列。】"
? ? trigger early-fs
? ? trigger fs
? ? trigger post-fs
? ? trigger post-fs-data
? ? # Load properties from /system/ + /factory after fs mount. Place
? ? # this in another action so that the load will be scheduled after the prior
? ? # issued fs triggers have completed.
? ? trigger load_all_props_action
? ? # Remove a file to wake up anything waiting for firmware.
? ? trigger firmware_mounts_complete
? ? trigger early-boot
? ? trigger boot
on post-fs
? ? ...
? ? "【一些創(chuàng)造目錄,建立鏈接,更改權(quán)限的操作,這里省略】"
on post-fs-data
? ? ...
? ? "【一些創(chuàng)造目錄,建立鏈接,更改權(quán)限的操作,這里省略】"
? ? "【恢復(fù)指定文件到file_contexts配置中指定的安全上線文環(huán)境】"
? ? restorecon /data/mediaserver
? ? "【將系統(tǒng)屬性<name>的值設(shè)置為<value>,即以鍵值對的方式設(shè)置系統(tǒng)屬性】"
? ? # Reload policy from /data/security if present.
? ? setprop selinux.reload_policy 1
? ? "【以遞歸的方式恢復(fù)指定目錄到file_contexts配置中指定的安全上下文中】"
? ? # Set SELinux security contexts on upgrade or policy update.
? ? restorecon_recursive /data
? ? # If there is no fs-post-data action in the init.<device>.rc file, you
? ? # must uncomment this line, otherwise encrypted filesystems
? ? # won't work.
? ? # Set indication (checked by vold) that we have finished this action
? ? #setprop vold.post_fs_data_done 1
on boot
? ? "【初始化網(wǎng)絡(luò)】"
? ? # basic network init
? ? ifup lo
? ? "【設(shè)置主機名為localhost】"
? ? hostname localhost
? ? "【設(shè)置域名localdomain】"
? ? domainname localdomain
? ? "【設(shè)置資源限制】"
? ? # set RLIMIT_NICE to allow priorities from 19 to -20
? ? setrlimit 13 40 40
? ? "【這里省略了一些chmod,chown,等操作,不多解釋】"
? ?...
? ? # Define default initial receive window size in segments.
? ? setprop net.tcp.default_init_rwnd 60
? ? "【重啟core服務(wù)】"
? ? class_start core
on nonencrypted
? ? class_start main
? ? class_start late_start
on property:vold.decrypt=trigger_default_encryption
? ? start defaultcrypto
on property:vold.decrypt=trigger_encryption
? ? start surfaceflinger
? ? start encrypt
on property:sys.init_log_level=*
? ? loglevel ${sys.init_log_level}
on charger
? ? class_start charger
on property:vold.decrypt=trigger_reset_main
? ? class_reset main
on property:vold.decrypt=trigger_load_persist_props
? ? load_persist_props
on property:vold.decrypt=trigger_post_fs_data
? ? trigger post-fs-data
on property:vold.decrypt=trigger_restart_min_framework
? ? class_start main
on property:vold.decrypt=trigger_restart_framework
? ? class_start main
? ? class_start late_start
on property:vold.decrypt=trigger_shutdown_framework
? ? class_reset late_start
? ? class_reset main
on property:sys.powerctl=*
? ? powerctl ${sys.powerctl}
# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
? ? write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
# "tcp_default_init_rwnd" Is too long!
on property:sys.sysctl.tcp_def_init_rwnd=*
? ? write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
"【守護進程】"
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
? ? class core
? ? critical
? ? seclabel u:r:ueventd:s0
"【日志服務(wù)進程】"
service logd /system/bin/logd
? ? class core
? ? socket logd stream 0666 logd logd
? ? socket logdr seqpacket 0666 logd logd
? ? socket logdw dgram 0222 logd logd
? ? seclabel u:r:logd:s0
"【Healthd是android4.4之后提出來的一種中介模型,該模型向下監(jiān)聽來自底層的電池事件,向上傳遞電池數(shù)據(jù)信息給Framework層的BatteryService用以計算電池電量相關(guān)狀態(tài)信息】"
service healthd /sbin/healthd
? ? class core
? ? critical
? ? seclabel u:r:healthd:s0
"【控制臺進程】"
service console /system/bin/sh
? ? "【為當(dāng)前service設(shè)定一個類別.相同類別的服務(wù)將會同時啟動或者停止,默認類名是default】"
? ? class core
? ? "【服務(wù)需要一個控制臺】"
? ? console
? ? "【服務(wù)不會自動啟動,必須通過服務(wù)名顯式啟動】"
? ? disabled
? ? "【在執(zhí)行此服務(wù)之前切換用戶名,當(dāng)前默認的是root.自Android M開始,即使它要求linux capabilities,也應(yīng)該使用該選項.很明顯,為了獲得該功能,進程需要以root用戶運行】"
? ? user shell
? ? seclabel u:r:shell:s0
on property:ro.debuggable=1
? ? start console
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
? ? class core
? ? "【創(chuàng)建一個unix域下的socket,其被命名/dev/socket/<name>. 并將其文件描述符fd返回給服務(wù)進程.其中,type必須為dgram,stream或者seqpacke,user和group默認是0.seclabel是該socket的SELLinux的安全上下文環(huán)境,默認是當(dāng)前service的上下文環(huán)境,通過seclabel指定】"
? ? socket adbd stream 660 system system
? ? disabled
? ? seclabel u:r:adbd:s0
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
? ? start adbd
"【內(nèi)存管理服務(wù),內(nèi)存不夠釋放內(nèi)存】"
service lmkd /system/bin/lmkd
? ? class core
? ? critical
? ? socket lmkd seqpacket 0660 system system
"【ServiceManager是一個守護進程,它維護著系統(tǒng)服務(wù)和客戶端的binder通信。
在Android系統(tǒng)中用到最多的通信機制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驅(qū)動程序組成。其中Client、Service和ServiceManager運行在用戶空間,而Binder驅(qū)動程序運行在內(nèi)核空間。核心組件就是Binder驅(qū)動程序了,而ServiceManager提供輔助管理的功能,無論是Client還是Service進行通信前首先要和ServiceManager取得聯(lián)系。而ServiceManager是一個守護進程,負責(zé)管理Server并向Client提供查詢Server的功能。】"
service servicemanager /system/bin/servicemanager
? ? class core
? ? user system
? ? group system
? ? critical
? ? onrestart restart healthd
? ? "【servicemanager 服務(wù)啟動時會重啟zygote服務(wù)】"
? ? onrestart restart zygote
? ? onrestart restart media
? ? onrestart restart surfaceflinger
? ? onrestart restart drm
"【Vold是Volume Daemon的縮寫,它是Android平臺中外部存儲系統(tǒng)的管控中心,是管理和控制Android平臺外部存儲設(shè)備的后臺進程】"
service vold /system/bin/vold
? ? class core
? ? socket vold stream 0660 root mount
? ? ioprio be 2
"【Netd是Android系統(tǒng)中專門負責(zé)網(wǎng)絡(luò)管理和控制的后臺daemon程序】"
service netd /system/bin/netd
? ? class main
? ? socket netd stream 0660 root system
? ? socket dnsproxyd stream 0660 root inet
? ? socket mdns stream 0660 root system
? ? socket fwmarkd stream 0660 root inet
"【debuggerd是一個daemon進程,在系統(tǒng)啟動時隨著init進程啟動。主要負責(zé)將進程運行時的信息dump到文件或者控制臺中】"
service debuggerd /system/bin/debuggerd
? ? class main
service debuggerd64 /system/bin/debuggerd64
? ? class main
"【Android RIL (Radio Interface Layer)提供了Telephony服務(wù)和Radio硬件之間的抽象層】"
# for using TK init.modem.rc rild-daemon setting
#service ril-daemon /system/bin/rild
# ? ?class main
# ? ?socket rild stream 660 root radio
# ? ?socket rild-debug stream 660 radio system
# ? ?user root
# ? ?group radio cache inet misc audio log
"【提供系統(tǒng) 范圍內(nèi)的surface composer功能,它能夠?qū)⒏鞣N應(yīng)用 程序的2D、3D surface進行組合。】"
service surfaceflinger /system/bin/surfaceflinger
? ? class core
? ? user system
? ? group graphics drmrpc
? ? onrestart restart zygote
"【DRM可以直接訪問DRM clients的硬件。DRM驅(qū)動用來處理DMA,內(nèi)存管理,資源鎖以及安全硬件訪問。為了同時支持多個3D應(yīng)用,3D圖形卡硬件必須作為一個共享資源,因此需要鎖來提供互斥訪問。DMA傳輸和AGP接口用來發(fā)送圖形操作的buffers到顯卡硬件,因此要防止客戶端越權(quán)訪問顯卡硬件。】"
#make sure drm server has rights to read and write sdcard ####
service drm /system/bin/drmserver
? ? class main
? ? user drm
? ? # group drm system inet drmrpc ####
? ? group drm system inet drmrpc sdcard_r ####
"【媒體服務(wù),無需多說】"
service media /system/bin/mediaserver
? ? class main
? ? user root ####
# ? google default ####
# ? user media ? ?####
? ? group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
# ? google default ####
# ? group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ####
? ? ioprio rt 4
"【設(shè)備加密相關(guān)服務(wù)】"
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
? ? disabled
? ? "【當(dāng)服務(wù)退出時,不重啟該服務(wù)】"
? ? oneshot
? ? # vold will set vold.decrypt to trigger_restart_framework (default
? ? # encryption) or trigger_restart_min_framework (other encryption)
# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
? ? disabled
? ? oneshot
? ? # vold will set vold.decrypt to trigger_restart_framework (default
? ? # encryption)
"【開機動畫服務(wù)】"
service bootanim /system/bin/bootanimation
? ? class core
? ? user graphics
# ? ?group graphics audio ####
? ? group graphics media audio ####
? ? disabled
? ? oneshot
"【在Android系統(tǒng)中,PackageManagerService用于管理系統(tǒng)中的所有安裝包信息及應(yīng)用程序的安裝卸載,但是應(yīng)用程序的安裝與卸載并非PackageManagerService來完成,而是通過PackageManagerService來訪問installd服務(wù)來執(zhí)行程序包的安裝與卸載的。】"
service installd /system/bin/installd
? ? class main
? ? socket installd stream 600 system system
service flash_recovery /system/bin/install-recovery.sh
? ? class main
? ? seclabel u:r:install_recovery:s0
? ? oneshot
"【vpn相關(guān)的服務(wù)】"
service racoon /system/bin/racoon
? ? class main
? ? socket racoon stream 600 system system
? ? # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
? ? group vpn net_admin inet
? ? disabled
? ? oneshot
"【android中有mtpd命令可以連接vpn】"
service mtpd /system/bin/mtpd
? ? class main
? ? socket mtpd stream 600 system system
? ? user vpn
? ? group vpn net_admin inet net_raw
? ? disabled
? ? oneshot
service keystore /system/bin/keystore /data/misc/keystore
? ? class main
? ? user keystore
? ? group keystore drmrpc
"【可以用dumpstate 獲取設(shè)備的各種信息】"
service dumpstate /system/bin/dumpstate -s
? ? class main
? ? socket dumpstate stream 0660 shell log
? ? disabled
? ? oneshot
"【mdnsd 是多播 DNS 和 DNS 服務(wù)發(fā)現(xiàn)的守護程序。】"
service mdnsd /system/bin/mdnsd
? ? class main
? ? user mdnsr
? ? group inet net_raw
? ? socket mdnsd stream 0660 mdnsr inet
? ? disabled
? ? oneshot
"【觸發(fā)關(guān)機流程繼續(xù)往下走】"
service pre-recovery /system/bin/uncrypt
? ? class main
? ? disabled
? ? "【當(dāng)服務(wù)退出時,不重啟該服務(wù)】"
? ? oneshot
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
init.c全解析
接下來我們具體分析以下這個main函數(shù)的執(zhí)行過程;可能比較長,大家耐心看一下:
int main( int argc, char **argv )
{
? ? #創(chuàng) 建一些linux根文件系統(tǒng)中的目錄
? ? mkdir( "/dev", 0755 );
? ? mkdir( "/proc", 0755 );
? ? mkdir( "/sys", 0755 );
? ? mount( "tmpfs", "/dev", "tmpfs", 0, "mode=0755" );
? ? mkdir( "/dev/pts", 0755 );
? ? mkdir( "/dev/socket", 0755 );
? ? mount( "devpts", "/dev/pts", "devpts", 0, NULL );
? ? mount( "proc", "/proc", "proc", 0, NULL );
? ? mount( "sysfs", "/sys", "sysfs", 0, NULL );
? ? #init的 標準輸入,標準輸出,標準錯誤文件描述符定向到__null__,意味著沒有輸入和輸出,它的輸入和輸出全部寫入到Log中
? ? open_devnull_stdio();
? ? #初始化 log 寫入init進 信息
? ? log_init();
? ? #讀取并 且解析init.rc文件(這個文件在根目錄下)
? ? parse_config_file( "/init.rc" );
? ? #取得硬件 為打印我們的設(shè)備名fs100
? ? get_hardware_name();
? ? snprintf( tmp, sizeof(tmp), "/init.%s.rc", hardware );
? ? #讀取并 且解析硬件相關(guān)的init腳本文件,
? ? parse_config_file( tmp );
? ? #觸發(fā)在init腳本文件中名字為early-init的action,并且執(zhí)行其commands,其實是: on early-init
? ? action_for_each_trigger( "early-init", action_add_queue_tail );
? ? drain_action_queue();
? ? #初始化動態(tài)設(shè)備管理,設(shè)備文件有變化時反應(yīng)給內(nèi)核,后面具體解釋
? ? device_fd = device_init(); # 初 始 化 設(shè) 備 管 理 務(wù)
? ? #加載啟動動畫,如果動畫打開失敗,則在屏幕上打印: A N D R O I D字樣。
? ? if ( load_565rle_image( INIT_IMAGE_FILE ) )
? ? {
? ? ? ? fd = open( "/dev/tty0", O_WRONLY );
? ? ? ? if ( fd >= 0 )
? ? ? ? {
? ? ? ? ? ? const char *msg;
? ? ? ? ? ? msg = "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? 879 ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n" /* console is 40 cols x 30 lines */
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? "\n"
? ? ? ? ? ? ? ? ? /* " ? ? ? ? ? ? A N D R O I D ";開機動畫 */
? ? ? ? ? ? ? ? ? write( fd, msg, strlen( msg ) );
? ? ? ? ? ? close( fd );
? ? ? ? }
? ? }
? ? #觸發(fā) 在init腳本文件中名字為init的action,并且執(zhí)行其commands,其實是:on init
? ? action_for_each_trigger( "init", action_add_queue_tail );
? ? drain_action_queue();
? ? #啟動系統(tǒng)屬性服務(wù): system property service
? ? property_set_fd = start_property_service();
? ? #創(chuàng)建socket用來處理孤兒進程信號
? ? if ( socketpair( AF_UNIX, SOCK_STREAM, 0, s ) == 0 )
? ? {
? ? ? ? signal_fd ? = s[0];
? ? ? ? signal_recv_fd ?= s[1];
? ? ? ? fcntl( s[0], F_SETFD, FD_CLOEXEC );
? ? ? ? fcntl( s[0], F_SETFL, O_NONBLOCK );
? ? ? ? fcntl( s[1], F_SETFD, FD_CLOEXEC );
? ? ? ? fcntl( s[1], F_SETFL, O_NONBLOCK );
? ? }
? ? #觸發(fā) 在init腳本文件中名字為early-boot和boot的action,并且執(zhí)行其commands,其實是:on early-boot和on boot
? ? action_for_each_trigger( "early-boot", action_add_queue_tail );
? ? action_for_each_trigger( "boot", action_add_queue_tail );
? ? drain_action_queue();
? ? #啟動所有屬性變化觸發(fā)命令,其實是: on property:ro.xx.xx=xx
? ? queue_all_property_triggers();
? ? drain_action_queue();
? ? #進入 死循環(huán)()
? ? for (;; )
? ? {
? ? #啟 動所有init腳本中聲明的service,
? ? #如 :266 service servicemanager /system/bin/servicemanager
? ? #user system
? ? #critical
? ? #onrestart restart zygote
? ? #onrestart restart media
? ? restart_processes();
? ? #多路監(jiān)聽設(shè)備管理,子進程運行狀態(tài),屬性服務(wù)
? ? ? ? nr = poll( ufds, fd_count, timeout );
? ? ? ? if ( nr <= 0 )
? ? ? ? ? ? continue;
? ? ? ? if ( ufds[2].revents == POLLIN )
? ? ? ? {
? ? ? ? ? ? read( signal_recv_fd, tmp, sizeof(tmp) );
? ? ? ? ? ? while ( !wait_for_one_process( 0 ) )
? ? ? ? ? ? ? ? ;
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? if ( ufds[0].revents == POLLIN )
? ? ? ? ? ? handle_device_fd( device_fd );
? ? ? ? if ( ufds[1].revents == POLLIN )
? ? ? ? ? ? handle_property_set_fd( property_set_fd );
? ? ? ? if ( ufds[3].revents == POLLIN )
? ? ? ? ? ? handle_keychord( keychord_fd );
? ? }
? ? return(0);
}
---------------------?
作者:瘋?cè)嗽旱脑洪L大人?
來源:CSDN?
原文:https://blog.csdn.net/zhonglunshun/article/details/78615980?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的Android系统init进程启动及init.rc全解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做技术知道了哪些事情代表自己成熟了?
- 下一篇: 数据分析-回归-案例-波士顿房价数据集