在HarmonyOS 5.0中,CppCrash指的是C/C++运行时崩溃,这类崩溃可能由空指针异常、数组越界异常、栈溢出异常等原因引起。系统提供了基于posix信号机制的崩溃异常检测能力,能够生成详细的故障日志以辅助故障定位。本文将详细介绍如何分析CppCrash,包括异常检测能力、崩溃问题定位分析思路,以及具体的案例分析。
CppCrash异常检测能力
进程崩溃基于posix信号机制,目前主要支持对以下崩溃异常信号的处理:
信号值(signo) | 信号 | 解释 | 触发原因 |
---|---|---|---|
4 | SIGILL | 非法指令 | 进程执行了非法、格式错误、未知或特权指令 |
5 | SIGTRAP | 断点或陷阱异常 | 异常或trap指令发生 |
6 | SIGABRT | 进程终止 | 进程异常终止,通常为进程自身调用abort()函数 |
7 | SIGBUS | 非法内存访问 | 进程访问了对齐或者不存在的物理地址 |
8 | SIGFPE | 浮点异常 | 进程执行了错误的算术运算,如除数为0、浮点溢出等 |
11 | SIGSEGV | 无效内存访问 | 进程访问了无效内存引用 |
16 | SIGSTKFLT | 栈错误 | 处理器执行了错误的栈操作,如栈空时弹出、栈满时压入 |
31 | SIGSYS | 错误的系统调用 | 系统调用时使用了错误或非法参数 |
以上部分故障信号,根据具体的场景还有二级分类(code)。
日志格式与获取
CppCrash故障根据报错场景可以分为运行态CppCrash故障和开发态CppCrash故障。在开发态下,DevEco Studio会收集CppCrash、App Freeze、JS Crash、System Freeze、ASan的崩溃日志到FaultLog下,开发者可以通过FaultLog的CppCrash日志、ASAN日志定位问题的具体原因。在运行态下,开发者需要提前开通崩溃服务,收集运行状态下的CppCrash。
基于崩溃栈定位行号
在应用开发场景中,对于应用自身的动态库,生成的cppcrash堆栈可以直接跳转到代码行处,支持Native栈帧和JS栈帧,无需开发者自行进行解行号操作。对于部分未能解析跳转到对应行号的栈帧,可以通过以下方式进行解析:
-
DevEco Studio开发者环境下,支持调用栈直接跳转到对应行号:在应用开发场景,对于应用自身的动态库,生成的cppcrash堆栈可以直接跳转到代码行处,支持Native栈帧和JS栈帧,无需开发者自行进行解行号操作。
-
使用addr2line工具:对于未能直接跳转的栈帧,可以使用addr2line工具将地址转换为代码行号。例如,使用以下命令:
$ addr2line -Cpie ./libcesfwk_core.z.so 000000000001c5a4 /mnt/disk/jenkins/ci/workspace/zidane_system_pipeline_release/compile/component_code/out/baltimore/../../base/notification/common_event_service/frameworks/core/src/common_event_proxy.cpp:385
这将帮助开发者快速定位到具体的代码行。
典型案例分析
锁范围不足导致的Crash问题
设备开关机压测时,崩溃在libcesfwk_core.z.so
,崩溃栈如下:
Timestamp:1970-11-28 13:44:49.206
Pid:2906
Uid:10006
Process name:com.ohos.xxx
Reason:Signal:SIGSEGV(SEGV_MAPERR)@0x00492e6b7766746e
Fault thread Info:
Tid:2978, Name:com.ohos.system
#00 pc 000000000003fea8 /system/lib64/libipc_core.z.so(OHOS::PeerHolder::Remote()+12)
#01 pc 000000000001c5a4 /system/lib64/libcesfwk_core.z.so(OHOS::EventFwk::CommonEventProxy::SendRequest(OHOS::EventFwk::ICommonEvent::Message, OHOS::MessageParcel&, OHOS::MessageParcel&)+168)
#02 pc 000000000001cff8 /system/lib64/libcesfwk_core.z.so(OHOS::EventFwk::CommonEventProxy::SubscribeCommonEvent(OHOS::EventFwk::CommonEventSubscribeInfo const&, OHOS::sptr<OHOS::IRemoteObject> const&)+540)
#03 pc 0000000000016518 /system/lib64/libcesfwk_core.z.so(OHOS::EventFwk::CommonEvent::SubscribeCommonEvent(std::__1::shared_ptr<OHOS::EventFwk::CommonEventSubscriber> const&)+468)
#04 pc 0000000000012c20 /system/lib64/libcesfwk_innerkits.z.so(OHOS::EventFwk::CommonEventManager::SubscribeCommonEvent(std::__1::shared_ptr<OHOS::EventFwk::CommonEventSubscriber> const&)+56)
#05 pc 000000000003253c /system/lib64/module/libcommonevent.z.so
#06 pc 0000000000019808 /system/lib64/libace_napi.z.so(NativeAsyncWork::AsyncWorkCallback(uv_work_s*)+316)
#07 pc 000000000001156c /system/lib64/libuv.so
#08 pc 00000000000d02a0 /system/lib64/libc.so(__pthread_start(void*)+40)
#09 pc 0000000000072128 /system/lib64/libc.so(__start_thread+68)
...
根据Reason可知为野指针,根据#01
定位到具体的代码行有:
$ addr2line -Cpie ./notification/common_event_service/libcesfwk_core.z.so 000000000001c5a4
/mnt/disk/jenkins/ci/workspace/zidane_system_pipeline_release/compile/component_code/out/baltimore/../../base/notification/common_event_service/frameworks/core/src/common_event_proxy.cpp:385
对应的代码如下所示:
bool CommonEventProxy::SendRequest(ICommonEvent::Message code, MessageParcel &data, MessageParcel &reply) {EVENT_LOGD("start");sptr<IRemoteObject> remote = Remote();if (remote == nullptr) {EVENT_LOGD("Remote is NULL, %{public}d", code);}MessageOption option(MessageOption::TF_SYNC);int32_t result = remote->SendRequest(static_cast<uint32_t>(code), data, reply, option);if (result != OHOS::NO_ERROR) {return false;}EVENT_LOGD("end");return true;
}
通过分析,可以发现remote
指针可能为nullptr
,导致后续的调用出现崩溃。
结语
通过本文的介绍,你应该对如何在HarmonyOS 5.0中分析CppCrash有了基本的了解。CppCrash分析是提升应用稳定性和用户体验的重要环节,合理利用日志分析和工具检测可以使你的应用更加健壮和易于维护。希望本文能够帮助你在开发过程中更好地分析和处理CppCrash问题。