Tencent / Tencent/libpag

[HarmonyOS][4.5.93] taskpool 间接导入 PAG 时 Native 初始化 SIGSEGV,伴随 owner env has been destroyed

Open
#3,725 1 comment 0 reactions 1 assignee View on GitHub

@kevingpqi123 is already working on this.

Since Sep 10, 2026.

Dominant language
HTML
Stars
5.8k
Forks
531
Avg merge
8d 55m
Merged PRs (30d)
17

Description

【版本信息】

  • 线上出现崩溃的版本:@tencent/libpag 4.5.93,ARM64。
  • 崩溃 SO Build ID:bb1a2fbf6a5e429c05bf5d89d494b185ed192c36,与本地 4.5.93 包内 SO 一致。
  • 已核对 #3431、#3629、#3692:4.5.93 已包含相关引用管理/并发初始化修复。
  • 另外对比了 4.5.94:src/platform/ohos/JsHelper.cppJPAG.cpp 与 4.5.93 字节一致;官方 4.5.94 OHOS HAR 的 SO(Build ID 0ac40311a19268557a3dacc69f889168a8a09fb8)也保留相同清理参数和缓存取用逻辑。4.5.94 仅做了源码及二进制核验,没有完成同场景真机复现,不能据此声称它线上同样崩溃。
  • 4.5.93 → 4.5.94 差异包含字体回退、视频解码及 tgfx 更新,希望确认发布说明中的并发初始化修复是否另有尚未覆盖的生命周期场景。

【平台信息】

HarmonyOS 原生,ARM64 真机,系统 6.1.0 系列。

一个取得完整 faultlog 的同路径样本来自 HUAWEI Pura 80 Pro,系统版本 LMR-AL00 6.1.0.135(SP8C00E120R10P6)。文末附的是另一份同 PAG Build ID / 偏移的堆栈,其系统库 Build ID 不同,不将二者当成同一现场。

【预期的表现】

taskpool 工作线程通过依赖导入 PAG Native 模块时,模块初始化应正确管理各 JS 环境的构造函数引用;环境销毁后,旧引用不应在后续初始化中再次被使用。

应用侧没有在这些 taskpool 任务中创建 PAG 视图或播放动画。即使公共入口间接引入了 PAG,也希望 SDK 能正确处理模块初始化、环境退出和再次初始化;若该导入方式不受支持,也请明确说明约束和推荐接入方式。

【实际的情况】

1. 无直接 PAG 调用的后台任务,也会进入 PAG Native Init

项目的依赖结构如下(仅为结构说明,不是已验证的最小复现 Demo):

@Concurrent 后台数据任务
  → 从业务公共入口导入日志 / 网络工具
  → 公共入口同时 re-export 一个 PAG UI 包装组件
  → 包装组件普通 import @tencent/libpag
  → PAG 包内部 import 'libpag.so'
  → 在 taskpool 环境执行 PAG Native Init

后台任务没有调用 PAGFile.Load、创建 PAGView 或播放动画。崩溃栈却明确是:

TaskPool::Worker::PerformTask
 → napi_deserialize
 → JSFunction::InitializeForConcurrentFunction
 → SourceTextModule::ModuleEvaluation
 → ArkNativeEngine::LoadNativeModule
 → libpag.so
 → napi_get_named_property
 → JSNApi::NapiGetNamedProperty
 → SIGSEGV,fault addr = 0

从匹配 Build ID 的 4.5.93 SO 调用指令、字符串常量和同版本源码对应看,PAG 路径是:

Init → JPAGLayerHandle::Init → InitPAGImageLayerEnv
 → DefineClass → ExtendClass → GetConstructor(parentName)
 → 读取父类 prototype

对应 PAG 栈偏移为 0x214678 → 0x223e00 → 0x21bc90 → 0x22f590 → 0x22f25c0x22f25c 调用 napi_get_named_property,传入字符串为 prototype。SO 调试符号已裁剪,以上是二进制与源码交叉定位,不是 addr2line 直接返回的行号。

2. 部分同路径样本明确报告引用所属环境已销毁

以下摘录已去掉进程、用户和应用标识:

[ValidEngineCheck] owner env has been destroyed, owner id: 18, current env id: 22.
Get at ark_native_reference.cpp:167
ArkNativeReference::Get
 → napi_get_reference_value
 → libpag.so +0x22f180
 → libpag.so +0x22f240
 → libpag.so +0x22f590
 → libpag.so +0x21bc90
 → libpag.so +0x223e00

同批日志还出现过:

[AddCleanupHook] AddCleanupHook Failed, data cannot register multiple times,
enable cross-thread check for more information.

这能证明同路径样本有失效环境引用的读取,以及存在清理注册冲突;尚不能证明该冲突一定来自 PAG 的那次注册,也没有取得完整的引用创建/清理/环境地址复用记录。

3. 源码中希望维护者核查的疑点

在 4.5.93 / 4.5.94 的 JsHelper.cpp 中:

  • ConstructorRefMapnapi_env 指针地址索引。
  • 首次创建缓存时注册 napi_add_env_cleanup_hook(env, CleanupConstructorRefs, env),第三参数直接使用公共的 env 地址。
  • SetConstructor 发现同名条目时直接返回成功,复用现有引用。
  • ExtendClass 通过 GetConstructor 从缓存获取父类,再读取 prototype

官方 cleanup hook 文档明确说明同一个 arg 不能绑定多个回调,环境已销毁而 cleanup 未执行时应检查上述重复注册错误。

公开 OpenHarmony 6.0 的 AddCleanupHook 按 arg 作为键;其外层 napi_add_env_cleanup_hook没有传出内部注册失败状态。因此该公开实现中,调用方的 status 检查未必能发现实际注册冲突。商业 ROM 是否逐项一致,仍需验证。

待验证的机制推断:若 PAG 清理回调注册失败,旧环境退出后缓存遗留;新环境地址复用时,SetConstructor 命中旧条目并保留原引用,随后 ExtendClass 读取属于已销毁环境的父类。我们没有把这条完整过程当成已证实的唯一根因。

4. 线上操作与本地复现情况

线上多次发生在同一应用进程中:选图进入编辑器 → 编辑确认/保存 → 返回相册 → 再次选图进入编辑器,部分会穿插前后台切换。也有进入另一个编辑面板时触发后台素材加载后崩溃。

这些流程会再次提交数据请求等 taskpool 任务,不要求用户播放 PAG 动画。现有日志没有把最终崩溃线程唯一对应到某一个业务 taskId。

本地普通播放动画、正常操作 taskpool 尚未稳定复现。没有 100% 必现步骤,也没有已验证的最小 Demo。工作线程退出/重建及清理缺失的完整过程需要进一步观测。

5. 希望 SDK 后续处理
  1. 核查 cleanup hook 使用公共 env 作参数的冲突风险,考虑采用与当前环境绑定的独立唯一清理上下文。
  2. 核查新环境初始化时复用旧构造函数条目的可能性,确保缓存严格随所属环境销毁,不仅依赖地址和类名相同。
  3. 在环境反复创建/销毁、多个 Native 模块同时注册 cleanup hook 的场景下补充回归验证。
  4. 确认应用没有实际调用 PAG、仅经公共模块间接导入时的推荐用法。应用侧正评估用静态懒加载隔离后台任务依赖;此规避尚未实施验证,也不能替代 SDK 对已创建引用的正确管理。

相关历史记录:#3237、#3431、#3629、#3692,以及 Discussion #3627。本次是初始化读取属性时的 SIGSEGV,并非仅重复报告旧版跨线程删除引用的 SIGABRT。

【Demo及附件】

暂无可公开的最小复现 Demo;目前没有证据指向某个 PAG 素材。以下为未包含用户标识和内部业务参数的完整 Native 栈:

完整 SIGSEGV 堆栈(PAG 4.5.93)
signal 11 (SIGSEGV),code 1,fault addr 000000000000000000

backtrace:
    #00 pc 0000000000a82d60  /system/lib64/platformsdk/libark_jsruntime.so (panda::JSNApi::NapiGetNamedProperty(panda::ecmascript::EcmaVM const*, unsigned long, char const*)+332) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #01 pc 000000000005c6d8  /system/lib64/platformsdk/libace_napi.z.so (napi_get_named_property+264) [buildId: e60d638ba9beaa9ab1a7bce088a5b688]
    #02 pc 000000000022f25c  /data/storage/el1/bundle/libs/arm64/libpag.so [buildId: bb1a2fbf6a5e429c05bf5d89d494b185ed192c36]
    #03 pc 000000000022f590  /data/storage/el1/bundle/libs/arm64/libpag.so [buildId: bb1a2fbf6a5e429c05bf5d89d494b185ed192c36]
    #04 pc 000000000021bc90  /data/storage/el1/bundle/libs/arm64/libpag.so [buildId: bb1a2fbf6a5e429c05bf5d89d494b185ed192c36]
    #05 pc 0000000000223e00  /data/storage/el1/bundle/libs/arm64/libpag.so [buildId: bb1a2fbf6a5e429c05bf5d89d494b185ed192c36]
    #06 pc 0000000000214678  /data/storage/el1/bundle/libs/arm64/libpag.so [buildId: bb1a2fbf6a5e429c05bf5d89d494b185ed192c36]
    #07 pc 000000000004f870  /system/lib64/platformsdk/libace_napi.z.so (ArkNativeEngine::LoadNativeModule(NativeModuleManager*, panda::Local<panda::StringRef>&, NativeModule*, panda::Local<panda::JSValueRef>, std::__h::basic_string<char, std::__h::char_traits<char>, std::__h::allocator<char>>&)+736) [buildId: e60d638ba9beaa9ab1a7bce088a5b688]
    #08 pc 0000000000074498  /system/lib64/platformsdk/libace_napi.z.so (ArkNativeEngine::RequireNapi(panda::JsiRuntimeCallInfo*)+344) [buildId: e60d638ba9beaa9ab1a7bce088a5b688]
    #09 pc 00000000002ae5a4  /system/lib64/platformsdk/libark_jsruntime.so (panda::Callback::RegisterCallback(panda::ecmascript::EcmaRuntimeCallInfo*)+3332) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #10 pc 0000000000e88080  /system/lib64/module/arkcompiler/stub.an (RTStub_AsmInterpreterEntry+484)
    #11 pc 0000000000e87ed8  /system/lib64/module/arkcompiler/stub.an (RTStub_AsmInterpreterEntry+60)
    #12 pc 00000000002130e8  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::InterpreterAssembly::Execute(panda::ecmascript::EcmaRuntimeCallInfo*)+960) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #13 pc 000000000045a3b8  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::SourceTextModule::LoadNativeModuleImpl(panda::ecmascript::EcmaVM*, panda::ecmascript::JSThread*, panda::ecmascript::JSHandle<panda::ecmascript::SourceTextModule> const&, panda::ecmascript::ModuleTypes)+5668) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #14 pc 00000000004556ec  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::SourceTextModule::LoadNativeModule(panda::ecmascript::JSThread*, panda::ecmascript::JSHandle<panda::ecmascript::SourceTextModule> const&, panda::ecmascript::ModuleTypes)+100) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #15 pc 000000000044fde0  /system/lib64/platformsdk/libark_jsruntime.so [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #16 pc 000000000044f894  /system/lib64/platformsdk/libark_jsruntime.so [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #17 pc 000000000044f894  /system/lib64/platformsdk/libark_jsruntime.so [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #18 pc 000000000044f894  /system/lib64/platformsdk/libark_jsruntime.so [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #19 pc 000000000044f894  /system/lib64/platformsdk/libark_jsruntime.so [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #20 pc 00000000004d4eb4  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::SourceTextModule::ModuleEvaluation(panda::ecmascript::JSThread*, panda::ecmascript::JSHandle<panda::ecmascript::SourceTextModule> const&, int, panda::ecmascript::JSHandle<panda::ecmascript::Method> const&)+544) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #21 pc 00000000004d3d88  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::JSFunction::InitializeForConcurrentFunction(panda::ecmascript::JSThread*, panda::ecmascript::JSHandle<panda::ecmascript::JSFunction>&)+996) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #22 pc 00000000004d15fc  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::BaseDeserializer::DeserializeJSTaggedValue()+592) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #23 pc 00000000004d12f8  /system/lib64/platformsdk/libark_jsruntime.so (panda::ecmascript::BaseDeserializer::ReadValue()+236) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #24 pc 0000000000a7e260  /system/lib64/platformsdk/libark_jsruntime.so (panda::JSNApi::DeserializeValue(panda::ecmascript::EcmaVM const*, void*, void*)+452) [buildId: a866290168be3d92b0a3fe6703efc9b5]
    #25 pc 00000000000632a4  /system/lib64/platformsdk/libace_napi.z.so (napi_deserialize+164) [buildId: e60d638ba9beaa9ab1a7bce088a5b688]
    #26 pc 0000000000049198  /system/lib64/module/libtaskpool.z.so (Commonlibrary::Concurrent::TaskPoolModule::Worker::PerformTask(uv_async_s const*) (.cfi)+4708) [buildId: dcb82263d27bd65dc3df1320fdaf55ec]
    #27 pc 000000000001bd10  /system/lib64/platformsdk/libuv.so (uv__async_io+536) [buildId: 2f80c4c7008ea3d584b8f5d8a7da8774]
    #28 pc 0000000000031d84  /system/lib64/platformsdk/libuv.so (uv__io_poll+1300) [buildId: 2f80c4c7008ea3d584b8f5d8a7da8774]
    #29 pc 000000000001ce68  /system/lib64/platformsdk/libuv.so (uv_run+1004) [buildId: 2f80c4c7008ea3d584b8f5d8a7da8774]
    #30 pc 0000000000046d70  /system/lib64/module/libtaskpool.z.so (Commonlibrary::Concurrent::TaskPoolModule::Worker::ExecuteInThread(void const*) (.cfi)+2168) [buildId: dcb82263d27bd65dc3df1320fdaf55ec]
    #31 pc 000000000003cc58  /system/lib64/module/libtaskpool.z.so (Commonlibrary::Concurrent::TaskPoolModule::TaskRunner::TaskInnerRunner::Run()+72) [buildId: dcb82263d27bd65dc3df1320fdaf55ec]
    #32 pc 00000000001e3b68  /system/lib/ld-musl-aarch64.so.1 (start+240) [buildId: ea15b39b4de0a4a2001767700c0ebe28]

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.