96d6f1b34e
- 维度字段 is_first_install 改为 app_install_status(normal/new_install/over_written 三值,与 StartManager 安装状态对齐) - 新增 5.1 模块策略下发:链路 B 为策略驱动(无策略时 create/record 空转并打印 eventId has not created!),策略 JSON 对齐 EventStrategyBean.fromJson(config 嵌套 + status/sampling_rate/interval/aggre_time/aggre_count),含字段说明表与判定生效步骤 - §6 补回标题与开头段:链路 A/B 分工、链路 B API 已随 HXLaunchMonitorPlugin 编译验证(不再待确认)、插件形态(仿 HXCrashMonitorPlugin,startPlugin 建指标,APMHelper 注册) - §7 验收标准同步策略激活条件与编译验证状态 - 新增 8.9 真实应用验证:首启 1141ms(new_install)/ 二次 1717ms(normal),链路 B 待策略下发复测;8.8 注明 demo(boolean)与生产(三值)差异 - 新增真机文档 apm_launch_monitor_config.md(真实 workspace 落地配置,含策略 JSON 与链路 A 字段定义) Co-Authored-By: Claude <noreply@anthropic.com>
128 lines
5.8 KiB
Markdown
128 lines
5.8 KiB
Markdown
# 启动性能监控(冷启动耗时)接入配置
|
||
|
||
> 作者:cheliangzhao
|
||
> 日期:2026-08-06
|
||
> 涉及模块:`entry`(HAP 入口)+ `@kernel/app_monitor_event`(APM 事件 SDK)
|
||
> 对应需求:冷启动耗时(`cold_start_time`)采集与看板聚合
|
||
|
||
---
|
||
|
||
## 1. 背景与目标
|
||
|
||
统计同花顺期货鸿蒙版**冷启动耗时**,覆盖三条启动入口(`Index` / `LauncherPage` / `NetworkAnomalyPage`),区分冷启动 / 补投递四种场景,实现启动性能的持续观测与劣化告警。
|
||
|
||
采集分两条通道:
|
||
|
||
- **链路 A(Elk 追溯,已上线验证)**:把冷启动指标结构化 JSON 经 `ElkService` 异步上报,字段最全,可明细定位。
|
||
- **链路 B(HXEventMonitor 分桶,需后台策略开启后生效)**:由 SDK 按桶自动归集,负责看板聚合曲线。
|
||
|
||
> ⚠️ 链路 B 是**策略驱动**的:SDK 侧在 `EventMonitorStrategy` 找不到 `launch` 模块的开启策略时,`create()/record()` 一律空转并打印 `Monitor.Event cold_start_time eventId has not created!`。应用侧无法绕开,必须由 **APM 后台下发对应模块策略**才能激活。
|
||
|
||
---
|
||
|
||
## 2. 链路 A:Elk 追溯(已生效,无需后台操作)
|
||
|
||
上报字段(`LaunchElkBuilder`,业务来源 `launch`):
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `cold_start_time` | number | 冷启动耗时 ms = 系统事件 `extend_time` |
|
||
| `start_type` | number | 启动类型(当前只统计 `0`=冷启动) |
|
||
| `entry_page` | string | 入口页(`Index`/`LauncherPage`/`NetworkAnomalyPage`;补投递为 `unknown`) |
|
||
| `app_version` | string | 应用内部版本号 |
|
||
| `app_install_status` | string | `normal`/`new_install`/`over_written` |
|
||
| `response_latency` | number | 离手到动效开始(需 API 22+) |
|
||
| `animation_finish_time` | number | 动效完成耗时 |
|
||
| `startability_processstart_dur` | number | 进程创建段(仅冷启动) |
|
||
| `appattach_to_appforeground_dur` | number | 进程挂载段(仅冷启动) |
|
||
| `git_commit` | string | 代码级追溯,劣化定位用 |
|
||
| `is_backfill` | boolean | 是否系统补投递的上次启动遗留事件 |
|
||
|
||
---
|
||
|
||
## 3. 链路 B:HXEventMonitor 分桶指标(需后台开启)
|
||
|
||
### 3.1 后台需下发的模块策略
|
||
|
||
SDK 由 `HXEventMonitorPlugin.parseMonitorStrategy()` 读取,注入到 `EventStrategyBean` 后按模块打开。请为 **module=`launch`** 下发如下配置:
|
||
|
||
```json
|
||
{
|
||
"module": "launch",
|
||
"config": {
|
||
"status": 1,
|
||
"sampling_rate": 1.0,
|
||
"interval": 5000,
|
||
"aggre_time": 60000,
|
||
"aggre_count": 10
|
||
}
|
||
}
|
||
```
|
||
|
||
字段说明(对齐 `EventStrategyBean.fromJson`,仅这些字段生效):
|
||
|
||
| 字段 | 取值 | 说明 |
|
||
|------|------|------|
|
||
| `module` | `launch` | 必须与代码 `HXEventMonitor.getEventFactory('launch')` 一致 |
|
||
| `status` | `1` | **必须 `1`(STATUS_OPEN)**;否则 `isOpen()` 为 false,`create/record` 全空转 |
|
||
| `sampling_rate` | `0~1` | 抽样率,`isOpen()` 需 `status==1 && 抽样通过` 才生效 |
|
||
| `interval` | ms | 采集间隔 |
|
||
| `aggre_time` | ms | 聚合时间阈值,达到即触发一次 push |
|
||
| `aggre_count` | 条 | 聚合数量阈值,达到即触发一次 push |
|
||
|
||
### 3.2 指标定义
|
||
|
||
| 项 | 值 |
|
||
|----|----|
|
||
| 模块名 `module` | `launch` |
|
||
| 指标名 `metric` | `cold_start_time` |
|
||
| 值域 | 冷启动耗时 ms(`extend_time`) |
|
||
| 分桶 `buckets` | `[500, 600, 700, 800, 1000, 1500, 2000, 3000]`(按实测 600–800ms 主体细分,尾部留劣化锚点) |
|
||
| 维度1 `start_type` | 冷启动 `0` |
|
||
| 维度2 `entry_page` | `Index`/`LauncherPage`/`NetworkAnomalyPage`/`unknown`(补投递) |
|
||
| 维度3 `app_version` | 应用内部版本号 |
|
||
| 维度4 `app_install_status` | `normal`/`new_install`/`over_written` |
|
||
|
||
### 3.3 判定生效
|
||
|
||
后台下发后,重启应用,冷启动日志中:
|
||
|
||
- ✅ 消失:`Monitor.Event cold_start_time eventId has not created!`
|
||
- ✅ 出现:`Cold start bucket metric recorded: <ms>` 与 SDK 聚合 push 日志
|
||
- ✅ 看板出现 `launch` 模块 `cold_start_time` 桶分布
|
||
|
||
---
|
||
|
||
## 4. 相关代码与文件
|
||
|
||
| 文件 | 作用 |
|
||
|------|------|
|
||
| `entry/src/main/ets/monitor/LaunchMonitor.ets` | APP_LAUNCH 订阅、Elk 上报、首帧 `reportDrawnCompleted`、桶指标定义与 record |
|
||
| `entry/src/main/ets/monitor/LaunchMonitor.ets`(`ensureColdStartMetric`) | 创建 `launch/cold_start_time` 桶指标(幂等) |
|
||
| `entry/src/main/ets/monitor/plugin/HXLaunchMonitorPlugin.ets` | 仿 `HXCrashMonitorPlugin` 接入的启动插件,在 `startPlugin()` 建指标 |
|
||
| `entry/src/main/ets/monitor/APMHelper.ets` | 注册 `HXLaunchMonitorPlugin` 及配置类、`.plugin(...)` 列表 |
|
||
| `entry/src/main/ets/entryability/EntryAbility.ets` | `onCreate` 早注册 `LaunchMonitor.init()` |
|
||
| `entry/src/main/ets/pages/Index.ets` / `LauncherPage.ets` / `network/NetworkAnomalyPage.ets` | 首帧 `HOME_ROOT` 监听 + `reportFirstFrameOnDraw`/`dispose` |
|
||
|
||
### 打点时序
|
||
|
||
```
|
||
EntryAbility.onCreate → LaunchMonitor.init()(注册 APP_LAUNCH watcher)
|
||
入口页 aboutToAppear → reportFirstFrameOnDraw(HOME_ROOT) → 首帧 draw → reportDrawnCompleted()
|
||
系统产生 APP_LAUNCH 事件(冷启动)→ onReceive
|
||
├─ 链路A: ElkService 上传冷启动 JSON(字段见 §2)
|
||
└─ 链路B: HXEventMonitor record(cold_start_time)(依赖 launch 策略,见 §3)
|
||
补投递:icon_input_time 早于 watcher 注册 > 2000ms → 判为 backfill,entry_page=unknown
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 真机验证结论(2026-08-06,nova 14 Pro)
|
||
|
||
| 场景 | 结果 |
|
||
|------|------|
|
||
| 全新安装首启(`new_install`) | 链路 A:`cold_start_time=1141ms`,Entry=Index,Elk 上报 ✅ |
|
||
| 二次冷启动(`normal`) | 链路 A:`cold_start_time=1717ms`,Elk 上报 ✅ |
|
||
| 链路 B(分桶) | ❌ 待后台下发 `launch` 策略(§3.1)后复测 |
|
||
|
||
编译:`./claude_tool/claude_compile.sh → BUILD_SUCCESS` |