[Android] 记一次FileDescriptor泄漏造成的Crash

记一次FileDescriptor泄漏造成的Crash

问题描述

最近项目中一直偶现Native Crash,先看下log。

09-29 10:46:47.530 24328-24328/? A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 24328 (com.bw.pk) 
09-29 10:46:47.533 448-448/? I/MIUINDBG_HOOK: hook hook_sigtimedwait 
09-29 10:46:47.696 25962-25962/? A/DEBUG: * * 
Build fingerprint: 'xiaomi/mido/mido:7.0/NRD90M/V9.0.5.0.NCFCNEI:user/release-keys' 
Revision: '0' 
ABI: 'arm' 
pid: 24328, tid: 24328, name: com.bw.pk >>> com.bw.pk <<< 
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- 
09-29 10:46:47.714 25962-25962/? A/DEBUG: Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE' 
r0 00000000 r1 00005f08 r2 00000006 r3 00000008 
r4 edb7c590 r5 00000006 r6 edb7c538 r7 0000010c 
r8 00000002 r9 0003555b sl ffa627e0 fp 00000002 
ip 0000000b sp ffa62520 lr ecef42b7 pc ecef6b38 cpsr 000e0010 
09-29 10:46:47.727 25962-25962/? A/DEBUG: backtrace: 
09-29 10:46:47.729 25962-25962/? A/DEBUG: #00 pc 00049b38 /system/lib/libc.so (tgkill+12) 
#01 pc 000472b3 /system/lib/libc.so (pthread_kill+34) 
#02 pc 0001d555 /system/lib/libc.so (raise+10) 
#03 pc 000190a1 /system/lib/libc.so (__libc_android_abort+34) 
#04 pc 00017104 /system/lib/libc.so (abort+4) 
#05 pc 0001b54f /system/lib/libc.so (__libc_fatal+22) 
#06 pc 0001b52f /system/lib/libc.so (__fortify_chk_fail+26) 
#07 pc 0004f44f /system/lib/libc.so (__FD_SET_chk+70) 
#08 pc 00000bdf /system/vendor/lib/libqti-perfd-client.so (mpctl_send+378) 
#09 pc 00000a25 /system/vendor/lib/libqti-perfd-client.so (perf_lock_acq+32) 
#10 pc 00000c57 /system/vendor/lib/libqti_performance.so 
#11 pc 000045dd /system/framework/oat/arm/QPerformance.odex (offset 0x4000)

分析

大概看了下,是libc.so抛出的,再仔细看,可以发现此问题的关键。

 Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE' 

文件描述符(fd)超过上限,文件描述符上限这个在不同系统中有不同的定义,在Android设备上是1024个。

可以通过这个命令进行查看:
ulimit用于限制启动进程所占用的资源,使用-n可以查看每个进程可以打开的最大fd。

adb shell ulimit -n

这个问题就相当的棘手了,先简单介绍下UNIX系统中的文件描述符。

UNIX系统中,所有文件是通过文件描述符进行引用的,它通常是一个非负整数,标识一个进程正在进行访问文件。

下面我们查看当前进程的fd使用情况。
首先找到pid

ps | grep <包名>

查看进程fd占用

cd /proc/<pid>/fd
# 计算进程的fd占用情况
ls -l | wc -l

ls-l查看所有已占用的fd资源

统计总的占用情况

表示当前进程一共占用了153个fd。

解决

随后逐渐定位问题,发现一些场景,如列表滑动,会造成fd一直增长,没有释放。

经过排查,问题出现在OkHttp的连接没有关闭。应该这样改正。

我们看下OkHttp源码,为什么Response不Close会造成泄漏。

如果ResponseBody不进行close的话最终会导致SteamAllocation中的streamFinished没有调用,导致Socket没有关闭。

总结

file,socket,pipe之类的fd资源需要及时关闭,否则会引起Native层的Crash,并且问题极难排查。

通过/proc/<pid>/fd/目录下的文件,查看fd的占用情况。

参考资料:
https://github.com/square/okhttp/issues/2232
https://gist.github.com/jhansche/322965fa3c3a6179114bc3ac8e4337ec#file-watch-fds-sh
https://stackoverflow.com/questions/30521826/fortify-source-fd-set-file-descriptor-fd-setsize-calling-abort

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值