Android Init Language由五个元素组成:Acttions、Commands、Services、Options和Imports。
Actions和Services隐式声明了一个新的section。所以的Commands和Options都属于最近声明的section。
Services具有唯一的名称,如果重名会报错。
Actions
Actions被视为Commands的序列。
Actions有一个trigger指明什么时候action被执行。当有和trigger事件匹配的事件发生时,这个action会被添加到待执行队列的尾部(除非它已经存在于队列中)。
Actions形如:
on <trigger> [&& <trigger>]*<command><command><command>...
Services
Services是init启动或重启时执行的程序。形如:
service <name> <pathname> [ <argument> ]*<option><option><option>...
Options
Options是Services的修饰符,表示如何或何时运行service。
具体有哪些Options,详见:init/README.md (googlesource.com)
Commands
具体有哪些Commands,详见:init/README.md (googlesource.com)
在代码中(/system/core/init/builtins.cpp)中,有Commands与函数的映射,指明了某个Command所对应的C++代码的执行函数。
// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();// clang-format offstatic const BuiltinFunctionMap builtin_functions = {{"bootchart", {1, 1, {false, do_bootchart}}},{"chmod", {2, 2, {true, do_chmod}}},{"chown", {2, 3, {true, do_chown}}},{"class_reset", {1, 1, {false, do_class_reset}}},{"class_restart", {1, 2, {false, do_class_restart}}},{"class_start", {1, 1, {false, do_class_start}}},{"class_stop", {1, 1, {false, do_class_stop}}},{"copy", {2, 2, {true, do_copy}}},{"copy_per_line", {2, 2, {true, do_copy_per_line}}},{"domainname", {1, 1, {true, do_domainname}}},{"enable", {1, 1, {false, do_enable}}},{"exec", {1, kMax, {false, do_exec}}},{"exec_background", {1, kMax, {false, do_exec_background}}},{"exec_start", {1, 1, {false, do_exec_start}}},{"export", {2, 2, {false, do_export}}},{"hostname", {1, 1, {true, do_hostname}}},{"ifup", {1, 1, {true, do_ifup}}},{"init_user0", {0, 0, {false, do_init_user0}}},{"insmod", {1, kMax, {true, do_insmod}}},{"installkey", {1, 1, {false, do_installkey}}},{"interface_restart", {1, 1, {false, do_interface_restart}}},{"interface_start", {1, 1, {false, do_interface_start}}},{"interface_stop", {1, 1, {false, do_interface_stop}}},{"load_exports", {1, 1, {false, do_load_exports}}},{"load_persist_props", {0, 0, {false, do_load_persist_props}}},{"load_system_props", {0, 0, {false, do_load_system_props}}},{"loglevel", {1, 1, {false, do_loglevel}}},{"mark_post_data", {0, 0, {false, do_mark_post_data}}},{"mkdir", {1, 6, {true, do_mkdir}}},// TODO: Do mount operations in vendor_init.// mount_all is currently too complex to run in vendor_init as it queues action triggers,// imports rc scripts, etc. It should be simplified and run in vendor_init context.// mount and umount are run in the same context as mount_all for symmetry.{"mount_all", {0, kMax, {false, do_mount_all}}},{"mount", {3, kMax, {false, do_mount}}},{"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},{"umount", {1, 1, {false, do_umount}}},{"umount_all", {0, 1, {false, do_umount_all}}},{"update_linker_config", {0, 0, {false, do_update_linker_config}}},{"readahead", {1, 2, {true, do_readahead}}},{"remount_userdata", {0, 0, {false, do_remount_userdata}}},{"restart", {1, 2, {false, do_restart}}},{"restorecon", {1, kMax, {true, do_restorecon}}},{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},{"rm", {1, 1, {true, do_rm}}},{"rmdir", {1, 1, {true, do_rmdir}}},{"setprop", {2, 2, {true, do_setprop}}},{"setrlimit", {3, 3, {false, do_setrlimit}}},{"start", {1, 1, {false, do_start}}},{"stop", {1, 1, {false, do_stop}}},{"swapon_all", {0, 1, {false, do_swapon_all}}},{"enter_default_mount_ns", {0, 0, {false, do_enter_default_mount_ns}}},{"symlink", {2, 2, {true, do_symlink}}},{"sysclktz", {1, 1, {false, do_sysclktz}}},{"trigger", {1, 1, {false, do_trigger}}},{"verity_update_state", {0, 0, {false, do_verity_update_state}}},{"wait", {1, 2, {true, do_wait}}},{"wait_for_prop", {2, 2, {false, do_wait_for_prop}}},{"write", {2, 2, {true, do_write}}},};// clang-format onreturn builtin_functions;
}
例如,bootchart这个Commands的执行函数是do_bootchart()这个函数。do_bootchart()函数如下:
Result<void> do_bootchart(const BuiltinArguments& args) {if (args[1] == "start") return do_bootchart_start();return do_bootchart_stop();
}
Imports
形如:
import <path>
Import有它自己的section,不是Actions的一部分。
Import用来解析init配置文件、扩展当前配置。如果
Triggers(触发器)
触发器用来匹配某类事件并触发aciton发生。
触发器分为事件触发器和属性触发器。
事件触发器由“trigger” Command或init程序的QueueEventTrigger()函数触发。
属性触发器是在属性改变时触发。
一个Action可以有多个属性触发器,但只能有一个事件触发器。
具体有哪些触发器,详见:init/README.md (googlesource.com)
init.rc举例
下面节选一下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 /init.environ.rc
import /system/etc/init/hw/init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /system/etc/init/hw/init.usb.configfs.rc
import /system/etc/init/hw/init.${ro.zygote}.rc......# Mount filesystems and start core system services.
on late-inittrigger early-fs# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter# '--early' can be specified to skip entries with 'latemount'.# /system and /vendor must be mounted by the end of the fs stage,# while /data is optional.trigger fstrigger post-fs# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter# to only mount entries with 'latemount'. This is needed if '--early' is# specified in the previous mount_all command on the fs stage.# With /system mounted and properties form /system + /factory available,# some services can be started.trigger late-fs# Now we can mount /data. File encryption requires keymaster to decrypt# /data, which in turn can only be loaded when system properties are present.trigger post-fs-data# Should be before netd, but after apex, properties and logging is available.trigger load_bpf_programs# Now we can start zygote for devices with file based encryptiontrigger zygote-start# Remove a file to wake up anything waiting for firmware.trigger firmware_mounts_completetrigger early-boottrigger boot......service boringssl_self_test32 /system/bin/boringssl_self_test32reboot_on_failure reboot,boringssl-self-check-failedstdio_to_kmsg# Explicitly specify that boringssl_self_test32 doesn't require any capabilitiescapabilitiesuser nobody