docs: add stability remediation evidence

This commit is contained in:
clz
2026-08-24 17:13:00 +08:00
commit b5d837cc45
20 changed files with 912 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
# Repository Guidelines
## Project Structure & Scope
This repository is an evidence bundle for HarmonyOS futures-app freeze and OOM remediation; it does not contain buildable application source code.
- `harmony-ths-futures-freeze/doc/change-notes/` contains freeze/performance remediation notes, numbered `01``11`.
- `harmony-ths-futures-apm-oom/doc/change-notes/` contains memory-retention remediation notes, numbered `10``15`.
- `change-notes.zip` is the distributable archive of those two directories. Keep it synchronized only when a deliverable archive is requested.
Treat notes as technical records: distinguish changes made in the app, communication HAR, and trade SDK repositories, and do not imply that an upstream change is present here.
## Documentation Style & Naming
Write Markdown in Chinese, matching the existing material. Use direct `#` and `##` headings and concise paragraphs. New notes should follow the established numbered, kebab-case pattern, for example `12-new-memory-audit.md`.
Use fenced code blocks for commands and backticks for paths, module names, APIs, package versions, branches, and commit IDs. Preserve exact measurements, units, dates, device details, and command output; identify estimates and limitations explicitly. Prefer tables for baseline-versus-result comparisons.
## Validation and Development Commands
There is no local build, formatter, linter, or test suite. Do not run application builds from this repository. Record validation performed in the relevant upstream HarmonyOS checkout, for example:
```sh
devecocli build --modules entry@default
devecocli check lint
devecocli log --crash --bundle-name <bundle-id>
```
State whether each command was actually run, its target (module/device), and any skipped coverage. Do not present a suggested command as a completed verification.
## Change Notes and Review
Each remediation note should include: the fix commit(s) and branch(es), problem statement, changed scope, implementation/mitigation, behavior and risk boundaries, and concrete verification results. Keep unrelated cleanup and temporary test artifacts out of documented production changes.
This bundle has no Git metadata, so no local commit-message convention can be inferred. Use a short imperative subject such as `docs: add table request cleanup note`. Pull requests should name the affected upstream repository and commit, link the incident or ticket when available, and include before/after metrics or screenshots/log excerpts for behavior claims.
BIN
View File
Binary file not shown.
@@ -0,0 +1,44 @@
# 行情表格请求切换的订阅与缓冲清理
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `5f6e007c7f431521350a68543c4db5314a8c644f` | 修复 `TableRequestClient` 订阅泄漏 |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `2ca4759c4e0212b4c80c41b94a0ae1339569e89c` | 完善请求切换时的统一清理逻辑 |
## 问题
行情列表通过 `TableRequestClient` 发起请求,并在带 `newrealtime=1` 的请求中向 `RealDataManager` 注册实时订阅。请求队列映射、实时订阅和请求缓冲分别以 instanceId、instanceId、`frameId + pageId + instanceId` 关联。
原有 `setPageId()` 先覆盖成员 `pageId`,再移除请求队列映射;随后无法获得旧 instanceId,也没有同步清理旧实时订阅与旧请求缓冲。切换行情分组时,`RealDataManager` 可能持续持有旧表格订阅并合并推送数据,造成 Local Heap 持续增长,最终有 OOM 风险。
## 优化方案
1. `setPageId()` 在覆盖成员前保存旧 `pageId`,递增请求生命周期版本并取消待执行通知,再统一解绑旧请求。
2. 新增私有 `detachCurrentRequest(oldPageId)`:调用 `RequestQueueManagement.removeByClient(this)` 原子取得并移除旧 instanceId 映射;当旧 ID 有效时,用该 ID 移除 `RealDataManager` 订阅,并以旧 `pageId` 删除对应请求缓冲。
3. `removeSubscriber()``release()` 复用同一解绑逻辑,避免多个生命周期出口清理策略不一致。
4. 保留既有异步版本校验和 `setTimeout` 取消逻辑,防止过期解析结果或通知闭包继续持有表格数据。
## 影响范围
- 仅修改 `lib_baseUI``TableRequestClient` 请求切换和释放生命周期。
- 不修改协议报文、请求参数、表格解析、实时数据合并或 UI 展示逻辑。
- 请求未建立队列映射时,清理操作保持幂等并直接返回。
## 预期收益与边界
每次行情分组切换和页面销毁都会同时释放旧请求的队列映射、实时订阅及请求缓冲,避免孤儿订阅继续持有全量表格并接收实时推送,从而抑制 Local Heap 随切页线性增长。
该修改只治理 `TableRequestClient` 链路的引用滞留;图形内存、Web、Native/CPP 堆及其他业务模块的内存增长仍需按各自链路继续分析。`removeSubscriber` 与缓冲删除均按旧 instanceId 执行,因此不会误删新请求。
## 验证建议
1. 执行 `devecocli build --modules entry@default`,确认 ArkTS 编译和打包通过。
2. 安装新 HAP 后,在“行情 → 国内”页的“全部主力 / 能源”等分组间连续切换 20~50 次,再离开列表页。
3. 使用临时调试计数验证每次切换后旧订阅和旧请求缓冲各减少一项,待执行通知数归零;验证完成后不保留计数日志或缓冲快照统计代码。
4. 检查应用崩溃日志,并结合 APM/HiLog 观察 Local Heap 在循环切换期间不再线性增长。
## 本次验证结果
在模拟器上完成 20 次同一活跃 `TableRequestClient` 的分组切换:每轮旧订阅数由 2 降至 1、请求缓冲数由 4 降至 3,待执行通知数始终为 0;离开行情列表后订阅数由 1 降至 0。未发现该应用的崩溃日志。上述计数日志仅用于本次验收,已从正式代码移除。
@@ -0,0 +1,37 @@
# 行情表格实时通知合并
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `909ab7e83795ca418138da81dc8273c29046ce55` | 合并同一事件循环内的行情表格实时通知 |
## 问题
`TableRequestClient.notifyDataReceive()` 原先会为每条行情通知创建一个 `setTimeout` 回调,并将对应的 `TableData` 闭包保存在待执行回调中。实时推送频繁、UI 线程暂时繁忙时,同一轮事件循环内可能堆积多个回调,每个回调都引用一份完整表格数据,放大瞬时 Local Heap 占用。
## 优化方案
1. 将待通知状态改为单个定时器 ID 和最新一份 `TableData | string`
2. 新数据到达时仅覆盖待发送数据;已有定时器时不再创建新的回调。
3. 定时器执行时读取并清空最新数据,再按既有请求生命周期版本校验后通知 UI。
4. 请求切换和释放时取消该定时器并清空待通知数据,避免异步回调继续引用旧表格。
## 影响范围
- 仅修改 `lib_baseUI``TableRequestClient` 的通知调度方式。
- 表格解析、实时订阅、请求参数和 UI 回调接口均不变。
- 同一事件循环内 UI 只接收最新一份表格数据;中间的过期快照不再逐份分发。
## 预期收益与边界
待执行通知从“每条推送一个闭包”收敛为“一个定时器加一份最新数据”,降低高频行情期间短时间内同时存活的完整表格数量,并避免页面切换后遗留的待通知数据。
该优化会合并同一事件循环内的中间 UI 刷新,因此不保证逐条推送都触发一次 UI 回调;最终展示的数据保持为最新快照。网络接收、表格解析和实时订阅的吞吐不受本次修改限制。
## 验证结果
1. 使用现有依赖直接执行 Hvigor `assembleHap`,构建成功;子线程导入检查通过。
2. 在 Pura 90 模拟器安装并启动应用,进入“行情 → 国内”,在“全部主力 / 能源”之间连续切换 20 轮,列表持续正常渲染。
3. 离开行情页后查询应用崩溃日志,未发现 JS Crash 或 CppCrash。
4. 同次验证临时记录了请求切换清理计数:每轮旧订阅由 2 降至 1、请求缓冲由 4 降至 3,且待通知数为 0;验证日志已删除,未纳入正式代码。
@@ -0,0 +1,42 @@
# 交易 SDK 市价缓存去重与正确删除
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony_futures_trade_sdk` | `feature/FUHM-1979-match-push-optimization` | `fbfb85d704510fcbe94d1c58f732e0add4a76292` | 修复市价缓存重复写入和删除失效 |
## 问题
交易 SDK 的 `DefaultMarketPriceCacheCenter` 使用数组保存 `ContractMarketPrice`。原有 `removeCache()` 误用 `slice(i, 1)`,该调用只返回数组片段,不会修改原数组,因此已消费的缓存节点仍被单例缓存中心长期持有。
原有 `cachePrice()` 对相同 `ContractBean + MarketPriceType` 的价格也会无条件新增节点。交易页反复取价或刷新时,同一缓存键会持续产生重复对象;即使业务调用删除,旧节点仍无法从数组移除,导致缓存数组和 Local Heap 随调用次数增长。
## 优化方案
1. `removeCache()` 使用 `splice(i, 1)` 原地删除命中的缓存节点。
2. `cachePrice()` 写入前查找相同合约和价格类型;命中时只更新最新价格并返回,不再追加重复节点。
3. 验证阶段由主工程临时接入本地构建的 `FuTrade.har`,并在当前已安装依赖源码中同步修复,以支持不执行 `ohpm install` 的直接 Hvigor 构建;压力测试、测试入口和本地联调改动均不进入正式提交。
## 影响范围
- 生产代码修改位于兄弟仓库 `../harmony_futures_trade_sdk/FuTrade` 的市价缓存中心。
- 主工程不修改交易协议、报价来源或下单流程;正式依赖仍保持 `1.0.13`,待交易 SDK 发布包含该修复的新版本后再升级版本号和锁定结果。
- 缓存键仍为既有的 `ContractBean + MarketPriceType`;不同合约或价格类型之间不会互相覆盖。
## 预期收益与边界
相同缓存键连续更新时,缓存节点数量从随调用次数线性增长收敛为最多一个;缓存被消费后会立即从数组移除。以本次 100 万次重复更新为例,节点数由潜在的 100 万个降至 1 个,删除后降至 0,重复节点消除率接近 100%。
根据 `ContractMarketPrice` 的对象字段、数组引用和价格字符串开销保守估算,100 万次重复更新可避免约 60~120 MB 的常驻堆增长;20 万次缓存/删除循环可避免约 12~24 MB 的残留。实际 PSS 和 JS Heap 收益受 Ark Runtime 对象布局、字符串表示及 GC 时机影响,仍应以修复前后的同场景 Profiler Trace 为准。
该修改只治理交易 SDK 市价缓存数组的重复节点和错误删除,不覆盖全局行情请求缓冲、实时订阅、整表解析与 UI 全量刷新等其他 OOM 链路。
## 验证结果
1. `FuTrade@default` 构建成功并生成新的 `FuTrade.har`;主工程 `entry@default``entry@ohosTest` 均通过直接 Hvigor 构建。
2. 在 Pura 90 模拟器执行 100 万次相同缓存键更新,耗时 148 ms;最终读取到最新价格,删除后缓存为空。
3. 在同一测试进程执行 20 万次缓存/删除循环,耗时 90 ms;循环结束后缓存为空。
4. Instrumented Test 共执行 4 个用例,结果为 `Pass 4 / Failure 0 / Error 0`,总测试耗时 239 ms。
5. 测试完成后未发现 `com.hexin.plat.hmn.futures` 的 OOM、JS Crash 或 CppCrash 记录。
6. 提交前已清理主工程的本地 HAR 路径、`oh_modules` 同步修改、临时 Instrumented Test 接入和 SDK 测试代码,避免提交不可移植的联调依赖或压力测试代码。
@@ -0,0 +1,37 @@
# WebView 行情总览销毁时释放请求 Client
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `da5599387d82f06256e9224eb8c8001410de1a6b` | 补齐总览页面销毁解绑并断开 bridge 引用 |
## 问题
`OverViewEvent` 只处理 WebView 前后台切换,没有注册页面销毁回调。三个行情 client 已登记到全局 `RequestQueueManagement` 并写入请求缓冲后,如果 WebView 直接销毁,全局队列仍可能持有 client,client 又反向持有 `WebViewJavaScriptBridge`,形成跨页面 retained reference。
## 优化方案
1. 注册 `addAboutToDisappearCallBack()`,页面销毁时统一调用 `stopRequest()`
2. `stopRequest()` 在取消三个请求后清空每个 client 的 bridge 引用和 `OverViewEvent` 成员引用,使重复调用保持幂等。
3. 销毁回调最后清空 `OverViewEvent.webViewJSBridge`,切断事件对象到 WebView bridge 的引用。
## 影响范围
- 仅修改行情总览 JS 事件的销毁生命周期。
- 不修改三个行情协议的 frameId、pageId、请求文本、解析或回调数据结构。
- 前后台恢复行为保持不变;已收到 JS 事件时仍会在回到前台后重新创建请求。
## 预期收益与边界
每次总览页销毁会确定释放 3 个请求 client、对应请求缓冲和队列映射,避免其随反复进出页面线性累积。实际节省内存取决于 bridge、请求参数和页面对象引用图,本次没有设备堆快照,因此不估算具体 MB 或百分比。
该修复只覆盖 `OverViewEvent` 的三条行情请求,不代表其他 WebView JS 事件或全局行情链路已全部完成生命周期审计。
## 验证结果
1. 对实际 `OverViewEvent.ets` 转译后使用模拟 bridge、请求缓冲和队列执行 20,000 轮“注册 → 发起 3 个请求 → 页面销毁”;每轮销毁后 retained request 为 0、retained client 为 0。
2. 使用直接 Hvigor 构建 `entry@default` Debug HAP 成功,完整 ArkTS 编译、HAP 打包和签名通过;未执行安装。
3. 临时压力测试文件和日志已删除,生产代码未保留计数、测试入口或调试日志。
4. 确认“行情 → 总览”页面可加载;主 Tab 切换只改变前后台状态,不销毁 `OverViewPage`,当前产品入口无法在不终止 Ability 的情况下重复触发本修复的页面销毁回调,因此未将主 Tab 循环冒充为 `OverViewEvent` 销毁验证。
5. 同次设备测试检查应用 Crash 日志及近 20 分钟错误日志,未发现 OOM、JS Crash、CppCrash、SIGSEGV 或 SIGABRT。
@@ -0,0 +1,41 @@
# 通信 SDK 跨 Frame 请求缓冲清理与 HAR 接入
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `ohos_mobile_lib_communication` | `work-freeze-lib-communication-1.1.1` | `4784e4698a3d335471f275fd7c8dd9c113323b78` | 清理旧 frame 请求缓冲及关联客户端 |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `da5599387d82f06256e9224eb8c8001410de1a6b` | 替换主工程本地通信 HAR |
## 问题
通信 SDK 在 `frameId` 变化时调用的 `clearRequestPageList()` 为空实现,导致旧 `_sReqList``_sTempReqBuff``_sTemqReqList` 和队列 client 引用继续保留。重复请求还可能通过 instance 映射形成伴随 client,仅删除主 instance 不能完整释放引用链。
## 优化方案
1. SDK 在切换 frame 时收集旧缓冲的全部 instanceId,释放主 instance 及其伴随 instance。
2. 清空三个缓冲并重置当前 frame,再按原流程写入新 frame。
3. 保留切换前已登记的新 client,不使用破坏范围更大的全局队列清空。
4. 构建新的 `lib_communication.har` 并替换主工程 `libs/lib_communication20250903.har`;依赖版本仍为 `1.1.1-beta.1`lockfile 不变。
## 影响范围
- SDK 修改位于 `../ohos_mobile_lib_communication/lib_communication`
- 主工程只替换本地通信 HAR,不修改调用 API 或请求协议。
- `HQ2RequestManager`、实时行情整表复制和 UI 全量解析不在本次范围。
## 预期收益与边界
跨 frame 切换后,请求缓冲由历史 frame 累积收敛为仅保留当前 frame;旧请求文本和 client 引用不再随切页次数线性增长。压力测试 20,000 轮后缓冲仍为 1 项,说明该场景的历史缓冲残留消除率为 100%。
上述结论只针对测试中的缓冲项和 client 计数,不等同于整进程 PSS 降幅;图片、Web、Native 堆及行情整表分配仍可能影响 OOM。
## 验证结果
1. SDK 实际源码压力测试执行 20,000 轮,每轮创建两个相同请求 client 并切换 frame;最终请求缓冲为 1、当前活跃 client 为 2,旧主/伴随 client 均为 0。
2. 直接 Hvigor 构建 SDK Release HAR 成功,耗时 9.145 秒;接入产物 SHA-256 为 `b6919758c15761d5f9f75dcc0bf608d6ab2b46bd5ada9c92ddf1237be8b39621`
3. 主工程直接 Hvigor 构建 `entry@default` Debug HAP 成功,耗时 34.940 秒;未执行 `ohpm install`、安装或启动。
4. 临时 API 24 配置、压力测试代码和日志均已清理;因本机缺少 API 20 SDKAPI 20 构建与设备 OOM/PSS 验证未执行。
5. 2026-08-21 在 Pura 90 API 24 模拟器执行有效的首页、行情、交易、发现四 Tab 定向循环 20 轮,每次切换等待 1 秒;进程持续存活,Crash 日志中未发现 OOM、JS Crash、CppCrash、SIGSEGV 或 SIGABRT。
6. 设备有效循环前 Total PSS / ArkTS heap PSS / Native heap PSS 分别为 562,024 / 110,843 / 211,017 kB20 轮后空闲 15 秒分别为 679,879 / 199,328 / 244,622 kB。整进程内存未回到基线,且生产包没有请求缓冲计数能力,因此该设备结果不能单独证明跨 frame 缓冲已释放,也不能据此将剩余增长归因于本链路;缓冲收敛结论仍以 20,000 轮白盒计数测试为依据。
7. 首次尝试因首页 VIP 广告遮挡底部 Tab,点击未实际切页,该组数据已作废且未计入上述 20 轮结果。
@@ -0,0 +1,43 @@
# 广告悬浮球 PixelMap 与 Dialog ID 生命周期清理
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures-apm-oom` | `work-20260820-clz-FUHM-1979-apm-oom` | `da5599387d82f06256e9224eb8c8001410de1a6b` | 释放广告 PixelMap、失效异步创建并清空 ID |
## 问题
`AdsBallManager` 创建完整图和半图 PixelMap 后未保存并显式释放所有权。任一图片加载失败时,另一张已成功创建的 PixelMap 会直接遗漏;弹窗销毁也只 dismiss dialog,不释放 Native 图片资源。`floatBallIds` 使用只增不删的数组,主题切换和广告刷新会长期保留历史 ID。
异步图片加载期间如果发生新的创建或销毁,旧任务还可能在完成后覆盖新弹窗,使旧图片和 dialog 生命周期错配。
## 优化方案
1. manager 明确持有当前完整图和半图 PixelMap,并在 dialog dismiss 后延迟 300 ms 释放,避免关闭动画仍使用图片。
2. 单图失败、弹窗 show 失败和异步任务过期时立即释放已创建但未展示的 PixelMap。
3. 使用 generation 标记使旧异步创建失效,避免旧结果覆盖新弹窗。
4. `floatBallIds` 改为 `Set<string>`,销毁后清空;兜底 dismiss 仍按历史登记 ID 匹配当前页面 dialog。
5. 对同一 PixelMap 被同时作为完整图和半图的异常情况只调用一次 `release()`
## 影响范围
- 仅修改首页广告悬浮球的图片与 dialog 生命周期管理。
- 不修改广告数据、图片地址、展示样式、点击行为或 300 ms 创建防抖。
- 延迟释放只持有已 dismiss 的当前两张图片 300 ms,避免立即释放与弹窗关闭动画竞争。
## 预期收益与边界
成功展示的每个悬浮球最多持有当前 2 张 PixelMap,销毁后释放;单图失败不再残留另一张;ID 集合在销毁后归零。Native 图片内存收益取决于图片尺寸、像素格式和系统解码缓存,本次未取得真实图片尺寸与设备 PSS,因此不估算具体 MB。
该修复不治理其他广告弹窗、网络图片缓存、系统图形缓存或 GPU/DMA 内存,也不代表 Native PSS 会在 release 后立即同步下降。
## 验证结果
1. 对实际 `AdsBallManager.ets` 转译后执行 5,000 轮成功创建/销毁、5,000 轮半图失败和 1 轮异步过期压力测试。
2. 共创建 15,001 个模拟 PixelMap,全部恰好释放一次;最终 retained dialog ID 为 0、retained dialog 为 0。
3. 新实现随主工程通过直接 Hvigor `entry@default` Debug HAP 构建,完整 ArkTS 编译、打包和签名成功;未执行安装。
4. 压力测试中将 300 ms 延迟计时器同步触发以校验所有权计数;真实设备关闭动画时序、Native PSS 回落和 OOM 日志未验证。
5. 临时压力测试代码与日志已删除,未在生产代码中保留调试计数。
6. 2026-08-21 在 Pura 90 API 24 模拟器确认首页 VIP 广告真实展示并成功关闭,关闭后底部 Tab 恢复可操作;同次测试未发现 OOM、JS Crash、CppCrash、SIGSEGV 或 SIGABRT。
7. 本次设备操作只完成 1 次真实广告展示/关闭,未取得 PixelMap Native 归属计数,也未完成 50~100 轮重复广告创建,因此不宣称真实设备 Native PSS 稳态已经验证;重复释放正确性仍以 15,001 个模拟 PixelMap 的白盒压力测试为依据。
@@ -0,0 +1,38 @@
# 通信库源码联调依赖说明
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `ohos_mobile_lib_communication` | `work-freeze-lib-communication-1.1.1` | `031d4cf221b4da6d9aaf2db443ba293559a0d4a5` | 通信 Worker 解码与队列优化(本说明所支撑的修复) |
> 本笔记为通信库源码联调/依赖说明,非生产修复本身;其支撑的修复见 `03`、`04`。
## 目的
解压与曲线修复基于 `lib_communication` `1.1.1-beta.1`,基线提交为 `7d3f126`,与应用原有 `lib_communication20250903.har` 的源码版本一致。性能验证期间曾将相邻仓库中的通信模块复制到当前工程 `lib_communication/`,以便临时加日志、打点和抓取 trace。
## 修改文件
- `oh-package.json5`
- `build-profile.json5`
- `base_ugc/oh-package.json5`
- `biz_forecast/oh-package.json5`
- `service_aigroup/oh-package.json5`
- `lib_communication/`
## 接入配置
验证期间,根依赖和 `overrides` 使用 `file:./lib_communication`,模块内直接依赖使用 `file:../lib_communication`,根 `build-profile.json5` 将其注册为 HAR 模块。构建 `entry` 时直接编译这份通信源码。
新增 Worker 的运行时导入闭包在验证期间按最小范围登记到子线程门禁:
- `ConcurrentDecodeWorker.ts -> @ohos.worker`
- `ConcurrentDecodeWorker.ts -> HXZip.ts`
## 影响与风险
本地源码保留原公开接口,包含 Worker 解压和曲线解析实现。该目录仅用于性能验证,不应作为正式交付方式。验证结束后已删除根 `build-profile.json5` 中的模块注册,并将根工程及三个业务模块的依赖恢复为 `libs/lib_communication20250903.har`
## 验证
同一源码构建的通信库 debug HAR 及 `entry@default` debug HAP 均已完成构建、安装和运行验证。三轮 A/B 测试确认主线程 CPU 时间中位数下降 20.2%,详细数据见 `06-communication-worker-ab-performance.md`;正式交付仍需发布并接入包含修复的新版 HAR。
@@ -0,0 +1,45 @@
# 网络响应 XML 异步解析
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `e16813f86b8dbabcf6e6e4a18df72c80c69cc9db` | 认证 XML 解析迁移至 TaskPool`ConcurrentXmlParser` |
## 背景与目标
Top 20 冻屏日志中,主线程采样命中 Upass 响应的 GBK 解码和 `XmlPullParser.parse()`。进一步扫描发现验证码响应、账户手机号查询也在通信回调中同步解码并解析 XML。本次统一将三条活动链路迁移到 TaskPool,避免响应体异常放大时阻塞主线程。
## 修改范围
- `biz_common/src/main/ets/utils/xml/ConcurrentXmlParser.ets`
- `biz_hxservice/src/main/ets/cookie/UpassSessionNetClient.ets`
- `biz_auth/src/main/ets/auth/verifycode/CheckCodeLoginClient.ets`
- `biz_auth/src/main/ets/auth/UserQueryClient.ets`
- `claude_tool/subthread-import-guard/subthread-import-policy.json`
`biz_auth/src/main/ets/auth/UpassSessionNetClient.ets` 未发现导出或调用关系,属于当前不可达的遗留实现,本次不修改。
## 通用方案
新增 `parseXmlAttributes()` 并发方法,参数为原始字节、字符编码、目标属性列表和可选结束标签。TaskPool 内完成文本解码与 XML 扫描,统一关闭 DOCTYPE;没有指定结束标签时,获取全部目标属性后立即停止。主线程只处理返回值,不向子线程传递业务对象。
三处调用配置:
- Upass`gbk`,提取 `sessionid`
- 验证码:`gbk`,提取 `code``msg`,遇到 `wlh_thsreg_modify` 结束标签停止。
- 用户查询:`utf-8`,提取 `ckmobile`
并发入口只包含 `@ohos.util``@ohos.xml` 两条运行时依赖边,已精确登记到子线程导入策略。
## 功能影响
- Upass SessionId 获取、持久化及 Cookie 建立。
- 手机号登录或注册时的验证码结果回调。
- 登录完成或推送更新时的账户手机号回填与偏好存储。
请求协议、公开回调接口和存储键不变。解析失败会进入原有失败处理;用户查询异步期间若发生用户切换,会丢弃旧响应。验证码日志不再输出完整 XML,只记录状态码和消息。
## 验证
`node claude_tool/subthread-import-guard/check-subthread-imports.mjs` 已通过:通用入口包含 1 个本地闭包文件和 2 条运行时依赖边。按当前要求未执行完整编译。运行期仍需覆盖 Upass 登录态、验证码成功/失败、手机号回填、用户切换和损坏 XML 场景,并确认主线程采样栈不再出现 XML 解析热点。
@@ -0,0 +1,59 @@
# 通信解压迁移至 Worker
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `ohos_mobile_lib_communication` | `work-freeze-lib-communication-1.1.1` | `031d4cf221b4da6d9aaf2db443ba293559a0d4a5` | `HXZip` 解压与曲线解析迁移到通信 HAR 内持久 Worker,并重构队列分发 |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `ce0719178530b5ca64272c6c1e90b5bcdb8297fc` | 重建并接入 `libs/lib_communication20250903-worker-opt.har` |
## 目的
冻屏采样栈显示主线程在 `HXZip.unzip()` 及解压后的行列转置循环中持续执行。压缩行情包越大,阻塞时间越长。
## 线上真实数据补充
2026-08-21 补充的 TOP10 耗时函数线上统计中,通信库仍有两条采样命中:
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 1 | `writeReceiveTime entry\|@kernel/lib_communication\|1.1.1-beta.1\|src/main/ets/components/communication/protocol/MiniDataHead.ts` | 1 | 2 | 600ms |
| 2 | `anonymous entry\|@kernel/lib_communication\|1.1.1-beta.1\|src/main/ets/request/QueueManagement.ts` | 1 | 2 | 600ms |
这两条不是 `HXZip.unzip()` 本身,但说明同一通信回调链路在线上仍能出现在主线程耗时采样中。`writeReceiveTime()` 只是写包头的短函数,单点优化价值低;`QueueManagement` 当前仍通过 `Map` 全量遍历完成注册、映射和分发查找,后续可将 `instanceId -> clients` / companion 映射拆成索引,减少行情响应分发阶段的线性扫描。
## TOP20 线上数据补充
同日 TOP20 统计中,通信库出现同一条分层回调链:
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 7 | `anonymous entry\|@kernel/lib_communication\|1.1.1-beta.1\|.../handler/Response...` | 59 | 590 | 177000ms |
| 8 | `fireConnectionRead entry\|@kernel/lib_communication\|1.1.1-beta.1\|.../connection/Abstract...` | 58 | 580 | 174000ms |
| 9 | `connectionRead entry\|@kernel/lib_communication\|1.1.1-beta.1\|.../communication/handler/...` | 58 | 580 | 174000ms |
| 10 | `invokeChannelRead entry\|@kernel/lib_communication\|1.1.1-beta.1\|.../connection/Abstract...` | 58 | 580 | 174000ms |
上述 4 项是同一次通信管线逐层转发的采样帧,不能将 699000ms 视为 4 个独立耗时问题。统计来自旧版 `1.1.1-beta.1`;当前工程已接入 Worker 解码和队列索引优化 HAR,需用新包重新采样确认是否仍上榜。
## 修改文件
- `lib_communication/.../protocol/ConcurrentDecodeClient.ts`
- `lib_communication/.../protocol/ConcurrentDecodeWorker.ts`
- `lib_communication/.../protocol/MobileDataProcessor.ts`
- `lib_communication/.../protocol/ReceiveDataProcess.ts`
- `lib_communication/.../handler/ResponseStructDecodeHandler.ts`
- `lib_communication/build-profile.json5`
以上修改基于相邻的 `ohos_mobile_lib_communication` 源码仓库,验证时临时复制到当前工程,验证结束后已移除。
## 实现
通信库主体为 `.ts`,不能直接导入只允许在 `.ets` 中声明的 `@Concurrent` 任务。因此改为复用一个 HAR 内持久 Worker,通过请求 ID 匹配结果,在 Worker 中完成 `HXZip` 解压及行列转置。解码调用链改为异步;每个 `ResponseStructDecodeHandler` 使用 Promise 队列串行处理响应,避免并发完成导致消息乱序。
## 影响与风险
主线程只负责组装 `HXDataInputStream` 和继续分发。Worker 参数与结果均为可序列化的基础类型或 `Uint8Array`。单次消息仍受 16 MB 序列化限制,Worker 异常会拒绝等待中的请求,响应队列捕获错误后继续处理后续消息。
## 验证
基于 `1.1.1-beta.1` 的通信库 HAR 和默认 debug HAP 已构建、安装并完成行情周期切换验证。三轮 A/B 测试中,主线程 CPU 时间中位数下降 20.2%,8 ms 以上连续运行片段减少 53.3%;详细结果与限制见 `06-communication-worker-ab-performance.md`
@@ -0,0 +1,33 @@
# 曲线解析迁移至 Worker
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `ohos_mobile_lib_communication` | `work-freeze-lib-communication-1.1.1` | `031d4cf221b4da6d9aaf2db443ba293559a0d4a5` | `HXZip` 解压与曲线解析迁移到通信 HAR 内持久 Worker |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `ce0719178530b5ca64272c6c1e90b5bcdb8297fc` | 重建并接入 `libs/lib_communication20250903-worker-opt.har` |
## 目的
冻屏日志显示曲线解析在主线程执行 `points × fields` 双重循环,并反复完成整数读取与 HXLong 浮点转换,是曲线点数较大时的 CPU 热点。
## TOP20 线上数据补充
TOP20 的 TOP7–TOP10 命中的是通信响应读取、连接转发和通道回调的分层函数,没有直接命中曲线解析函数。由于这些函数属于同一条响应管线,不能据此证明曲线解析仍是独立瓶颈;当前 Worker 版本的收益仍需使用新包按曲线大包场景重新采样确认。
## 修改文件
- `lib_communication/.../protocol/ConcurrentDecodeClient.ts`
- `lib_communication/.../protocol/ConcurrentDecodeWorker.ts`
- `lib_communication/.../protocol/MobileDataProcessor.ts`
## 实现
扩展数据仍按原逻辑解析;剩余曲线字节、字段类型和点数提交给通信 HAR 内的持久 Worker。子线程保持原协议的小端读取、`MD_TYPE_MASK` 分支、HXLong 符号/指数/空值语义,返回按字段排列的数值列。宿主线程仅按字段 ID 重建 `dataTable``typeTable`
## 影响与风险
公开的 `StuffCurveStruct` 数据结构不变,重复字段 ID 仍以后出现的列为准。若实际单包接近 Worker 的 16 MB 序列化上限,需要进一步改为分块或共享缓冲区。
## 验证
基于 `1.1.1-beta.1` 的通信库 HAR 和默认 debug HAP 已构建、安装并完成行情周期切换验证。当前结果证明通信解析阶段的主线程负载下降,但 `CurveView` 刷新耗时和超时帧没有稳定改善;详细结果与限制见 `06-communication-worker-ab-performance.md`
@@ -0,0 +1,57 @@
# 交易 SDK Native 锁竞争应用侧优化
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `d04f7720c13b130bd9bdab69109d6a93c6edcfca` | 应用侧减少交易 SDK Native 锁竞争(`FuturesApiInterceptor`/`TradeApiManager` |
| `futures_trade_sdk`(原生 lib-weituosdk | `work-clz-FUHM-1979-native-lock-opt` | `1ba241ef8d9aae16dde1b0c4e406d6cd41cca216` | 链接复用计数由 `recursive_mutex` 改为 `std::atomic`,降低锁竞争 |
Native 锁优化 SO`futures-trade-sdk-so-1.2.0-lock-opt.har`)由上述 SDK 提交构建(lib-weituosdk 的 `futures_spi_api_manager.cpp`/`futures_quants_spi.cpp`/`.h`)。应用侧止血见上表首行;本工程 `oh-package.json5` 指向该 SO 的接入改动尚未提交。
## 问题
冻屏日志显示,主线程调用交易 SDK 时阻塞在 `getReuseSpiApiByMode``hasLoggingInRequest` 等 Native 锁上。高频入口包括交易请求发送前检查和自动重登检查。
## 线上真实数据补充
2026-08-21 补充的 TOP10 耗时函数线上统计中,交易 SDK 发送链路仍被采样命中:
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 7 | `sendMsg entry\|@b2c-f/futures_ohos_trade_sdk\|1.0.13\|src/main/ets/trade/api/rpc/RspSendMsgCenterImpl.ts` | 1 | 10 | 3000ms |
| 4 | `isNumber entry\|@b2c-f/futures_ohos_trade_sdk\|1.0.13\|src/main/ets/trade/util/StringUtil.ts` | 1 | 2 | 600ms |
`sendMsg()` 是交易请求进入 SDK/Native 的关键同步入口,和本 notes 记录的 Native 锁竞争止血方向一致。`isNumber()` 为短函数,单独看不像根因,更可能是交易列表或请求参数处理链路中的采样帧;应结合完整调用栈判断是否被 `sendMsg()` 或列表刷新长任务包裹。
同日 TOP20 统计进一步命中交易 SDK 的两组调用链:
| TOP | 函数/调用链 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 14 | `getReuseIpForLogin → getRequestIpForLogin → libweituo_sdk_ohos.so` | 75 | 750 | 900000ms(分层重复采样) |
| 56 | `FuturesApiInterceptor.interceptSendMsg*` | 67/64 | 670/640 | 201000/192000ms |
| 1118 | `enqueue → awaitEnqueue → innerEnqueue → startSendRequest → proceedSendMsg` | 4748 | 470480 | 141000144000ms/项(分层重复采样) |
| 1920 | `TradeApiManager.tryToReLoginAccount` 及其匿名闭包 | 44 | 440 | 132000ms/项 |
TOP14 和 TOP19–20 共同指向自动重登录入口的同步复用 IP 查询;TOP11–18 是同一请求链的多层采样,不能直接累加为独立损耗。该 TOP20 文件记录的是旧版 `1.0.11/1.1.1`,当前工程已接入 `1.0.13/1.2.0` 锁优化 SO;应用侧仍保留首次同步 `getReuseIpForLogin()` 风险,需新包线上复采确认。
## 优化方案
1. 删除 `FuturesApiInterceptor` 中无实际拦截效果的请求前检查。原逻辑会在每次交易请求前同步查询登录中、在线状态,但两个判断分支中的拦截代码均已注释。删除后不改变当前请求行为,同时避免业务请求重复进入 Native 锁域。
2. `TradeApiManager` 按交易账号复用正在执行的重登 Promise。同一账号由认证、交易页或推送重复触发重登时,只执行一次 SDK 登录,其余调用复用结果并保留各自成功、失败回调。
3. 在线检查和复用连接查询前先判断该账号是否正在重登,避免登录过程中再次同步查询 Native 状态。
## 影响范围
- 交易接口发送、自动重登、推送触发的在线检查和交易页切换重登。
- 不修改交易 SDK、Native SO、登录参数、失败重试次数及成功/失败业务处理。
- 不将 SDK 对象迁移到 Worker 或 TaskPool,不改变其线程归属。
## 预期收益与边界
优化可减少主线程进入交易 SDK 互斥锁的频率,并阻止同账号重复登录放大锁竞争。`tryToReLoginAccount` 首次判断仍需调用一次 `getReuseIpForLogin`,因此这属于应用侧止血;彻底消除锁等待仍需要 SDK 缩小 Native 锁范围并发布新的 SO。
## 验证建议
在持续发送交易请求时反复执行断网重连、前后台切换、推送唤起和交易账号切换,确认同账号并发登录数不超过 1,并检查冻屏主线程栈中是否仍出现 `mutex::lock → getReuseSpiApiByMode/hasLoggingInRequest`
@@ -0,0 +1,39 @@
# 通信 Worker A/B 性能验证
## 验证对象(对应修复)
该验证针对 `HXZip` 解压与曲线解析迁移至 Worker 的收益,属于笔记 `03``04` 的量化回放,完整修复提交见 `03`/`04``ohos_mobile_lib_communication` `031d4cf221b4da6d9aaf2db443ba293559a0d4a5``harmony-ths-futures` `ce0719178530b5ca64272c6c1e90b5bcdb8297fc`)。
## 验证目标
对比 `lib_communication` `1.1.1-beta.1` 在同步解压/曲线解析与 Worker 异步处理下的主线程负载。测试只评价通信解压和曲线解析改造,不包含 XML、交易 SDK 或图表绘制优化。
## 测试方法
- 时间:2026-08-18
- 设备:Pura 90 手机模拟器,`127.0.0.1:5555`
- 页面:国内行情“乙二醇2609”详情页
- 操作:依次点击 `1分 -> 5分 -> 15分 -> 日K -> 分时`,连续执行 3 组,共 15 次切换
- 轮次:旧同步版和 Worker 新版各 3 轮;每轮重新启动应用进程并采集 20 秒 hitrace
- 分析:使用 DevEco `trace_streamer` 转换为 SQLite,统计目标进程 `lat.hmn.futures` 的主线程调度片段
## 测试结果
下表使用三轮中位数,括号内为三轮范围。
| 指标 | 旧同步版 | Worker 新版 | 变化 |
| --- | ---: | ---: | ---: |
| 主线程 CPU 时间 | 2959 ms29233309 | 2361 ms23302512 | -20.2% |
| 进程总 CPU 时间 | 3765 ms37314201 | 3075 ms30693250 | -18.3% |
| 主线程 `>= 8 ms` 连续运行片段 | 30 次(2336 | 14 次(1417 | -53.3% |
| 主线程调度片段 P99 | 5.747 ms5.3045.865 | 4.644 ms4.4524.692 | -19.2% |
| 主线程最大连续运行片段 | 23.698 ms13.25231.006 | 19.360 ms12.92424.345 | -18.3% |
## 结论与限制
Worker 改造使主线程计算量下降约 20%,8 ms 以上连续运行片段减少一半以上,主要收益是降低大包解压和曲线解析占用主线程导致的冻屏风险。
`CurveView` 刷新总耗时中位数由 221.5 ms 变为 236.0 ms,没有稳定改善。超过 16.67 ms 的帧中位数由 9 次变为 13 次,帧尾部数据也未呈现一致收益。因此本次结果不能解释为整体帧率提升,优化范围仅限通信解析阶段。
自动框架识别未生成应用绘帧记录,因此未套用 ArkUI 丢帧分类结果。后续建议在真机上使用固定响应包、增加解压和曲线解析起止 trace 点,并扩大轮次,以进一步隔离网络波动、模拟器调度和图表渲染噪声。
原始 trace 和 SQLite 数据未纳入仓库,测试时临时保存在 `/tmp/sdk-worker-ab.psA7Sp/`
@@ -0,0 +1,63 @@
# 交易 SDK 成交推送去重与排序优化
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `ce0719178530b5ca64272c6c1e90b5bcdb8297fc` | 接入本地 `libs/FuTrade-1.0.13-match-push-opt.har`(含成交推送去重与排序) |
| `harmony_futures_trade_sdk` | `feature/FUHM-1979-match-push-optimization` | `9e56923cfaadb14fff0fa928cabe4e5aef615490` | 优化成交推送处理(去重与稳定排序) |
| `harmony_futures_trade_sdk` | `feature/FUHM-1979-match-push-optimization` | `31256eff45b51a96551a2ba8f2b31bb02e4258af` | 优化推送缓存查重 |
SDK 侧成交推送去重/排序来源于 `harmony_futures_trade_sdk` 仓库上述源码提交,本仓库以本地 HAR 携带,接入提交见上表首行。
## 问题
成交推送进入 `MatchOrderSummary.updateMatchOrders()` 时,旧逻辑需要遍历全部成交记录判断重复成交,并在每次新增后对完整数组执行一次排序。成交推送频繁或历史成交较多时,会重复消耗 CPU,并增加成交列表更新的耗时。
## 线上真实数据补充
2026-08-21 补充的 TOP10 耗时函数线上统计没有直接命中 `MatchOrderSummary.updateMatchOrders()`,但命中了同属交易 SDK 的 `RspSendMsgCenterImpl.sendMsg()`:1 次故障、10 次调用、总耗时 3000ms。该数据不能证明成交推送优化已覆盖此线上样本,只能说明交易 SDK 1.0.13 仍存在主线程高频 SDK 调用采样;成交推送优化需要继续依赖新 HAR 接入后的成交推送专项回归和新日志闭环。
TOP20 统计同样没有直接命中 `MatchOrderSummary.updateMatchOrders()`。TOP11–TOP18 命中的是交易请求发送链的 `enqueue/awaitEnqueue/proceedSendMsg` 分层函数,属于请求排队和发送链路,不足以证明成交推送去重与排序优化已经生效或失效;仍需通过成交推送专项采样验证。
## 优化方案
1.`MatchOrderSummary` 中增加 `Set<string>`,缓存已有成交的 `matchIdentify().identify`。重复推送直接通过 `Set.has()` 过滤,避免遍历成交数组。
2. 首次新增推送仍执行完整排序,确保查询结果初始顺序不确定时可以恢复到成交排序规则。
3. 首次排序完成后,后续推送使用二分查找确定插入位置,再插入 `matchOrderRsps`,避免每次对全部成交记录重新排序。
4. 二分插入在比较结果相同时继续向后查找,使相同成交时间和开平方向的记录保持稳定顺序。
5. 增加单元测试,覆盖重复成交、稳定排序插入和不同账号推送过滤。
## 影响范围
- 交易 SDK 的成交汇总、成交推送和成交列表排序。
- 当前项目通过本地 `libs/FuTrade-1.0.13-match-push-opt.har` 使用该版本,依赖配置位于根目录 `oh-package.json5`
- 成交量、平仓盈亏、盯市平仓盈亏的汇总规则不变。
- 账号过滤规则和成交唯一标识规则不变;`Set` 仅用于查重,不参与成交列表排序。
## 预期收益与边界
重复推送判断由数组遍历变为近似 O(1),后续新增成交由全量排序变为二分查找加数组插入。优化主要针对高频成交推送和较大历史成交列表,业务展示顺序不应发生变化。
`matchOrderRsps` 仍是公开可变数组。如果外部代码直接修改、排序或替换数组内容,可能导致成交数组、去重 `Set` 和有序状态不一致;业务代码应通过 SDK 的成交汇总接口读取,避免直接修改该数组。初始查询数据中的重复项也不会由本次改动主动清理。
## 验证建议
### 单元测试
在交易 SDK 的 `FuTrade` 模块运行 `MatchOrderSummary` 测试,确认以下场景:
- 相同成交推送只保留一条,汇总值不重复增加;
- 首次推送后成交记录按既有时间和开平方向规则排序;
- 后续推送插入到正确位置,相同排序值保持稳定顺序;
- 不同账号的成交推送被过滤;
- 空初始列表、白盘/夜盘边界和不同开平方向均可正常插入。
### 当前项目验证
确认 `oh-package.json5` 指向本地 HAR 后,执行:
```bash
./claude_tool/claude_compile.sh
```
并在成交页面回归查询成交、接收新成交推送、重复推送和账号切换,检查成交条数、成交量、盈亏汇总及列表顺序均保持正确。
@@ -0,0 +1,55 @@
# 交易页前台在线状态查询改为读缓存
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `8c3170778f50bf767c9146ea177e82080d629da2` | 交易页前台在线状态改为读缓存 `currentAccount.isOnline` |
## 问题
冻屏日志聚类 20020090(3 次):应用切回前台触发 `TradePage.isAbilityForeGroundChanged()` 时,主线程同步调用 `ApiCommon.isOnlineAccount()`,经 JSI 桥穿透到 `libweituo_sdk_ohos.so``SpiApiManager::getLoginSuccSpiApi` 并等待 `recursive_mutex`。当 SDK 网络线程(asio 断线/连接回调链路)持有该锁时,主线程卡在 `__timedwait_cp` 等锁 3.1/6.2 秒,3S/6S 抓栈逐帧一致,触发冻屏上报。
交易 SDK 1.0.13 的 `TradeAccount` 已维护应用侧在线状态:登录成功(`setLoginSuccess`)、断网(`checkAccountOnline`)、重登成功/失败(`TradeApiManager`)及退出登录(`resetUnLogined`)时经 `updateOnlineStatus()` 更新 `isOnline` 字段并广播 `ACCOUNT_ONLINE_STATUS_CHANGED` 事件。交易页已监听该事件,前台切换所需的"是否在线"用缓存即可回答,无需同步穿透 Native 查询。
## 线上真实数据补充
2026-08-21 补充的 TOP10 耗时函数线上统计中,交易页前台链路仍被采样命中:
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 10 | `onForeground entry\|biz_trade\|1.0.0\|src/main/ets/views/tab/TradeGuaDanListView.ts` | 1 | 10 | 3000ms |
该样本不是 `TradePage.isAbilityForeGroundChanged()` 的同一函数,但同属交易页前台恢复路径。当前 `TradeGuaDanListView.onForeground()` 会立即触发 `GuaDanViewModel.sendRequest()`,其中包含条件单标签查询和挂单查询;如果前后台切换、刷新和交易推送相互叠加,仍可能造成主线程连续调度和 SDK 请求入口放大。后续可对前台刷新增加去重、节流或复用正在进行的查询。
## TOP20 线上数据补充
TOP20 未直接命中 `TradeGuaDanListView.onForeground()`,但命中了交易页自动重登录入口:
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 19 | `tryToReLoginAccount entry\|biz_trade\|1.0.0\|.../TradeApiManager.ts` | 44 | 440 | 132000ms |
| 20 | `anonymous entry\|biz_trade\|1.0.0\|.../TradeApiManager.ts` | 44 | 440 | 132000ms |
该结果说明前台恢复、推送和交易页刷新仍可能汇聚到自动重登录链路,但两个函数属于同一入口的分层采样,不能重复计为两项独立耗时。`TradePage` 的在线状态查询已改为读缓存;`TradeApiManager` 的同步复用 IP 查询仍需结合新版 SDK 线上采样继续确认。
## 优化方案
1. `TradePage.isAbilityForeGroundChanged()` 中的 `ApiCommon.isOnlineAccount(currentAccount)` 替换为读缓存 `currentAccount.isOnline`
2. 删除 `TradePage` 中不再使用的 `ApiCommon` import(全文件仅此一处使用)。
## 影响范围
- 交易页前台切换时在线状态判断的数据来源,由 Native 同步查询改为应用侧缓存。
- 条件单查询时机不变:在线时立即 `checkConditionTriggeredForCurrentAccount()`,离线时置 `needQueryConditionTriggeredAfterTradeLogin`,登录成功后由 `onTradePushLoginResult`、切换账户后由 `onTradeLogin` 补查。
- 不修改交易 SDK、Native SO、`isOnline` 状态的维护链路及其事件广播。
## 预期收益与边界
消除该主线程等锁入口,前台切换不再同步进入交易 SDK 锁域。`isOnline` 为应用侧维护状态,SDK 断线回调尚未到达的极短窗口内可能读到旧值,最多导致多查一次条件单(请求失败无害);彻底消除等锁风险仍需要 SDK 缩小 Native 锁范围并发布新的 SO。
## 验证建议
1. 执行 `./claude_tool/claude_compile.sh` 编译通过。
2. 真机登录后反复前后台切换,确认条件单查询行为与改动前一致,hilog 中不再出现主线程 `isLoggedInAccount` 同步调用。
3. 断网后回前台、恢复网络、重登成功,确认 `onTradePushLoginResult` 兜底补查条件单的路径正常。
4. 检查冻屏主线程栈中是否仍出现 `mutex::lock → SpiApiManager::getLoginSuccSpiApi`
@@ -0,0 +1,35 @@
# 画线绘制候选集去重 O(n²) → O(n)
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `hmdrawlinebasicsdk` | `work-clz-fuhm-1979-drawline-dedup` | `c3f8e6bc2ca44af9afa9bf0163d88d2508d55a0a` | 画线绘制候选集去重 O(n²)→O(n) |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `ce0719178530b5ca64272c6c1e90b5bcdb8297fc` | 接入 `libs/drawlinebasic-1.2.1-dedup-opt.har` 及主工程 overrides |
## 问题
冻屏聚类 200202175 次)、200203403 次):主线程栈停在 `DrawingApiImpl.appendUniqueLines → findIndex → isSameLine``drawLines()` 每帧渲染都会调用 `getLinesToDraw()` 重建绘制候选集,其中 `appendUniqueLines``source.forEach` 嵌套 `target.findIndex` 判重,复杂度 O(n·m)。画线数量较多或跨周期线合并时,主线程持续繁忙触发 3S/6S 冻屏上报。
判重语义(原 `isSameLine`):同对象引用、本地 ID 或远端 ID 任一非空且相等即判为同一条线。注意本地 ID 不同但远端 ID 相同的两条线也判同一条,因此不能用单一 key 去重。
## 优化方案
1. `appendUniqueLines` 改为三个 Set(对象引用 `refSet`、本地 ID `localIdSet`、远端 ID `lineIdSet`)一次遍历完成判重,复杂度降为 O(n);判重语义与原 `isSameLine` 逐条等价,目标列表插入顺序不变;原私有方法 `isSameLine` 随之删除。
2. 补丁基于 `hmdrawlinebasicsdk` 仓库 `feature-zyh-20260708-FUHM-1578-cross-period` 分支(画线 SDK 1.2.1 的发布源,与 ohpm 发布包源码树逐字节一致;master 仍为 1.1.2,无此代码),仓库内 commit `c3f8e6b`,本地构建产物为 `libs/drawlinebasic-1.2.1-dedup-opt.har`
3. 主工程三处接入:根 `oh-package.json5` 依赖与 `overrides``biz_quote/oh-package.json5` 依赖均改为 `file:` 引用本地 HAR。`overrides` 同时将 `drawlinepane@1.1.0` 传递依赖的 `drawlinebasic@1.2.0` 强制指向同一本地 HAR,保证最终产物只有一份 drawlinebasic。
## 影响范围
- 仅画线绘制候选集的去重实现;画线数据模型、持久化、云端合并、绘制样式与命中逻辑不变。
- 每帧绘制候选集重建仍会分配三个 Set,列表本身不缓存;进一步可考虑按 cache 版本缓存合并结果(本次未做)。
## 预期收益与边界
候选集去重由 O(n·m) 降为 O(n),画线数量越大收益越明显,直接消除该冻屏聚类的热点函数。判重语义与原实现逐条等价(含"本地 ID 不同但远端 ID 相同判同一条"的边界情形),重复描边、线条层级行为不变。画线 SDK 侧彻底根治仍建议上游将 `getLinesToDraw` 的合并结果按缓存版本缓存,避免每帧重建。
## 验证建议
1. 执行 `./claude_tool/claude_compile.sh` 编译通过。
2. 真机在画线较多(数十条以上)的 K 线页面滑动、切换周期,确认绘制行为与改动前一致,冻屏主线程栈不再出现 `appendUniqueLines → findIndex`
3. 回归跨周期画线:新建、云端合并、编辑态切换、删除场景下无重复描边,线条层级与命中结果不变。
4. 检查最终产物中 `@b2c-f/drawlinebasic` 仅存在一份(overrides 生效)。
@@ -0,0 +1,39 @@
# TOP10 线上耗时函数后续候选项
## 修复说明
本笔记为线上 TOP10 耗时函数的分析、候选项与建议修复顺序,未包含生产修复本身;候选的实现见 **`11-top10-followup-fixes.md`**(对应本仓库 commit `0d10cf71a01c8c5d875ca4c950d6d2fd71d3fd42`)。
## 数据来源
2026-08-21 从 `~/Downloads/TOP10耗时函数列表.md` 补充线上真实 TOP10 耗时函数统计。该列表是函数采样聚合,不等价于完整冻屏根因;短函数命中通常表示它处在更长的调用链上,需要结合完整 faultlog/采样栈判断。
| TOP | 函数 | 故障出现次数 | 调用次数 | 总耗时 |
| ---: | --- | ---: | ---: | ---: |
| 1 | `writeReceiveTime entry\|@kernel/lib_communication\|1.1.1-beta.1\|src/main/ets/components/communication/protocol/MiniDataHead.ts` | 1 | 2 | 600ms |
| 2 | `anonymous entry\|@kernel/lib_communication\|1.1.1-beta.1\|src/main/ets/request/QueueManagement.ts` | 1 | 2 | 600ms |
| 3 | `anonymous entry\|@b2b/hq_table\|1.0.0-rc.9\|src/main/ets/model/data/TableDataSource.ts` | 1 | 10 | 3000ms |
| 4 | `isNumber entry\|@b2c-f/futures_ohos_trade_sdk\|1.0.13\|src/main/ets/trade/util/StringUtil.ts` | 1 | 2 | 600ms |
| 5 | `transFormServerColor entry\|@b2c/lib_baseui\|1.0.0\|src/main/ets/utils/ColorUtils.ts` | 1 | 2 | 600ms |
| 6 | `isArbitrageEnabled entry\|biz_trade\|1.0.0\|src/main/ets/trade/manager/TradeCustomTabManager.ts` | 1 | 4 | 1200ms |
| 7 | `sendMsg entry\|@b2c-f/futures_ohos_trade_sdk\|1.0.13\|src/main/ets/trade/api/rpc/RspSendMsgCenterImpl.ts` | 1 | 10 | 3000ms |
| 8 | `showOrderNameCell entry\|biz_trade\|1.0.0\|src/main/ets/views/tab/ContractNameCellView.ts` | 1 | 4 | 1200ms |
| 9 | `anonymous entry\|biz_futures_chart\|1.0.0\|src/main/ets/view/View.ts` | 1 | 6 | 1800ms |
| 10 | `onForeground entry\|biz_trade\|1.0.0\|src/main/ets/views/tab/TradeGuaDanListView.ts` | 1 | 10 | 3000ms |
## 当前判断
- `hq_table` 表格数据合并是优先级最高的新增候选:`TableDataSource.notifyDataSetChanged()` 仍在主线程逐行 merge、创建默认行并触发可见行更新,TOP3 达到 10 次调用、3000ms。
- `lib_communication` 队列管理仍有结构性优化空间:`QueueManagement` 通过遍历 `Map<ITCPClient, Map<InstanceId, InstanceId[]>>` 完成注册、删除、映射和分发查找,可改为维护 `instanceId` 索引减少线性扫描。
- `biz_trade` 套利开关可做缓存:`isArbitrageEnabled()` 会进入 `TradeFunctionSwitch.isSupportArbitrageTrade()``GrayTestManager.isFeatureEnable()`,灰度命中时包含日志和 `JSON.stringify(grayConfig)`,不适合在列表构建中高频调用。
- `ContractNameCellView.showOrderNameCell()``ColorUtils.transFormServerColor()``StringUtil.isNumber()``BaseView` 绘制/布局闭包本身都较短,当前不应只针对短函数微调,应先定位其上层列表刷新、图表刷新或交易请求链路。
## 建议修复顺序
1.`hq_table` 源码侧优化 `TableDataSource.notifyDataSetChanged()`:减少全量行合并、只更新可见区、批量合并 `notifyChange()`,必要时将可 Sendable 的数据预处理继续前移到子线程。
2. 在通信 SDK 源码侧重构 `QueueManagement` 索引:新增 `instanceId -> clients` 和 companion 映射,保留原公开接口,避免响应分发时扫描全部客户端。
3.`TradeCustomTabManager``TradeFunctionSwitch` 增加账号维度套利灰度缓存,并在灰度配置变更、账号切换、设置变更时失效。
4.`TradeGuaDanListView.onForeground()` 的挂单刷新做去重/节流,避免前台恢复、手动刷新和推送触发重复查询。
## 验证口径
每个候选项修复后,需要用新包重新采集线上或真机冻屏采样,确认对应函数不再进入 TOP 耗时列表。仅凭本次 TOP10 采样不能判定短函数为唯一根因。
@@ -0,0 +1,90 @@
# TOP10 线上耗时函数后续修复
## 修复提交
| 仓库 | 分支 | Commit ID | 说明 |
| --- | --- | --- | --- |
| `harmony-ths-futures` | `work-20260818-clz-FUHM-1979-apm-appfreeze` | `0d10cf71a01c8c5d875ca4c950d6d2fd71d3fd42` | 挂单请求合并、套利开关缓存、通信队列索引、行情表格延迟合并 |
| `ohos_mobile_lib_communication` | `work-freeze-lib-communication-1.1.1` | `031d4cf221b4da6d9aaf2db443ba293559a0d4a5` | `QueueManagement` 队列索引(instanceId→client / companion |
## 问题来源
基于 2026-08-21 `TOP10耗时函数列表.md` 的线上采样,继续处理仍有明确优化空间的主线程热点:
- `@b2b/hq_table` `TableDataSource`:1 次故障、10 次调用、总耗时 3000ms。
- `@kernel/lib_communication` `QueueManagement`:1 次故障、2 次调用、总耗时 600ms。
- `biz_trade` `TradeCustomTabManager.isArbitrageEnabled()`:1 次故障、4 次调用、总耗时 1200ms。
- `biz_trade` `TradeGuaDanListView.onForeground()`:1 次故障、10 次调用、总耗时 3000ms。
## TOP20 线上数据补充
同日 `/Users/clz/Downloads/TOP20耗时函数列表.md` 汇总数据如下:故障出现次数 `1134`,调用次数 `11340`,记录总耗时 `3402000ms`。所有记录的单个故障最大耗时均为 `3000ms`。这些数值是采样记录的分层汇总,不代表一次冻屏实际耗时,不能直接相加计算收益。
TOP20 主要归并为以下调用链:
| 调用链 | TOP | 故障/调用 | 总耗时 | 当前判断 |
| --- | ---: | ---: | ---: | --- |
| 重登录复用 IP 与 Native 锁 | 14、1920 | 75/75044/440 | 900000ms132000ms/项 | 锁优化 SO 已接入,应用侧仍有同步查询边界,待新包复采 |
| 交易请求拦截与发送 | 56、1118 | 4767/470670 | 141000201000ms/项 | 已移除拦截器同步状态检查,通用请求仍需观察并发放大 |
| 通信响应回调转发 | 710 | 5859/580590 | 174000177000ms/项 | 属同一管线分层采样,Worker/索引优化已接入,待新包复采 |
TOP20 显示的交易 SDK 与通信库版本分别为旧版 `1.0.11/1.1.1``1.1.1-beta.1`;当前工程依赖已更新为交易 SDK `1.0.13/1.2.0` 及 Worker 优化通信 HAR。因此本表用于记录线上问题来源和修复映射,不能作为当前版本仍全部复现的证据。
## 修复内容
1. `GuaDanViewModel.sendRequest()` 增加进行中请求合并:挂单查询未返回时,后续前台/刷新触发只记录一次尾随刷新,避免短时间重复进入 SDK 查询链路。
2. `TradeCustomTabManager.isArbitrageGrayOpened()` 增加当前账号维度缓存;`TradeSettingEvents.SETTING_UPDATE` 触发时失效,避免列表构建高频进入 `GrayTestManager.isFeatureEnable()` 的日志和配置序列化路径。
3. 通信 SDK `QueueManagement` 增加 `instanceId -> client` 和 companion 映射索引,`getNetworkClient()` 从全量扫描改为按索引取主请求和 companion 请求。
4. `hq_table_20260616.har``TableDataSource` 对非可见区 `SendableRow` 做延迟合并:当前刷新只合并可见行,非可见行缓存到 `pendingSendableRows`,滚动取数时再落到 `RowData`
5. 重新构建通信 HAR,并替换当前工程 `libs/lib_communication20250903-worker-opt.har``hq_table` 无相邻源码仓库,本次直接以最小差异更新现有 HAR。
## 影响范围
- 挂单列表前台恢复、手动刷新和交易推送叠加时的请求频率。
- 独立交易页期权/套利 Tab 显示判断。
- 通信响应分发中的请求匹配。
- 行情表格 Sendable 数据进入主线程后的行合并时机。
业务协议、接口签名、表格展示数据结构和交易请求返回处理不变。挂单请求合并保留尾随刷新,避免丢掉进行中期间发生的最后一次刷新诉求。
## 验证与压测
- `node claude_tool/subthread-import-guard/check-subthread-imports.mjs`PASS。
- 通信 SDK`devecocli build --modules lib_communication@default`BUILD SUCCESSFUL。
- 主工程:`./claude_tool/claude_compile.sh`BUILD_SUCCESS。
- 模拟器:Pura 90`127.0.0.1:5555`HarmonyOS 6.1.1(24)。
- `devecocli run --module entry --device 127.0.0.1:5555 --product default --build-mode debug --skip-build`:安装并启动成功。
- 应用进程 `com.hexin.plat.hmn.futures` 存活,前台任务 `EntryAbility` 存在。
- 前后台压力:Home/重新拉起 20 轮完成,无 crash、无 `APPFREEZE` 日志。
- UI 基础场景:行情 Tab 切换、行情页上下滑动 8 轮、交易 Tab 切换、交易入口前后台 5 轮完成,无 crash、无 `APPFREEZE` 日志。
- 备注:未登录交易账号,挂单真实请求返回链路未覆盖;本轮覆盖交易入口页加载和前台恢复基础路径。
- 临时 stdin 压测脚本未落盘,覆盖 100000 个通信实例索引查询、100000 行表格 Sendable 延迟合并、1000 次挂单刷新触发合并:
- `queueIndexedMs`: 4ms
- `tableDeferredMs`: 4ms
- `requestRealSendAfter1000Triggers`: 2
### 新模拟器真实账户验证
- 设备:Mate X7`127.0.0.1:5557`HarmonyOS 6.1.1(24);通过 `devecocli ui` 完成控件树检查和交互。
- 真实账户登录成功,交易首页权益、可用资金和行情盘口加载完成。
- 进入当日委托/挂单页面,连续 10 轮切换挂单、委托、成交并触发刷新;页面保持响应,无 `APPFREEZE`,无应用 crash。
- 该轮未执行下单、撤单或改价,避免产生真实资金业务副作用。
- 设备网络不可用时出现 DNS/监控上传错误;同时观察到已有 SQLite 空表名查询错误,均未导致应用退出或冻屏,不纳入本次 TOP 修复结论。
- 最后一次误触打开交易时间提醒 WebView,页面仍正常展示;该路径不属于本次交易 SDK 压测范围。
### Wukong 滑动压力验证
- 设备:Mate X7`127.0.0.1:5557`;仅允许 `com.hexin.plat.hmn.futures`,固定种子 `20260821`
- Wukong 随机测试报告:`task status=success``task time=149s``task count=100`,事件为 100 次滑动;点击、键盘、旋转和应用切换比例均为 0。
- Wukong 异常统计为空;设备 `APPFREEZE` 查询为空,应用 crash 查询为空。
- 报告目录:`/data/local/tmp/wukong/report/20260821_152309/`。该轮未执行交易点击,真实账户无资金业务副作用。
### 按修改点专项复验
- `hq_table`:国内行情大表执行 Wukong 50 次纯滑动,报告 `task status=success``task count=50`、滑动事件 50 次、异常为空;页面仍可正常进入合约详情。
- Worker 解码:合约详情连续 8 轮切换分时、日 K、1/5/15 分钟,图表和行情数据正常,无 `APPFREEZE` 或 crash。
- `GuaDanViewModel``QueueManagement`:真实账户交易页在设置更新后重新进入当日委托,连续 5 轮切换挂单/委托并刷新;页面正常,无 `APPFREEZE` 或 crash。
- `TradeCustomTabManager`:当前真实账户和灰度环境未展示期权/套利独立下单 Tab,仅触发交易设置更新事件并返回交易页验证回退/重建路径;期权/套利 Tab 的直接专项验证待灰度开放后补测。
## 后续验证
需要用新包重新采集线上或真机冻屏采样,确认 `TableDataSource``QueueManagement``isArbitrageEnabled``TradeGuaDanListView.onForeground` 不再进入 TOP 耗时函数。短函数如 `ColorUtils.transFormServerColor()``StringUtil.isNumber()``BaseView` 绘制闭包仍应结合完整栈判断,不单独做微调。
+80
View File
@@ -0,0 +1,80 @@
# 期货 HarmonyOS 客户端稳定性治理需求开发文档
## 1. 文档目的
本文将现有冻结(App Freeze)与内存溢出(OOM)整改记录整理为可研发落地、可测试验收的需求。目标是在不改变行情、交易、画线业务协议及用户可见规则的前提下,降低主线程阻塞、请求重复与对象滞留风险。
本文记录的是已验证改造的需求基线,不代表所有项均已随正式版本发布;版本接入与线上复采必须以各上游仓库和发布包为准。
## 2. 范围与代码归属
| 域 | 主要归属 | 本次目标 |
| ------ | ------------------------------------------------------------------- | --------------------- |
| 应用业务 | `harmony-ths-futures` | 交易、行情与 WebView 生命周期治理 |
| 通信 | `ohos_mobile_lib_communication` | 解码、曲线解析、请求队列与缓冲释放 |
| 交易 SDK | `harmony_futures_trade_sdk` `futures_trade_sdk`(原生 `lib-weituosdk`) | Native 锁规避、成交推送、市价缓存 |
| 画线 SDK | `hmdrawlinebasicsdk` | 绘制候选集去重 |
本仓库仅保存变更说明,不能直接构建或产出 HAP/HAR。
## 3. 功能需求
### FR-01 通信与解析异步化
1. XML 响应的字节解码和属性解析必须在 TaskPool 中完成;主线程仅消费解析结果。解析入口只允许携带可序列化数据,禁用 DOCTYPE,并保持登录会话、验证码、手机号查询的原有回调与失败语义。
2. `HXZip` 解压及曲线的 `points × fields` 解析必须在通信 HAR 的持久 Worker 中执行。响应须按请求顺序串行回调;Worker 异常须拒绝当前等待任务,但不得阻断后续消息。
3. `QueueManagement` 必须维护 `instanceId → client/companion` 索引,避免响应分发遍历全部客户端;跨 `frameId` 切换时,必须释放旧请求缓冲、主/伴随 client 映射。
### FR-02 行情与绘制主线程削峰
1. 表格实时通知在同一事件循环内仅保留最新一份 `TableData`,已有定时器时不得继续创建闭包;切页或释放时必须取消定时器并清空待通知数据。
2. 画线候选集去重必须保持“同对象、本地 ID 相同或远端 ID 相同即重复”的既有语义与插入顺序,复杂度由 O(n²) 降为 O(n)。
### FR-03 交易链路防重复与锁规避
1. 前台交易页的在线判断必须读取 `currentAccount.isOnline` 缓存,不得同步调用 Native 在线查询;断网、重登、切账号后的条件单补查行为保持不变。
2. 同一账号重登必须复用进行中的 Promise;无实际拦截效果的交易发送前 SDK 状态检查必须移除。
3. 挂单查询进行中再次触发时,只保留一次尾随刷新;列表构建中的套利灰度判断按账号缓存,并在设置更新、账号或灰度配置变化时失效。
4. 成交推送必须按唯一标识去重。首次加载可全量排序,后续记录必须以稳定二分插入,且不改变成交量、盈亏、账号过滤与展示顺序。
5. 市价缓存须按“合约 + 价格类型”更新同一节点;消费后必须用可修改数组操作删除节点,禁止重复累积。
### FR-04 页面与请求资源释放
1. `TableRequestClient` 切页、取消订阅或释放时,必须幂等地移除旧队列映射、实时订阅、请求缓冲与待通知数据。
2. WebView 总览页销毁时,必须停止三个行情请求并清空 client 与 JS bridge 的双向引用。
## 4. 影响面
| 需求域 | 用户/业务入口 | 受影响组件 | 保持不变 | 重点回归 |
| --- | --- | --- | --- | --- |
| 通信与解析 | 登录、验证码、行情包与 K 线加载 | XML Parser、通信 Worker、`QueueManagement` | 协议、回调结果、消息顺序 | 损坏 XML、大包、周期连续切换、跨 Frame 请求 |
| 行情与画线 | 行情列表刷新、合约详情、K 线绘制 | `TableRequestClient`、画线 SDK | 行情数据、线条样式、命中与层级 | 高频推送、分组切换、滚动、跨周期线合并 |
| 交易 | 前后台、账号切换、挂单/委托/成交页 | `TradePage``TradeApiManager`、交易 SDK | 下单/撤单、账户过滤、成交汇总与排序规则 | 断网重登、重复刷新、重复推送、真实账户切换 |
| 页面生命周期 | WebView 行情总览页退出 | `OverViewEvent`、请求 client、JS bridge | 总览请求参数、前后台恢复行为 | 反复进入/退出总览页、页面销毁后回调 |
## 5. 非功能要求与边界
- 所有异步任务仅传递基础类型、`Uint8Array` 或其他可序列化数据;单个 Worker 消息受 16 MB 限制,接近上限时需分块设计。
- 不修改网络协议、公开接口、交易下单/撤单规则、行情数据模型或画线样式。
- 不将 SDK 对象迁移至 WorkerNative 锁的根治依赖交易 SDK 缩小锁粒度,应用侧仅减少进入锁域的次数。
- 临时 HAR 路径、压测代码、计数日志和 API SDK 替换不得进入正式提交。
## 6. 验收标准
1. 在上游项目执行 `devecocli build --modules <module>@default` 或对应 HAP 构建成功,且 `devecocli check lint` 无新增问题。
2. 覆盖登录/断网重登、前后台、账号切换、挂单/委托/成交刷新、行情分组切换、K 线周期切换及 WebView 总览销毁;无 JS Crash、CppCrash、OOM 或 `APPFREEZE`
3. 成交去重、稳定排序、缓存删除和请求解绑须具备单元或白盒压力测试;测试后不存在旧订阅、旧缓冲、待通知数据或缓存节点残留。
4. 新包须在真机或模拟器重新采集冻屏采样。`QueueManagement``isArbitrageEnabled``TradeGuaDanListView.onForeground` 不应继续作为可归因的 TOP 耗时热点;分层采样不得重复相加作为性能收益。
## 7. 交付与追溯
每个交付项需提供:所属仓库/分支/commit、HAR 或 HAP 版本与校验值、修改文件清单、构建日志、测试设备与场景、前后指标、未覆盖项及回滚包。详细历史证据见 `harmony-ths-futures-freeze/doc/change-notes/``harmony-ths-futures-apm-oom/doc/change-notes/`
## 8. Change-notes 追溯
| 需求域 | 改动仓库 | 原始功能改动记录(括号内为改动仓库) |
| ------ | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 通信与解析 | `harmony-ths-futures`<br>`ohos_mobile_lib_communication` | <ul><li>[02-xml-taskpool-refactor.md](harmony-ths-futures-freeze/doc/change-notes/02-xml-taskpool-refactor.md)`harmony-ths-futures`</li><li>[03-communication-taskpool-decompression.md](harmony-ths-futures-freeze/doc/change-notes/03-communication-taskpool-decompression.md)`ohos_mobile_lib_communication``harmony-ths-futures`</li><li>[04-curve-parsing-taskpool.md](harmony-ths-futures-freeze/doc/change-notes/04-curve-parsing-taskpool.md)`ohos_mobile_lib_communication``harmony-ths-futures`</li><li>[14-communication-request-buffer-frame-cleanup.md](harmony-ths-futures-apm-oom/doc/change-notes/14-communication-request-buffer-frame-cleanup.md)`ohos_mobile_lib_communication``harmony-ths-futures`</li></ul> |
| 行情与画线 | `harmony-ths-futures`<br>`hmdrawlinebasicsdk` | <ul><li>[09-drawline-dedup-optimization.md](harmony-ths-futures-freeze/doc/change-notes/09-drawline-dedup-optimization.md)`hmdrawlinebasicsdk``harmony-ths-futures`</li><li>[10-table-request-client-subscription-cleanup.md](harmony-ths-futures-apm-oom/doc/change-notes/10-table-request-client-subscription-cleanup.md)`harmony-ths-futures`</li><li>[11-table-request-client-notification-coalescing.md](harmony-ths-futures-apm-oom/doc/change-notes/11-table-request-client-notification-coalescing.md)`harmony-ths-futures`</li></ul> |
| 交易 | `harmony-ths-futures`<br>`futures_trade_sdk`(原生 `lib-weituosdk`<br>`harmony_futures_trade_sdk` | <ul><li>[05-trade-sdk-native-lock-app-mitigation.md](harmony-ths-futures-freeze/doc/change-notes/05-trade-sdk-native-lock-app-mitigation.md)`harmony-ths-futures``futures_trade_sdk` 的原生 `lib-weituosdk`</li><li>[07-trade-sdk-match-push-optimization.md](harmony-ths-futures-freeze/doc/change-notes/07-trade-sdk-match-push-optimization.md)`harmony-ths-futures``harmony_futures_trade_sdk`</li><li>[08-trade-page-online-status-cache.md](harmony-ths-futures-freeze/doc/change-notes/08-trade-page-online-status-cache.md)`harmony-ths-futures`</li><li>[11-top10-followup-fixes.md](harmony-ths-futures-freeze/doc/change-notes/11-top10-followup-fixes.md)`harmony-ths-futures`</li><li>[12-trade-sdk-market-price-cache-cleanup.md](harmony-ths-futures-apm-oom/doc/change-notes/12-trade-sdk-market-price-cache-cleanup.md)`harmony_futures_trade_sdk`</li></ul> |
| 页面生命周期 | `harmony-ths-futures` | <ul><li>[13-webview-overview-request-cleanup.md](harmony-ths-futures-apm-oom/doc/change-notes/13-webview-overview-request-cleanup.md)`harmony-ths-futures`</li></ul> |