复杂项目即时通讯从android 5升级android x后遗症之解决报错#1057 SIGABRT #00 pc 0000000000073898-优雅草卓伊凡|bigniu
1057 SIGABRT
00 pc 0000000000073898 /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) 报错的解决方案 Android 异常
引言
基本上从4.0.9版本开始 我们大部分 疑难杂症兼容性问题已经没有了,在bugly后台可以看到所影响机型只有几十种,其次呢还有大部分反馈的问题是由于一个功能切换账号功能导致的,目前切换账号时候退出账号保留了资料如果没有卸载app会和新登录账号产生冲突,当然了其实这个属于一个功能的完善并不属于兼容性,不过我们打算在4.1.0来完善好这个版本,另外在新版本中我们也更新了身份标识和群标识功能,在接下来的9月我们将对本产品进行进一步的迭代和升级,核心还有整体UI改版。

遇到的 SIGABRT
错误是 Android 开发中一个比较常见但也很棘手的崩溃类型。abort+160
表明是系统主动终止应用。
什么是 SIGABRT?
SIGABRT
(Signal Abort) 是一个信号,通常由程序自身调用 abort()
函数触发。在 Android 上,这通常发生在以下情况:
- 原生代码(C/C++) :检测到无法恢复的错误状态(如 double free,堆损坏等)。
- Java 代码 :虽然由 Java 代码引起,但最终是由 Android 运行时(ART)或底层原生代码检测到致命问题并调用
abort
。 - 系统限制:触发了系统的某些保护机制。
常见原因及解决方案
由于你的日志指向 libc.so
的 abort
,这更可能是一个原生代码崩溃。但 Java 层的严重错误也可能最终导致它。我们从最常见的原因开始排查。
1. Java 层导致的 SIGABRT (最常见)
即使错误在 libc.so
,根源也常常在 Java。
- 原因: 未捕获的异常(尤其是在 Native 代码调用的回调中)、主线程阻塞、视图(View)相关错误等,有时会以 SIGABRT 的形式表现出来。
- 排查方法:
-
- 查看 Logcat :这是最关键的一步! 在 Android Studio 的 Logcat 中,不要只过滤崩溃时的日志,要查看 ****
Application
****或 ****No Filters
****下的所有日志 。在崩溃发生之前 ,几乎肯定会有 Java 异常堆栈信息或错误提示。仔细寻找Exception
,Error
,FATAL EXCEPTION
等关键字。
- 查看 Logcat :这是最关键的一步! 在 Android Studio 的 Logcat 中,不要只过滤崩溃时的日志,要查看 ****
-
-
- 示例: 你可能会先看到一个
NullPointerException
,然后才有一大堆原生堆栈信息,最终以 SIGABRT 结束。那么解决那个NPE
就是关键。
- 示例: 你可能会先看到一个
-
-
- 关注主线程:如果主线程被阻塞(如执行耗时网络操作)或发生了异常,系统可能会中止应用。
2. 原生代码(JNI)问题
如果你的应用使用了 JNI 或原生库(.so 文件),这是重点怀疑对象。
- 原因:
-
- JNI 调用错误:在 JNI 中传递了错误的参数(如 NULL 指针)、错误地使用了 JNIEnv(如在错误的线程中使用)、没有检查异常等。
- 内存问题:
-
-
- 堆栈损坏:数组越界、缓冲区溢出。
- Use-after-free:访问已经释放的内存。
- Double-free:多次释放同一块内存。
-
-
- 链接问题:加载了不兼容版本的原生库。
- 排查方法:
-
- 使用 ****
adb logcat
****查看完整日志 :Android Studio 的 Logcat 有时会丢失部分信息。在终端中运行adb logcat > log.txt
,然后在手机上重现崩溃,Ctrl+C
停止命令,查看log.txt
文件。寻找DEBUG
,ADEBUG
或者libc
相关的错误信息,它们通常会提供更详细的崩溃原因(比如Fatal signal 6 (SIGABRT)
之前的日志)。 - 使用 ****
addr2line
****或 ****ndk-stack
:
- 使用 ****
-
-
- 你的日志中应该有一个类似于
#00 pc 0000000000073898 /apex/com.android.runtime/lib64/bionic/libc.so (abort+160)
的堆栈跟踪。但这只是系统代码。你需要寻找来自你自己代码库的.so
文件的堆栈信息(例如/data/app/.../lib/arm64/libmyapp.so
)。 - 将崩溃日志保存到文件(例如
crash.log
)。 - 使用 NDK 提供的
ndk-stack
工具来符号化堆栈信息:
- 你的日志中应该有一个类似于
-
lua
$ANDROID_NDK_HOME/ndk-stack -sym /path/to/your/app/build/intermediates/cmake/debug/obj/arm64-v8a/ -dump crash.log
(请根据你的实际架构路径修改 -sym
参数)
-
-
- 这会将那些难以理解的地址转换成具体的源代码文件和行号,直接告诉你哪一行代码出了问题。
-
-
- 启用 JNI 检查 :在设备的"开发者选项"中,打开 "启用严格模式" 和 "通过JNI检查应用" 。这会让系统更严格地检查 JNI 调用,更容易在早期暴露问题。
3. 其他系统级原因
- 资源耗尽:打开太多文件句柄或线程,超出系统限制。
- 权限问题:尝试访问没有权限的文件或资源。
系统化的解决步骤
- 第一步:全面分析 Logcat
-
- 打开 Android Studio 的 Logcat,清除日志,然后重现崩溃。
- 不要使用过滤器,仔细阅读崩溃前几秒的所有日志(尤其是 Error 级别以上的)。
- 寻找任何明显的 Java 异常或错误信息。
- 第二步:检查是否与 JNI/NDK 相关
-
- 如果你的应用没有明确使用 JNI/NDK,那么问题很大概率是第一步中找到的 Java 异常引起的。
- 如果使用了,按照上面的方法,使用
ndk-stack
工具对原生堆栈进行符号化。
- 第三步:简化与定位
-
- 二分法:如果最近有代码变更,尝试使用二分法回退代码,定位是哪一次提交引入的问题。
- 最小化复现:尝试创建一个能复现问题的最简单例子,移除所有不相关的代码和逻辑。
- 第四步:使用调试工具
-
- 对于原生代码问题,使用 ASan (AddressSanitizer) 来检测内存错误。它在编译时注入代码,可以非常精确地定位到内存越界、use-after-free 等问题。
- 在 Java 端,使用严格的代码检查和测试。
一个简单的例子
假设你在 Logcat 中看到如下信息:
markdown
A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 12345 (MyAppThread), pid 6789 (com.example.myapp)
...
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: ...
...
backtrace:
#00 pc 0000000000073898 /apex/com.android.runtime/lib64/bionic/libc.so (abort+160)
#01 pc 000000000000a1bc /data/app/~~...==/com.example.myapp-.../lib/arm64/libmyjnilib.so (my_buggy_function+123)
#02 pc 000000000000a204 /data/app/~~...==/com.example.myapp-.../lib/arm64/libmyjnilib.so (Java_com_example_myapp_MainActivity_callNativeFunction+7)
解决方案:
- 你发现崩溃来自
libmyjnilib.so
。 - 使用
ndk-stack
工具,传入包含上述 backtrace 的日志文件和你的libmyjnilib.so
的带调试信息的版本(通常在build/intermediates
目录下)。 ndk-stack
会输出类似的结果:my_buggy_function
位于/path/to/your/jni/src/my_file.c:123
。- 你打开
my_file.c
文件的第 123 行,发现了一个数组越界访问的错误,修复它。
总结
步骤 | 操作 |
---|---|
1 | 仔细阅读完整的 Logcat 日志,寻找崩溃前的 Java 异常或错误信息。 |
2 | 如果使用了 JNI/NDK,使用 ndk-stack 工具对原生堆栈进行符号化,定位到源代码。 |
3 | 检查 JNI 调用是否正确(参数、异常处理、线程)。 |
4 | 启用 ASan 等内存调试工具来辅助排查原生内存问题。 |
请提供更多你的 Logcat 信息(尤其是 SIGABRT 发生之前的日志),这样我可以给出更具体、更有针对性的建议。