android设备上电,引导程序引导进入boot(通常是uboot),加载initramfs、kernel镜像,启动kernel后,进入用户态程序。第一个用户空间程序是init,PID固定是1.在android系统上,init的代码位于/system/core/init下,基本功能有:
这些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
```
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
文件。
rc规则主要包含了四种类型的语句:
以下做具体详解:
动作表示了一组命令(commands)组成.动作包括一个触发器,决定了何时运行这个动作。
注意:当触发器的条件满足时,这个动作会被增加到已被运行的队列尾。假设此动作在队列中已经存在,那么它将不会运行.
一个动作所包括的命令将被依次运行。
on ## 触发条件
##执行命令
##可以执行多个命令
在"动作"(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 | 当属性值满足条件时触发 |
command是action的命令列表中的命令,或者是service中的选项 onrestart 的参数命令.
命令将在所属事件发生时被一个个地执行.
常见命令:
命令 | 描写叙述 |
---|---|
exec [ ]* | 运行指定路径下的程序,并传递參数. |
export | 设置全局环境參数。此參数被设置后对全部进程都有效. |
ifup | 使指定的网络接口"上线",相当激活指定的网络接口 |
import | 导入一个额外的init配置文件. |
hostname | 设置主机名 |
chdir | 改变工作文件夹. |
chmod | 改变指定文件的读取权限. |
chown | 改变指定文件的拥有都和组名的属性. |
chroot | 改变进行的根文件夹. |
class_start 启动指定类属的全部服务,假设服务已经启动,则不再反复启动. |
|
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 |
设置系统基准时间. |
trigger | Trigger an event. Used to queue an action from another action. 这名话没有理解,望高手指点. |
write [ ]* | 往指定的文件写字符串. |
服务是指那些须要在系统初始化时就启动或退出时自己主动重新启动的程序.
service [ ]*
解释一下各个参数:
参数 | 含义 |
---|---|
表示此服务的名称 | |
此服务所在路径因为是可执行文件,所以一定有存储路径。 | |
启动服务所带的参数 | |
对此服务的约束选项 |
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之前。