背景知识
- 近场通信(Near Field Communication,NFC)是一种短距高频的无线电技术,在13.56MHz频率运行,通信距离一般在10厘米范围内。
- HCE(Host Card Emulation),称为基于主机的卡模拟,表示不依赖安全单元芯片,电子设备上的应用程序模拟NFC卡片和NFC读卡器通信,实现NFC刷卡业务。
- 3100301 NFC卡模拟状态异常:NFC服务执行卡模拟业务逻辑遇到错误。
- CppCrash进程崩溃检测基于操作系统信号机制,目前支持的崩溃信号参考Cpp Crash(进程崩溃)检测。
- CppCrash日志规格说明可以参考日志规格说明。
- JS Crash异常根据不同的异常场景,在Reason字段进行了分类,分为Error、TypeError、SyntaxError、ReferenceError、RangeError等错误类型。参考文档JS Crash(进程崩溃)检测。
- JS Crash日志规格说明可以参考日志规格。
- 用户在使用应用时,如果出现点击无反应或应用无响应等情况,并且持续时间超过一定限制,就会被定义为应用无响应,详情参考AppFreeze(应用冻屏)检测。
- AppFreeze日志规格说明可以参考日志规格。
[h2]场景一
- 在hilog日志中搜索关键字kill Reason,找到应用的进程号10300对应的终止记录,可以看到应用被终止的原因是OnRemoteDied。
05-09 20:40:40.407 952 1197 I C01713/resource_schedule_service/SUSPEND_MANAGER: [(RemoveProcess):463] remove process 20020043_应用包名_10300, processNum: 0
05-09 20:40:40.407 1547 11114 I C01311/foundation/AppMS: [app_mgr_service_inner.cpp:2679]kill reason=OnRemoteDied, pid=10300
05-09 20:40:40.407 623 13474 I C02C03/PARAM_WATCHER: [watcher_manager.cpp:504]Agent died 972 10300
- 从kill Reason日志向上查找关键字OnRemoteDied,可以看到错误日志是hce on remote died,错误码是3100301。
05-09 20:40:40.407 11311 11336 E C00301/nfc_service/Nfc_Core: [(UnRegAllCallback:92)]hce is null
05-09 20:40:40.407 623 13474 W C057C2/param_watcher/IPCObjectProxy: SendObituary 513: handle:51 desc:*.IWatcher 2665647552
05-09 20:40:40.407 11311 11336 I C00301/nfc_service/Nfc_Core: [(OnRemoteDied:35)]OnRemoteDied, UnRegAllCallback ret=3100301
05-09 20:40:40.407 11311 11336 E C00301/nfc_service/Nfc_Core: [(RemoveHceDeathRecipient:335)]hce on remote died
- 通过错误码可以判断应用注册HCE前未检测设备是否打开NFC。
[h2]场景二
- 查看faultlogger目录下的CppCrash崩溃日志,故障原因是SIGABRT,进程异常终止,LastFatalMessage为Unexpected call: exit(-1),发生了未预期的exit退出函数调用。
Reason:Signal:SIGABRT(SI_TKILL)@0x01317c0400007129 from:28969:20020228
LastFatalMessage:[appspawn_server.c:57]Unexpected call: exit(-1)
- 排查堆栈,栈顶是libappspawn_helper.z.so中exit函数调用了abort函数终止了进程,而exit函数是下一个栈帧libjiagu.so中调用,需要梳理动态库中直接调用exit的业务场景,分析是否有必要直接exit。
Fault thread info:
Tid:29027, Name:com.hx.example
#00 pc 000000000019ca00 /system/lib/ld-musl-aarch64.so.1(raise+228)(f77c0346c0084ebbadf721ea319f5f77)
#01 pc 0000000000149b70 /system/lib/ld-musl-aarch64.so.1(abort+20)(f77c0346c0084ebbadf721ea319f5f77)
#02 pc 0000000000001ca4 /system/lib64/libappspawn_helper.z.so(exit+144)(1f3a93bc50a79f539e4c02b5b88b2ee9)
#03 pc 000000000001dd84 /data/storage/el1/bundle/libs/arm64/libjiagu.so(e2e257836d5f3479377e680f3812454d0cd87a0e)
#04 pc 00000000001bdcac /system/lib/ld-musl-aarch64.so.1(start+236)(f77c0346c0084ebbadf721ea319f5f77)
[h2]场景三
- 从faultlogger目录下获取到应用的SysFreeze和JS Crash故障日志,SysFreeze故障原因为LIFECYCLE_TIMEOUT,搜索崩溃栈,关键字TID:进程ID(PID),观察到半周期堆栈里有清晰的业务调用信息,阻塞堆栈中信息不完整,Failed to dump,原因是process is dumping当前进程已经在dump当中。
// LIFECYCLE_HALF_TIMEOUT半周期检测堆栈
Tid:42239, Name:com.hx.example
#00 pc 000000000007ae88 /data/storage/el1/bundle/libs/arm64/libapplogrs.so
#01 pc 000000000007ae74 /data/storage/el1/bundle/libs/arm64/libapplogrs.so
#02 pc 0000000000e12868 /system/lib64/module/arkcompiler/stub.an(RTStub_PushCallArgsAndDispatchNative+40)
#03 pc 000000000038959c /system/lib64/module/arkcompiler/stub.an(BCStub_HandleCallthis1Imm8V8V8WithProf+1060)
#04 at init (xxx|@dp/applog|1.2.16|src/main/ets/AppLogInstance.ts:114:1)
#05 at initAppLog (xxx|@xxx/applog|1.0.0|src/main/ets/b60.ts:46:1)
#06 at run (xxx|xxx|1.0.0|src/main/ets/y179/k58/g181.ts:11:1)
#07 at runSyncTask (xxx|@hpaas/ez_launch_task|4.2.55|src/main/ets/LaunchTaskScheduler.ts:132:1)
#08 at runTasks (xxx|@hpaas/ez_launch_task|4.2.55|src/main/ets/LaunchTaskScheduler.ts:50:1)
#09 at confirmStage (xxx|@hpaas/ez_launch_task|4.2.55|src/main/ets/LaunchTaskScheduler.ts:42:1)
#10 at onUIAbilityCreate (xxx|xxx|1.0.0|src/main/ets/y179/z179.ts:63:1)
#11 at onCreate (xxx|xxx|1.0.0|src/main/ets/xxxability/DcarUIAbility.ts:77:1)
// LIFECYCLE_TIMEOUT阻塞堆栈
Failed to dump normal stacktrace for 42239
Reason:
normal stack:process is dumping
Tid:42239, Name:com.hx.example
#00 pc 000000000007ce1c /data/storage/el1/bundle/libs/arm64/libapplogrs.so
#01 pc 0000000000e12868 /system/lib64/module/arkcompiler/stub.an
#02 pc 000000000038959c /system/lib64/module/arkcompiler/stub.an
- 从mainHandler主线程任务队列信息中观察到,当前执行任务并没有改变,并且两个堆栈中stub.an的指令地址相同,所以可以确定两个的堆栈业务是一致的,应用函数执行时间过长。
// LIFECYCLE_HALF_TIMEOUT半周期检测堆栈
mainHandler dump is:
EventHandler dump begin curTime: 2025-11-08 14:13:52.248
Event runner (Thread name = , Thread ID = 42239) is running
Current Running: start at 2025-11-08 14:13:49.750, Event { send thread = 42281, send time = 2025-11-08 14:13:49.742, handle time = 2025-11-08 14:13:49.742, trigger time = 2025-11-08 14:13:49.750, task name = UIAbilityThread:AbilityTransaction, caller = [ui_ability_thread.cpp(ScheduleAbilityTransaction:339)] }
// LIFECYCLE_TIMEOUT阻塞堆栈
mainHandler dump is:
EventHandler dump begin curTime: 2025-11-08 14:13:54.771
Event runner (Thread name = , Thread ID = 42239) is running
Current Running: start at 2025-11-08 14:13:49.749, Event { send thread = 42281, send time = 2025-11-08 14:13:49.742, handle time = 2025-11-08 14:13:49.742, trigger time = 2025-11-08 14:13:49.749, task name = UIAbilityThread:AbilityTransaction, caller = [ui_ability_thread.cpp(ScheduleAbilityTransaction:339)] } - SysFreeze阻塞堆栈的process is dumping与JS Crash崩溃有关,进程正是在dump jscrash的日志,随后进程因JS Crash终止,所以SysFreeze阻塞栈导出异常。
11-08 14:13:52.381 1571 41366 I C02D11/foundation/DfxDumpCatcher: Receive DumpCatch request for cPid:(1571), pid(42239)
11-08 14:13:52.381 1571 41366 I C02D11/foundation/DfxFaultLogger: FAULT_LOGGERD_CLIENT.RequestSdkDump :: pid: 42239, tid: 0, isJson: 1.
11-08 14:13:52.383 575 575 I C02D11/DfxFaultLogger: FAULT_LOGGER_SERVER :: faultloggerd.sdkdump.server has processed request for pid: 1571, clientType: 1, and retCode 0
11-08 14:13:52.546 42544 42544 I C02D11/DfxFaultLogger: Start main function of processdump
11-08 14:13:52.718 575 575 I C02D11/DfxFaultLogger: FAULT_LOGGER_SERVER :: faultloggerd.crash.server receive request from pid: 42544, clientType: 2
11-08 14:13:52.718 42544 42544 I C02D11/DfxFaultLogger: unwind key thread dump start
11-08 14:13:52.718 42544 42544 I C02D11/DfxFaultLogger: GetKeyThreadStack, unwind tid(42239) start.
11-08 14:13:52.718 575 575 I C02D11/DfxFaultLogger: FAULT_LOGGER_SERVER :: faultloggerd.crash.server has processed request for pid: 42544, clientType: 2, and retCode 0
// ...
11-08 14:13:54.965 1571 38090 I C02D11/foundation/DfxDumpCatcher: Receive DumpCatch request for cPid:(1571), pid(42239)
11-08 14:13:54.965 1571 38090 I C02D11/foundation/DfxFaultLogger: FAULT_LOGGERD_CLIENT.RequestSdkDump :: pid: 42239, tid: 0, isJson: 1.
11-08 14:13:54.966 575 575 I C02D11/DfxFaultLogger: FAULT_LOGGER_SERVER :: faultloggerd.sdkdump.server receive request from pid: 1571, clientType: 1
11-08 14:13:54.966 575 575 I C02D11/DfxFaultLogger: Receive dump request for pid:42239 tid:0.
11-08 14:13:54.966 575 575 E C02D11/DfxFaultLogger: FAULT_LOGGER_SERVICE :: pid(42239) is dumping, break.
11-08 14:13:54.966 575 575 I C02D11/DfxFaultLogger: FAULT_LOGGER_SERVER :: faultloggerd.sdkdump.server has processed request for pid: 1571, clientType: 1, and retCode 5
- 查看JS Crash日志,发现异常原因是主窗调用getWindowProperties时,未能获取到窗口属性。
Reason:Error
Error name:Error
Error message:[window][getWindowProperties]msg: get property info failed
Error code:1300002
Stacktrace:
Cannot get SourceMap info, dump raw stack:
at calcInitScreenSize (xxx|@xxx/utils|1.0.0|src/main/ets/x/y.ts:141:1)
at initAndRegisterWindowSizeChange (xxx|@xxx/utils|1.0.0|src/main/ets/x/y.ts:159:1)
at anonymous (xxx|xxx|1.0.0|src/main/ets/xxxability/DcarUIAbility.ts:179:1) - SysFreeze和JsCrash是同步发生,顺序应该是应用启动卡在onCreate->foregroundTimeout超时->sessionException->触发主窗口销毁->应用调用到getWindowProperties产生JS Crash问题。
11-08 14:13:54.727 1571 34260 W C01336/foundation/AMS: [UALM1691]LIFECYCLE_TIMEOUT: uid: 20020200, pid: 42239, bundleName: com.hx.example, abilityName: DcarAbility, msg: ability:DcarAbility foreground timeout.
11-08 14:13:54.769 1571 34260 I C01336/foundation/AMS: [UALM2175]scb call, NotifySCBToHandleException reason: handleForegroundTimeout
11-08 14:13:54.772 3055 3055 I A04200/com.ohos.sceneboard/WINDOW: SCBSceneSession: on sessionException errorReason: handleForegroundTimeout, shouldSkipKillInStartup: false, needRemoveSession: false needClearCallerLink: true
11-08 14:13:54.800 3055 3055 I A04200/com.ohos.sceneboard/WINDOW: SCBSpecificScenePanelViewModel --> onDestroyFloatWindowFromSceneSession
11-08 14:13:54.806 3055 3400 I C04217/com.ohos.sceneboard/WMSAttribute: WindowDestroyNotifyVisibility: in, wid: 66, RSVisible: 0, WindowMode: 1
11-08 14:13:55.849 42239 42239 W C03F00/com.hx.example/ArkCompiler: [default] [CallForNapi:3949] occur exception need return
11-08 14:13:55.849 42239 42239 W C03F01/com.hx.example/NAPI: [napi_call_function] pending exception when js function called, print exception info:
11-08 14:13:55.849 42239 42239 E C03F00/com.hx.example/ArkCompiler: Error: [window][getWindowProperties]msg: get property info failed
11-08 14:13:55.850 1571 1571 I C01336/foundation/AMS: [app_exit_reason_helper58]not record extension reason: 2097247
11-08 14:13:55.850 1571 1571 E C01336/foundation/AMS: [app_exit_reason_helper71]abilityLists empty
[h2]场景一
注册HCE前未检测设备是否打开NFC,接口抛出异常导致应用闪退。
[h2]场景二
应用主动调用exit()函数终止进程。
[h2]场景三
函数执行时间过长,导致主线程超时卡死。
[h2]场景二
程序正常运行过程中,直接调用exit或abort强制终止程序,可能会造成内存泄漏,不建议使用,而是应当抛出相关异常错误码。
[h2]场景三
参考文档主线程耗时操作优化,当主线程中遇到一些难以避免的耗时操作时,例如同步网络请求、大文件读写、复杂计算、音频处理、数据传输等,可以从以下角度进行性能优化:
- 避免使用耗时接口,同一接口的不同使用方式存在性能差异,选择耗时更少,性能更优的接口。
- 使用多线程能力,可以使用系统自带的Taskpool多线程能力,将耗时任务交由子线程执行,避免主线程的长时间阻塞。