来自 Google 在 Android init at https://android.googlesource.com/platform/system/core/+/oreo-release/init/README.md 上的文档如下
一个操作可以有多个属性触发器,但只能有一个 事件触发器。
例如:
on boot && property:a=b
定义一个仅 当"boot"事件触发器发生并且属性 a 等于 b。
on property:a=b && property:c=d
定义执行的操作 在三次:
- 在初始启动期间,如果属性 a=b 和属性 c=d。
- 每当属性 a 转换为值 b,而属性 c 已等于 d 时。
- 每当属性 c 转换为值 d,而属性 a 已经等于 b 时。
在第一个示例中,on boot
触发器似乎是在启动时执行操作的必要条件。但是在第二个示例中,没有使用on boot
触发器,但文档说该操作仍将在启动时执行。
因此,似乎只有两种说法中的一种是正确的:
property
触发器永远不会在启动时自动发生,在这种情况下,第二个示例描述是错误的,情况 #1property
触发器总是在启动时执行,而不仅仅是在它们转换时执行,在这种情况下,第一个示例不需要包含boot
触发器。
如果第二种说法是正确的,那么它是专门针对boot
阶段而不是说late-init
吗?
我决定继续运行一些测试。证据表明,关于发生的事情的文档是正确的,但缺乏关于原因的细节。
第一个示例on boot && property:a=b
将在启动期间 init 触发boot
事件时执行。请注意,并非所有属性都同时初始化,因此这可能会影响它们在各种引导事件期间的可用性。另请注意,当属性更改时,此示例不会运行。主要的混淆是 init 中的属性既是事件又是状态,而 init 阶段只是事件。
第二个示例在启动期间运行,但它与boot
事件无关!它在 init 启用属性触发器时运行(有关详细信息,请参阅下文(。此外,如前所述,当任一属性更改为声明的值而另一个属性条件为 true 时,它将运行。
测试结果:
on boot
exec /system/bin/echo "Trigger test A"
初始化脚本触发事件时运行boot
on late-init
exec /system/bin/echo "Trigger test B"
初始化触发事件时运行late-init
on property:persist.testing=1
exec /system/bin/echo "Trigger test C"
当从文件系统持久化属性加载属性时运行(在测试时这是在完成后post-fs-data
(,这也会在以后任何时间属性转换为指定值时运行
on boot && property:persist.testing=1
exec /system/bin/echo "Trigger test D"
从不运行,触发boot
时持久属性不可用
on post-fs-data && property:persist.testing=1
exec /system/bin/echo "Trigger test E"
永远不要运行,当触发post-fs-data
时,持久属性不可用,之后立即可用,但为时已晚!
on property:ro.build.type=eng
exec /system/bin/echo "Trigger test F"
在完成触发后,在启用属性触发器时运行late-init
(请参阅下面的注释了解原因(
on boot && property:ro.build.type=eng
exec /system/bin/echo "Trigger test G"
在启动过程中运行,当 init 触发boot
事件时,该属性当时可用
on post-fs-data && property:ro.build.type=eng
exec /system/bin/echo "Trigger test H"
在启动过程中,当 init 触发事件时运行两次post-fs-data
一次在解密之前装载数据时运行一次,一次在解密后装载数据时运行
on late-init && property:ro.build.type=eng
exec /system/bin/echo "Trigger test I"
初始化触发器late-init
时运行
历史证据:
01-25 23:26:25.605 0 0 W : Trigger test B
01-25 23:26:25.605 0 0 W : Trigger test I
01-25 23:26:26.892 0 0 W : Trigger test H
01-25 23:26:28.475 0 0 I init : processing action (early-boot) from (/vendor/etc/init/hw/init.target.rc:79)
01-25 23:26:28.537 0 0 I init : processing action (boot) from (/init.rc:660)
01-25 23:26:28.745 0 0 I : Trigger test A
01-25 23:26:28.778 0 0 I : Trigger test G
01-25 23:26:28.939 0 0 I : Trigger test F
01-25 23:26:31.070 0 0 I : Trigger test H
01-25 23:26:34.871 0 0 I init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc:9)
01-25 15:26:35.284 0 0 I : Trigger test C
01-25 15:26:42.468 0 0 I init : processing action (sys.boot_completed=1) from (/init.rc:819)
2022 年更新:
我更新了一些先前的解释和测试结果。
有人指出,仅属性触发发生在late-init
之后。不清楚为什么谷歌选择这样做,但看看init.cpp你可以在init.cpp中看到以下代码:
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
am.QueueEventTrigger("late-init");
}
// Run all property triggers based on current state of the properties.
am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
这意味着所有late-init
和更早版本的触发器都在仅属性触发器之前运行。因此,像on late-init && property:xyz=*
这样的触发器在触发器on property:xyz=*
之前运行!