name: rnoh-stability-triage description: 用于分析 OpenHarmony React Native / RNOH / React Native Harmony 场景中的稳定性问题。只要用户在排查闪退、卡死、内存异常、资源泄漏、SIGSEGV、SIGABRT、UAF、空指针、死锁、生命周期异常、兼容性崩溃、sort 排序崩溃、容器越界访问,或者明确想判断"是不是框架问题""历史版本是否修过""该升级还是回捞补丁",就应使用此 skill。

RNOH 稳定性问题分析

这个 skill 用于把零散日志、版本信息和当前框架代码收敛成可执行的稳定性分析结论。

优先目标有三个:

  1. 先判断是否能命中历史已修复问题。
  2. 再判断更像是用户代码问题、框架问题,还是证据不足。
  3. 最后给出按优先级排序的修复建议。

对伙伴排查最重要的是两点:

  1. 不要停留在“像某类问题”,而是尽量收敛到具体模块、具体触发阶段和具体历史修复。
  2. 即使证据不足,也要告诉对方下一步最值得补哪 1 到 3 项信息,而不是泛泛要求“补更多日志”。

分析入口

使用这个 skill 时,先遵循稳定性文档里的分析口径:

  1. 先判断问题属于应用异常退出、应用冻屏、内存异常还是资源泄漏。
  2. 再基于日志、堆栈、版本和触发阶段做 AI 分析。
  3. 如果 AI 分析收敛到具体模块或历史修复,再结合当前代码做验证。

如果工作区中存在以下文档,优先对齐其口径:

  • docs/zh-cn/稳定性/稳定性问题介绍/稳定性概览.md
  • docs/zh-cn/稳定性/稳定性问题介绍/稳定性分析方法.md

如果需要读取 GitCode PR、MR 或文件列表,先检查以下可选配置文件:

  • references/gitcode-config.json

当该文件存在且 gitcode_access_token 已填写为有效值时,优先使用 GitCode API 读取 PR 详情、变更文件和 patch;未填写、仍为占位值或文件不存在时,退回到公开页面抓取、git fetch 或工作区本地代码分析方式。

注意事项:

  • 只将该 token 用于读取 GitCode PR / MR 相关信息,不在输出中回显 token。
  • 如果仓库或 PR 为公开可读,优先走无鉴权方式;只有在需要 API 结构化数据或公开页面信息不足时再使用 token。
  • 如果读取失败,要在结论中说明是“未配置 token / token 无效 / 权限不足”,不要伪造 PR 信息。

何时优先使用

遇到以下场景时,优先使用这个 skill,而不是直接给笼统结论:

  • 用户提供 crash 栈、hlog、native backtrace、JSVM 错误、SIGSEGV、SIGABRT、abort、UAF、死锁、空指针、内存泄漏线索。
  • 用户说自己使用的不是最新版本,想知道问题是否已经被上游或当前仓库修复。
  • 用户只有日志,没有或很少有业务代码上下文。
  • 用户想区分是框架缺陷、接入方式问题,还是业务调用触发的非法输入/非法生命周期。
  • 用户需要升级建议、补丁建议、规避方案或最小化复现方向。

如果用户只是泛泛询问稳定性概念、想看分类定义或想了解分析方法,而不是在定位具体问题,优先引用稳定性文档,不要强行进入深度 triage。

最小必要输入

尽量收集这些信息,但缺失时不要停住,基于现有证据继续分析:

  • crash 日志、backtrace、墓碑、异常消息。
  • hlog、hilog、启动日志、生命周期日志。
  • 使用的 RNOH / RN Harmony 版本、分支名、提交号,或者至少是大版本,例如 0.72 / 0.77 / 0.82。
  • 触发场景:启动、reload、页面退出、图片加载、动画、滚动、TurboModule 调用、字体注册、文本布局等。
  • 当前工作区里的框架代码。

如果输入不完整,按下面优先级补信息:

  1. 先补最能改变分类判断的信息,例如 FaultLog、崩溃线程、异常类型、冻屏时线程栈。
  2. 再补最能改变归因判断的信息,例如版本号、触发时机、模块名、复现路径。
  3. 最后再补用于精确命中的信息,例如符号化结果、具体提交范围、更多 hilog。

如果用户只给了很少的信息,至少也要从现象、线程、模块、触发阶段四个维度做一次初步收敛,并说明当前结论的置信度。

核心原则

  • 先证据,后判断。不要因为“看起来像框架问题”就直接定性。
  • 不要臆造业务代码实现细节。没有用户代码时,只能基于日志、调用栈、接口契约和框架代码推断。
  • 先查历史稳定性修复,再看当前代码。很多问题在旧版本已修复,直接给升级或回捞补丁建议,价值最高。
  • 相似不等于同一问题。只有当崩溃阶段、模块、异常形态、触发条件至少大体一致时,才能认为“高相似”。
  • 如果证据不足,允许输出“暂不能确定”,但必须说明还缺什么。
  • 伙伴定位问题时,优先给“最短路径”。不要一上来列很长排查清单,而要先指出当前最值得查的模块、最相关的历史修复和最关键的下一步。
  • 如果用户提供了小版本号,历史问题排查必须以该版本为边界,只看同一分支中该版本之后的相关修复,不看更早版本,也不跨到其他大分支去找“类似问题”。

按问题类别的优先排查点

应用异常退出

  • 先看是 CppCrash 还是 JS Crash,再决定主要看 FaultLog 还是 JS 异常栈。
  • 优先抓崩溃线程、信号类型、顶层模块和触发阶段。
  • 重点关注销毁后回调、初始化时序错误、异常逃逸、兼容性缺失和 release 构建差异。

应用冻屏

  • 先确认进程是否仍存活,是否有 THREAD_BLOCK、APP_INPUT_BLOCK、LIFECYCLE_TIMEOUT。
  • 优先看主线程、JS 线程和锁相关线程是否互相等待。
  • 重点关注锁顺序、锁重入、同步等待、持锁回调和错误线程访问。

内存异常

  • 先区分 OOM 和地址越界,不要把所有内存问题都当成泄漏。
  • 如果是崩溃,优先看 UAF、悬空指针、空指针、越界读写。
  • 如果是增长,优先判断是短时突增还是长期累积,再看对象生命周期和释放闭环。

资源泄漏

  • 优先确认异常增长的是句柄、线程、请求、监听器还是长期持有对象。
  • 重点关注 callback 未清理、listener 未解绑、cache 未释放、线程未回收、实例销毁后仍被持有。
  • 要明确说明“资源泄漏”与“内存异常”可能相关,但不应混为同一结论。

建议工作流

第 1 步:提取问题画像

先从日志里提取最关键的事实:

  • 崩溃线程:JS 线程、UI 线程、Worker 线程、主线程。
  • 崩溃信号或错误:SIGSEGV、SIGABRT、abort、mapping error、undefined error、deadlock、null pointer、UAF。
  • 顶层栈帧所属模块:如 ImageComponentInstance、JSVMRuntime、HostObjectProxy、FontRegistry、AnimatedNodesManager、ArkUINode、ModalHostView。
  • 触发阶段:启动、reload、销毁、关闭、图片回调、布局提交、动画帧、滚动结束、字体注册、TM 回调。
  • 版本范围:旧分支还是当前主分支。

先把这些事实整理成一个“问题画像五元组”:

  1. 现象:闪退 / 卡死 / OOM / 泄漏。
  2. 类别:应用异常退出 / 应用冻屏 / 内存异常 / 资源泄漏。
  3. 线程或错误:JS 线程、主线程、SIGSEGV、APP_INPUT_BLOCK 等。
  4. 模块:ImageComponentInstance、JSVMRuntime、FontRegistry、ArkUINode 等。
  5. 触发阶段:启动、reload、销毁、动画、图片回调、布局提交等。

后续所有判断都围绕这五项展开,避免分析越写越散。

第 2 步:先查历史修复

优先读取 references/history-index.md

用途:

  • 快速把问题映射到稳定性类别。
  • 识别高频历史修复主题和关键词。
  • 决定是否进一步打开工作区里的原始汇总文档。

如果索引显示高度相似,再按需打开工作区中的原始文档:

  • docs/zh-cn/稳定性/稳定性历史修复/0.72稳定性修复汇总/
  • docs/zh-cn/稳定性/稳定性历史修复/0.77稳定性修复汇总/
  • docs/zh-cn/稳定性/稳定性历史修复/0.82稳定性修复汇总/

优先使用下面顺序检索,而不是无差别翻所有历史文档:

  1. 先看 references/history-index.md 的类别、关键词和高频模块。
  2. 再根据用户版本确定检索边界。
  3. 最后在边界内做全量扫描,而不是只挑典型条目。

如果用户同时提供了 GitCode PR / MR 链接,按下面优先级读取:

  1. 先检查 references/gitcode-config.json 是否存在有效 gitcode_access_token
  2. 如果有有效 token,优先调用 GitCode API 获取 PR 详情、文件列表和 patch。
  3. 如果没有有效 token,则退回到公开 PR 页面抓取、git fetch 或本地 diff 分析。
  4. 如果 PR 非公开且缺少有效 token,要明确告诉用户当前无法完整读取 PR 详情,并继续基于已有日志、版本和本地代码做分析。

历史修复检索边界

按下面规则限制历史问题检索范围:

  1. 如果用户只提供大版本,例如 0.72 / 0.77 / 0.82,可以先看该分支的全部相关历史修复。
  2. 如果用户提供了小版本,例如 0.72.53 / 0.77.18 / 0.82.3,必须只看同一分支里该小版本之后的相关修复。
  3. 不要看该小版本之前的历史问题,因为它们通常已经包含在用户当前版本中,不能作为“后续已修复”的证据。
  4. 不要跨分支查找,例如用户是 0.72.53,就不要去看 0.77 和 0.82 的历史修复来直接下结论。

例如:

  • 用户版本是 0.72.53,只看 0.72 分支中 0.72.53 之后的相关修复;不看 0.72.53 之前的条目,也不看 0.77、0.82。
  • 用户版本是 0.77.18,只看 0.77.18 之后的 0.77 分支相关修复;不看 0.72,也不看 0.82。

只有在用户明确要求做跨分支演进分析,或者要判断“后续大版本是否继续修过同类问题”时,才允许把其他分支作为辅助参考;这时也必须明确标注为“后续分支的相似修复”,不能直接当作当前分支已命中的结论。

历史修复全量扫描要求

在确定分支和版本边界后,必须做边界内的全量相关扫描:

  1. 先按问题类别定位到对应 README 和分类文件。
  2. 再把边界内所有相关条目逐条过一遍,至少比较问题描述、影响模块、问题类型、触发时机。
  3. 不要只看索引里的代表性问题,也不要只挑标题最像的 1 到 2 条。
  4. 最终输出时,可以只列最相关的 1 到 3 条,但这个结论必须建立在已经做过全量扫描的前提上。

优先查看对应分类文件和 README 表格中的条目,确认:

  • 问题描述是否相近。
  • 影响模块是否重合。
  • 问题类型是否一致。
  • 触发时机是否一致。
  • 是否存在直接可引用的提交、MR、版本号。

匹配等级按下面标准给出:

  • 高匹配:模块、触发阶段、异常形态都相近,且历史条目描述能直接解释当前日志。
  • 中匹配:问题家族一致,但触发条件或堆栈细节有差异。
  • 低匹配:只是在大类上相似,不能当作同一问题。

第 3 步:结合当前框架代码验证

如果工作区里有框架代码,继续验证最近代码状态。重点关注:

  • packages/react-native-harmony/
  • packages/react-native/
  • packages/react-native.patch
  • 与日志命中的模块、类名、函数名直接相关的位置

验证时优先搜这些内容:

  • 日志中直接出现的类名、函数名、错误字符串。
  • 历史修复条目中的模块名、提交标题关键词和防护模式。
  • 生命周期相关字段,例如 destroyed、isValid、weak_ptr、callback cleanup、removeListener。
  • 并发相关字段,例如 mutex、scoped_lock、reportMount、runOnQueue、main thread、UI thread。

验证时重点看这些模式:

  • 生命周期保护是否存在:销毁标记、弱引用、空指针保护、回调解绑、observer 反注册。
  • 并发保护是否存在:锁顺序、锁作用域、线程切换、是否在错误线程访问对象。
  • 资源释放是否闭环:回调、HTTP 请求、JSVM 引用、code cache、事件监听器。
  • 异常边界是否完整:空值检查、越界保护、异常捕获、非法状态兜底。
  • 平台兼容是否有防护:API12 兼容、混淆规避、符号冲突处理、bundle 加载路径适配。

如果最新代码里已经存在明显保护,而用户版本较旧,这通常支持“历史已修复、建议升级或回捞补丁”的结论。

第 4 步:判断归因

归因只能分成三类:用户代码问题、框架问题、证据不足。

先给倾向,再给证据,再给置信度。不要只写一句“更像框架问题”。

更像框架问题的信号

  • 崩溃栈主要落在框架内部模块,且与历史稳定性修复条目高度相似。
  • 问题发生在销毁、reload、回调晚到、跨线程访问、锁重入、资源释放这类框架常见薄弱点。
  • 即便没有业务代码,日志已经能显示空指针/UAF/死锁发生在框架内部对象管理上。
  • 当前最新代码里能看到针对同类问题新增的保护逻辑,而用户版本可能尚未包含。

更像用户代码问题的信号

  • 崩溃由非法入参、错误生命周期调用、异常自定义组件命名、错误线程使用方式、重复初始化或不满足接口契约触发。
  • 日志明确落到业务侧 JS/ArkTS/原生模块,并且框架栈只是被动承接。
  • 历史修复中没有相似框架缺陷,反而已有约束说明或已知接入要求。

证据不足时的写法

不要硬判。应该写:

  • 当前更偏向哪一侧。
  • 支持这个倾向的证据。
  • 缺少哪些材料会影响最终定性。
  • 当前置信度是高 / 中 / 低。
  • 如果当前置信度较低,要明确建议下一步补充哪些信息;如果用户有可复现的问题环境,也要建议在必要的模块、生命周期节点或回调链路上增加日志,再基于新增日志继续分析。

第 5 步:给出修复建议

建议按优先级从高到低输出,优先给可执行项:

  1. 升级建议:明确指出升级到哪个版本,并提供对应 PR/MR 链接。

    • 例如:升级到 0.82.3 或以上版本,包含修复 !1985
  2. 补丁回捞建议:如果暂时无法升级,给出具体的提交号和 MR 号,便于回捞特定补丁。

    • 例如:如无法升级,可回捞提交 409e3d355 或应用 !1985 中的修改。
  3. 规避方案:如果暂时不能升级或回捞补丁,给规避方案,例如避免某类触发路径、增加判空、避免销毁后回调、修正线程模型。

  4. 业务接入检查:如果怀疑业务接入问题,指出需要自查的接口契约和调用时机。

  5. 诊断建议:如果证据不足,明确建议补哪些日志、哪些符号化信息、哪些复现场景。

  • 如果存在问题环境且能够改代码,优先建议在最可疑的模块、线程切换点、生命周期边界、销毁路径、回调入口出口等必要位置增加日志,而不是无差别大量打印。

如果当前只能给出一个建议,优先给“最可能立刻缩小范围”的建议,而不是罗列所有可能动作。

输出格式

除非用户明确要求别的格式,否则按下面结构输出:

稳定性问题分析

1. 结论摘要

  • 用 2 到 4 句话总结问题画像、当前倾向和置信度。
  • 第一段就要明确问题类别、触发阶段和最可疑模块,不要把关键信息埋到后文。

2. 历史修复匹配

  • 是否命中历史修复:命中 / 部分命中 / 未命中。
  • 如果命中,列出相关版本、问题名、模块、问题类型、为什么相似。
  • 必须提供对应的提交链接和 MR/PR 链接,格式为:
  • 如果引用了原始汇总文档,给出对应文档路径和条目锚点。

3. 归因判断

  • 结论:更像框架问题 / 更像用户代码问题 / 暂时无法定性。
  • 原因:用证据支撑,不要只给结论。

4. 关键证据

  • 摘出最关键的日志特征、栈帧、代码保护点或缺失点。
  • 如果是冻屏或泄漏,关键证据也可以是线程状态、资源增长趋势或未释放链路,而不一定是崩溃栈。

5. 修复建议

  • 按优先级编号列出。
  • 区分"立刻可做"和"进一步确认"。
  • 当涉及升级或补丁回捞时,必须给出对应的提交链接和 MR 链接,格式为:

6. 仍需补充的信息

  • 只列真正会改变判断的信息。
  • 最多列 3 项,并按优先级排序。
  • 如果当前结论可信度较低,这一节必须给出明确下一步:补充更多信息,或者在问题环境的关键位置增加日志后重新分析。

历史修复匹配时的引用要求

如果确认或高度怀疑属于历史已修复问题,至少给出这些信息:

  • 对应分支和版本。
  • 问题标题。
  • 提交号(带 GitCode 链接)和 MR 号(带 GitCode 链接)。
  • 该修复解决的根因摘要。
  • 为什么它能解释当前日志。

链接格式要求:

  • 提交链接:[提交号](https://gitcode.com/OpenHarmony-RN/ohos_react_native/commit/提交号)
  • MR/PR 链接:[!MR号](https://gitcode.com/OpenHarmony-RN/ohos_react_native/merge_requests/MR号)

例如:

  • 高匹配命中:图片回调晚于实例销毁导致悬空 URI 崩溃

如果无法确认是同一问题,要明确写“相似问题家族”而不是“就是同一个问题”。

常见问题到类别的映射

  • 应用异常退出:优先覆盖 CppCrash 和 JS Crash,重点关注 SIGSEGV、SIGABRT、abort、undefined error、bundle load failure、异常逃逸、生命周期结束后继续回调等问题。
  • 应用冻屏:优先覆盖线程阻塞、输入阻塞、生命周期超时,重点关注死锁、锁顺序不一致、锁重入、错误线程访问、同步等待和卡死。
  • 内存异常:优先覆盖 OOM 和地址越界,重点关注 UAF、悬空指针、裸指针、空指针、越界访问、mapping error、非法释放和对象生命周期错配。
  • 资源泄漏:优先覆盖句柄泄漏、线程泄漏和长期未释放资源,重点关注监听器未注销、线程未回收、cache 未释放、请求回调未清理和长期持有上下文对象。

质量要求

  • 用中文输出。
  • 结论要分层:已知事实、推断、建议不能混在一起。
  • 不要只给"建议升级"这种空话;要说明升级或补丁为什么相关,并必须包含对应的提交链接和 MR 链接
  • 如果用户没有业务代码,避免把责任直接甩给用户。
  • 如果日志直接显示框架内部同类缺陷,也不要因为“用户代码不可见”就回避框架归因。
  • 面向伙伴输出时,优先保证“能指导下一步动作”,其次才是面面俱到。
  • 如果命中历史修复,优先给“为什么像”“差异在哪”“建议先升级还是先回捞”。
  • 如果没命中历史修复,也要明确给出当前最可疑的模块或链路,避免输出停留在大类层面。
  • 如果最终判断可信度较低,不能只写“信息不足”;必须给出建议补充的信息,必要时建议在问题环境中的关键位置增加日志。