Android 12下klogd 1.5.0因fdsan触发SIGABRT的解决方案咨询
问题
klogd 1.5.0在Android 9/10运行正常,但在Android 12中崩溃,报错为fdsan检测到尝试关闭被FILE*持有的文件描述符3,触发致命信号。从API 30开始,fdsan默认级别设为FATAL,导致这类fd管理错误直接终止进程。已尝试修改系统fdsan默认级别为WARN_ONCE,但会降低全局fd bug检测能力,不适合作为长期方案。
崩溃日志关键信息:
libc : fdsan: attempted to close file descriptor 3, expected to be unowned, actually owned by FILE* 0x70fde09018 libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 6539 (klogd), pid 6539 (klogd) backtrace: #00 pc 000000000008d6f4 /apex/com.android.runtime/lib64/bionic/libc.so (fdsan_error(char const*, ...)+564) #01 pc 000000000008d3f8 /apex/com.android.runtime/lib64/bionic/libc.so (android_fdsan_close_with_tag+752) #02 pc 000000000008db78 /apex/com.android.runtime/lib64/bionic/libc.so (close+16) #03 pc 00000000000037e0 /vendor/bin/klogd (write_pid+176)
解决方案
1. 根源修复:修正klogd的文件描述符管理逻辑
从崩溃栈可以看出,错误出现在write_pid函数调用close()关闭fd3,但该fd已被FILE*结构体持有。fdsan会跟踪fd的所有权:
- 若通过
fopen()或fdopen()创建了FILE*,fd的所有权会转移给这个FILE*,必须用fclose()来关闭,而不是直接调用close()。 - 直接调用
close()会导致fdsan认为FILE*仍持有该fd,触发所有权冲突错误。
修复步骤:
- 找到klogd源码中
write_pid函数里操作fd3的代码:- 如果是用
fopen打开文件后直接调用close(fileno(fp)),替换为fclose(fp)。 - 示例错误代码:
FILE* pid_fp = fopen("/var/run/klogd.pid", "w"); if (pid_fp != NULL) { fprintf(pid_fp, "%d\n", getpid()); close(fileno(pid_fp)); // 错误:直接关闭fd,未解除FILE*关联 } - 修正后:
FILE* pid_fp = fopen("/var/run/klogd.pid", "w"); if (pid_fp != NULL) { fprintf(pid_fp, "%d\n", getpid()); fclose(pid_fp); // 正确:通过fclose释放FILE*并关闭fd,同步fdsan跟踪信息 }
- 如果是用
- 重新编译klogd并替换
/vendor/bin/klogd,即可解决崩溃问题。
2. 临时过渡方案:单独为klogd进程设置fdsan级别
如果暂时无法修改klogd源码,可以通过环境变量单独降低klogd进程的fdsan错误级别,不影响系统全局的fd检测能力:
- 在启动klogd的脚本或命令前添加环境变量:
ANDROID_FDSAN_ERROR_LEVEL=1 /vendor/bin/klogd - 其中
1对应ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE,只会对该进程触发警告而非致命错误,系统其他进程仍保持FATAL级别的fdsan检测。
内容的提问来源于stack exchange,提问作者Tushar Gopale
相关产品推荐
相关产品推荐

