鸿蒙开发功耗检测:CPU高负载事件(二)
·
上一篇讲了功耗检测的原理和门限,本文继续介绍在 ArkTS 工程中订阅 CPU 高负载事件。
一、核心接口
| 接口名 | 描述 |
|---|---|
addWatcher(watcher: Watcher): AppEventPackageHolder | 添加应用事件观察者,以添加对应用事件的订阅 |
removeWatcher(watcher: Watcher): void | 移除应用事件观察者,以移除对应用事件的订阅 |
二、开发步骤(以多线程死循环触发CPU高负载为例)
步骤1:导入依赖模块
编辑 entry > src > main > ets > entryability > EntryAbility.ets,导入依赖模块:
import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit';
步骤2:添加系统事件订阅
在 onCreate 函数中添加订阅,示例代码:
hiAppEvent.addWatcher({
// 可以自定义观察者名称,系统会使用名称来标识不同的观察者
name: "watcher",
// 可以订阅感兴趣的系统事件,此处是订阅了CPU高负载事件
appEventFilters: [
{
domain: hiAppEvent.domain.OS,
names: [hiAppEvent.event.CPU_USAGE_HIGH]
}
],
// 可以自行实现订阅实时回调函数,以便对订阅获取到的事件数据进行自定义处理
onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
hilog.info(0x0000, 'testTag', 'HiAppEvent onReceive: domain=%{public}s', domain);
for (const eventGroup of appEventGroups) {
// 可以根据事件集合中的事件名称区分不同的系统事件
hilog.info(0x0000, 'testTag', 'HiAppEvent eventName=%{public}s', eventGroup.name);
for (const eventInfo of eventGroup.appEventInfos) {
// 可以对事件集合中的事件数据进行自定义处理,此处是将事件数据打印在日志中
hilog.info(0x0000, 'testTag', 'HiAppEvent eventInfo=%{public}s', JSON.stringify(eventInfo));
}
}
}
});
步骤3(可选):自定义CPU高负载事件配置策略
示例代码:
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
let policy: hiAppEvent.EventPolicy = {
"cpuUsageHighPolicy": {
"foregroundLoadThreshold": 10, // 设置应用前台CPU负载异常阈值为 10%
"backgroundLoadThreshold": 5, // 设置应用后台CPU负载异常阈值为 5%
"threadLoadThreshold": 50, // 设置应用线程CPU负载异常阈值为 50%
"perfLogCaptureCount": 3, // 设置采样栈每日采集次数上限为3次
"threadLoadInterval": 30 // 设置应用线程负载异常检测周期为30秒
}
};
hiAppEvent.configEventPolicy(policy).then(() => {
hilog.info(0x0000, 'hiAppEvent', 'Successfully set cpu usage high event policy.');
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'hiAppEvent', 'Failed to set cpu usage high event policy. Code: %{public}d, message: %{public}s', err?.code, err?.message);
});
说明:抓取采样栈有内存开销,影响功耗性能,只建议在本地调试时使用自定义参数功能。
采样栈每日采集次数阈值范围:
| 应用版本 | 阈值范围 |
|---|---|
| Debug 版本 | [-1, 100] |
| Release 版本 | [0, 20] |
步骤4:添加 Worker 死循环
在 entry > src > main > ets > workers > worker.ets 中构造死循环,接收到主线程消息后触发 CPU 高负载:
import { worker } from '@kit.ArkTS';
let workerPort = worker.workerPort;
workerPort.onmessage = (message) => {
eatCpu();
};
function eatCpu(): void {
let val: number = 0;
while (true) {
val++;
}
}
步骤5:添加 CpuTest 类
在 entry > src > main > ets > test > CpuTest.ets 中开启多个线程的死循环:
import { worker } from '@kit.ArkTS';
export default class CpuTest {
workerInstance: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');
start(threadNum: number) {
for (let index = 0; index < threadNum; index++) {
this.workerInstance = new worker.ThreadWorker('entry/ets/workers/worker.ets');
this.workerInstance.postMessage('msg');
}
}
}
步骤6:在页面添加"CPU加压"按钮
在 entry > src > main > ets > pages > Index.ets 中添加按钮并触发多线程死循环:
import CpuTest from './test/CpuTest';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State enable: boolean = true;
@State threadNum: number = 6;
cpuTest: CpuTest = new CpuTest();
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button('CPU 加压')
.fontSize(18)
.margin(12)
.fontWeight(FontWeight.Bold)
.enabled(this.enable)
.onClick(() => {
this.cpuTest.start(this.threadNum);
this.enable = false;
})
}
.width('100%')
}
.height('100%')
}
}
步骤7:运行并验证
-
点击 DevEco Studio 的运行按钮,运行应用
-
在应用界面点击 "CPU 加压" 按钮,触发 CPU 高负载事件
-
应用保持在前台且屏幕处于亮屏状态,五到十分钟之后可以在 Log 窗口看到事件处理日志
说明:
-
默认状态下,CPU 高负载事件抓取次数存在限制
-
若未抓取到
external_log日志,可以尝试重启测试设备重新抓取或自定义相关配置策略
日志示例
HiAppEvent eventInfo={
"domain":"OS",
"eventType":1,
"name":"CPU_USAGE_HIGH",
"params":{
"begin_time":1723725531352,
"bundle_name":"com.xxx.test",
"bundle_version":"1.0.0",
"end_time":1623625863613,
"external_log":[
"data/storage/el2/log/hiappevent/CPU_USAGE_HIGH_1623625950016_0.log",
"data/storage/el2/log/hiappevent/CPU_USAGE_HIGH_16232625950196_0.log"
],
"fault_type":1,
"foreground":false,
"log_over_limit":false,
"threads":[
{"name":"com.xxx.test","tid":60677,"usage":0.0708},
{"name":"WorkerThread","tid":60856,"usage":7.5353},
{"name":"WorkerThread","tid":60855,"usage":7.5645},
{"name":"WorkerThread","tid":60854,"usage":7.5120},
{"name":"WorkerThread","tid":60853,"usage":7.5660}
],
"time":1723725949836,
"usage":25
}
}
自定义策略参数
| 参数 | 含义 | 示例值 |
|---|---|---|
foregroundLoadThreshold | 前台 CPU 负载异常阈值 | 10(%) |
backgroundLoadThreshold | 后台 CPU 负载异常阈值 | 5(%) |
threadLoadThreshold | 线程 CPU 负载异常阈值 | 50(%) |
perfLogCaptureCount | 采样栈每日采集次数上限 | 3 |
threadLoadInterval | 线程负载异常检测周期 | 30(秒) |
如果应用被反馈耗电异常,可以先用这套流程在测试环境复现,拿到 external_log 后分析调用栈和采样栈,定位具体是哪段代码导致的 CPU 高负载。
更多推荐




所有评论(0)