应用耗电异常,很多时候是 CPU 高负载在背后作祟。本文基于官方文档,把功耗检测的定位、实现原理、事件场景、限制梳理清楚。

一、功耗检测

功耗检测主要提供 CPU 高负载检测,可以通过订阅相关事件实现检测。

目前仅提供 ArkTS 接口支持。

HiAppEvent 提供订阅 CPU 高负载事件,下篇文档中介绍如何使用。

二、实现原理

系统会周期性及在特定条件(如前后台切换)下,采集三方应用在 CPU 上的运行时间,并每 5 分钟统计一次前 5 分钟的平均负载。

触发机制:若负载超过设定门限,将触发 HiAppEvent 预警事件。

负载计算方式

负载是根据 CPU 核数归一化后的运行时间。

计算示例:

在 5 分钟内,应用进程在 10 核 CPU 上运行了 5 分钟,其平均负载为:

5(CPU 上运行时间)/ 5(统计周期分钟)/ 10(核数)= 10%

三、CPU高负载事件的场景

基础场景(3 种)

场景触发条件
1. 应用在前台时触发 CPU 高负载事件5 分钟内平均负载 大于 30%
2. 应用在后台时触发 CPU 高负载事件5 分钟内平均负载 大于 10%
3. 应用线程高负载异常事件单线程 1 分钟内平均负载 大于 70%

后台高负载的 3 档规格

CPU 后台高负载场景还支持以下 3 档规格:

档位触发条件
1应用在后台时触发 CPU 高负载事件:10 分钟内平均负载大于 7%
2应用在后台时触发 CPU 高负载事件:30 分钟内平均负载大于 2%
3应用在后台时触发 CPU 高负载事件:60 分钟内平均负载大于 1%

这 3 档规格与基础场景的"后台 5 分钟 > 10%"是并列关系,可根据需要选择不同的检测粒度。

四、限制

场景默认抓取限制
前台 CPU 高负载异常单应用默认一天只抓取 1 次调用栈,1 次采样栈
后台 CPU 高负载异常单应用默认一天只抓取 1 次调用栈,1 次采样栈
线程 CPU 高负载异常单应用默认一天只抓取 1 次采样栈

备注:相关配置可自定义

五、日志规格

在订阅事件开发步骤的最后一步中,获取到系统事件数据的处理日志后,可通过查找日志中 external_log 记录的故障日志文件路径,得到故障日志。

事件数据示例

HiAppEvent eventInfo={
  "domain":"OS",
  "name":"CPU_USAGE_HIGH",
  "eventType":1,
  "params":[
    "begin_time":1765959898079,
    "bundle_name":"com.xpower.test",
    "bundle_version":"1.0.0",
    "end_time":1765959958079,
    "external_log":[
      "/data/storage/el2/log/hiappevent/CPU_USAGE_HIGH_1765959959260_0.log"
    ],
    "fault_type":3,
    "foreground":true,
    "log_over_limit":false,
    "threads":[
      {
        "name":"WorkerThread",
        "tid":29164,
        "usage":72
      }
    ],
    "time":1765959959257,
    "usage":72
  ]
}

字段说明

字段说明
external_log记录故障日志的路径,在路径下可获取到故障日志
foreground是否前台(示例中为 true)
fault_type故障类型(示例中为 3)
threads线程信息,包含线程名 name、线程 ID tid、使用率 usage
usage负载使用率(示例中为 72)

两类故障日志

日志类型说明
调用栈故障日志触发故障时当前故障线程的调用链堆栈信息。
采样栈故障日志主动采集的 perf 日志。

说明:

  1. 功耗检测 = CPU 高负载检测:当前聚焦在 CPU 高负载这一项,通过 HiAppEvent 订阅事件实现,仅支持 ArkTS 接口。

  2. 负载是"归一化"后的值:不是简单的 CPU 占用百分比,而是 运行时间 / 统计周期 / 核数,这个计算方式要理解清楚,否则容易误判。

  3. 前台和后台门限差异大:

    • 前台:5 分钟平均负载 > 30% 才触发

    • 后台:5 分钟平均负载 > 10% 就触发

    • 后台要求更严格,因为后台高负载对用户体验和续航影响更大。

  4. 线程高负载是单线程维度:1 分钟内平均负载 > 70% 触发,和前两种是不同维度的检测。

  5. 后台还有三档长周期规格:

    • 10 分钟 > 7%

    • 30 分钟 > 2%

    • 60 分钟 > 1%

    • 周期越长门限越低,适合检测"慢性"高负载问题。

  6. 抓取次数有默认限制:单应用一天只抓 1 次调用栈 + 1 次采样栈(线程高负载只有 1 次采样栈),避免频繁抓取影响性能。需要更多数据要自定义配置。

  7. 日志通过 external_log 路径获取:事件数据里的 external_log 字段记录了故障日志的文件路径,拿到路径后去读文件即可。

  8. 两类故障日志用途不同:

    • 调用栈故障日志:看故障线程的调用链,定位代码位置

    • 采样栈故障日志:perf 日志,看 CPU 采样分布

    • 前者定位"哪行代码",后者定位"时间花在哪"。

  9. 1 天 1 次限制要注意:如果当天已经抓过一次,再触发高负载可能拿不到新日志,调试时要留意。需要更多数据,按《自定义参数》调整。

如果应用被用户反馈耗电快,可以先用这套检测跑一段时间,看看是否触发 CPU 高负载事件,拿到日志后再针对性优化。特别是后台高负载,门限只有 10%,是耗电问题的高发区。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐