Android 启动原因

戈壁老王

启动原因确定

Android通过三个属性来确定启动原因。

  • ro.boot.bootreason:系统启动过程中,Init进程会将内核启动命令行中的androidboot.bootreason=<reason> 转化为ro.boot.bootreason。启动命令行中的bootreason由一般芯片供应商提供,内核在断电前会将启动原因写入专用的硬件资源或约定的内存地址。下次启动时,Bootloader就可以读取相应的资源来确定启动原因,然后添加到内核启动命令行中。如果芯片供应商不支持启动原因写入,androidboot.bootreason就可能不存在。
  • sys.boot.reason:系统启动时先将ro.boot.bootreason复制给sys.boot.reason。因为ro.boot.bootreason可能不存在,或者可能提供不准确、不可解析或不合规范的信息,在启动完成后会进一步更新sys.boot.reason。更新后的sys.boot.reason将提供准确可靠的、符合规范的启动原因。
  • persist.sys.boot.reason:Android系统在重启前会将重启原因写入到persist.sys.boot.reason中。这个属性可以用来在ro.boot.bootreason不存在时,协助确定启动原因。

准确的启动原因应该通过属性sys.boot.reason来获取,并且只有在用户数据加载完成后才能提供可靠信息。该属性的更新通过命令bootstat完成,可以在init.rc中找到启动的过程。

# Record boot complete metrics.
on property:sys.boot_completed=1 && property:sys.logbootcomplete=1
    # Converts bootloader boot reason to system boot reason
    # Record boot_complete and related stats (decryption, etc).
    # Record the boot reason.
    # Record time since factory reset.
    # Log all boot events.
    exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l 

Bootstat对sys.boot.reason处理的简单流程如下,

  1. 读取ro.boot.bootreason,将其转化为符合规范的reason。
  2. 如果reason是watchdog,检查是否需要增加security标签。
  3. 如果reason是kernel_panic,从last klog中查找详细信息。
  4. 如果reason属于弱集(包含空值),从last klog中查找信息,检查是否电池耗尽引起死机,根据persist.sys.boot.reason修正reason。
  5. 如果上述操作依然无法确定reason,将值设置为reboot,<boot_reason>
  6. 如果reason属于内核集,重写persist.sys.boot.reason

启动原因格式

在 Android 9 中,ro.boot.bootreason 的规范化启动原因格式使用以下语法:

<reason>,<subreason>,<detail>…

格式设置规则如下:

  • 小写
  • 无空格(可使用下划线)
  • 全部为可打印字符
  • 以英文逗号分隔reason、subreason,以及一个或多个detail。

    • reason是必须的,表示设备为什么必须重启或关机,优先级最高的原因。
    • subreason为选用,表示设备为什么必须重启或关机的简短摘要(或重启/关闭设备的人员)。
    • 一个或多个选用的 detail 值。detail 可以指向某个子系统,以协助确定是哪个具体系统导致了 subreason。您可以指定多个 detail 值,这些值通常应按照重要程度排序。不过,也可以报告多个具有同等重要性的 detail 值。

Reason分类

reason值必须是以下集合(分为内核原因、强原因和弱原因)之一:

  • 内核集:

    • "watchdog":通常表示触发了硬件watchdog引起重启。
    • "kernel_panic":表示系统发生了kernel panic。
  • 强集:

    • "recovery":通常为通过reboot接口或命令进入recovery模式。
    • "bootloader":通常为通过reboot接口或命令进入bootloader。
  • 弱集:

    • "cold":通常表示完全重置所有设备,包括内存。
    • "hard":通常表示硬件重置了状态,并且 ramoops 应保留持久性内容。
    • "warm":通常表示内存和设备保持某种状态,并且 ramoops(请参阅内核中的 pstore 驱动程序)后备存储空间包含持久性内容。
    • "shutdown"
    • "reboot":通常意味着 ramoops 状态和硬件状态未知。该值是与 coldhardwarm 一样的通用值,可提供关于设备重置深度的提示。

引导加载程序必须提供内核集或弱集 reason,强烈建议引导加载程序提供 subreason(如果可以确定的话)。例如,电源键长按(无论是否有 ramoops 备份)的启动原因为 "reboot,longkey"

第一个跨度 reason 不能是任何 subreasondetail 的组成部分。不过,由于用户空间无法产生内核集原因,因此可能会在弱集原因之后重复使用 "watchdog" 以及源代码的详细信息(例如 "reboot,watchdog,service_manager_unresponsive""reboot,software,watchdog")。

启动原因应该无需专家级内部知识即可解读,并且(或者)应该能让人看懂并提供直观报告。示例:"shutdown,vbxd"(糟糕)、"shutdown,uv"(较好)、"shutdown,undervoltage"(首选)。

Reason-Subreason组合

Android 保留了一组 reason-subreason 组合,在正常使用情况下不应过量使用这些组合;不过,如果组合能准确反映相关状况,则可根据具体情况加以使用。保留组合的示例包括:

  • "reboot,userrequested"
  • "shutdown,userrequested"
  • "shutdown,thermal"(来自 thermald
  • "shutdown,battery"
  • "shutdown,battery,thermal"(来自 BatteryStatsService
  • "reboot,adb"
  • "reboot,shell"
  • "reboot,bootloader"
  • "reboot,recovery"

参考文档:

Canonical Boot Reason

阅读 2.2k

老王系统屋
做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,

做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,

58 声望
13 粉丝
0 条评论

做为一个不称职的老年码农,一直疏忽整理笔记,开博记录一下,用来丰富老年生活,

58 声望
13 粉丝
宣传栏