问题描述 客户反馈话机的voipsdk demo在运行起来之后 放置不动,几小时过后,应用进行任何操作都会崩溃。 通过logcat 报错信息 发现出现了句柄泄露。通过ls -l /proc//fd 可以查看到在demo进程下,持有的socket数量会规律性上升。
1 2 3 4 5 lrwx------ system system 2018-03-08 14:11 60 -> socket:[4027431] lrwx------ system system 2018-03-08 14:11 61 -> socket:[4025517] lrwx------ system system 2018-03-08 14:11 62 -> socket:[4028038] lrwx------ system system 2018-03-08 14:11 63 -> socket:[4028322] lrwx------ system system 2018-03-08 14:11 64 -> socket:[4026799]
大概十秒增加一个,一直到超出安卓规定的数量,此时由于已无可用fd句柄,在进行任何操作都会因无可用句柄直接导致崩溃。
可以看到新增socket的inode号码之后,通过查找/proc/net/tcp(udp对应/proc/net/udp)文件,其中也列出了相应socket的inode号,通过比对此字段,我在/proc/net/tcp下获得此套接口的其他信息,对应的<本地地址:端口号,远端地址:端口号>对,窗口大小,状态等信息。具体字段含义详见net/ipv4/tcp_ipv4.c 中的 tcp4_seq_show 函数。cat /proc/net/tcp 如下:
1 2 3 4 5 6 7 8 root@TOS_IP:/proc/net # cat tcp6 sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode 0: 0000000000000000FFFF00007665A8C0:D483 0000000000000000FFFF00009F173379:0050 08 00000000:00000001 00:00000000 00000000 10077 0 3660979 1 00000000 25 4 30 10 -1 1: 0000000000000000FFFF00007665A8C0:E595 0000000000000000FFFF0000DCD5B276:0050 08 00000000:00000001 00:00000000 00000000 10077 0 3661419 1 00000000 24 4 28 10 -1 2: 0000000000000000FFFF00007665A8C0:81EC 0000000000000000FFFF00009F173379:0050 08 00000000:00000001 00:00000000 00000000 1000 0 4019721 1 00000000 23 4 30 10 -1 3: 0000000000000000FFFF00007665A8C0:B885 0000000000000000FFFF0000F28D0D6F:0050 08 00000000:00000001 00:00000000 00000000 1000 0 3659952 1 00000000 26 4 30 10 -1 4: 0000000000000000FFFF00007665A8C0:8AD0 0000000000000000FFFF00009F173379:0050 08 00000000:00000001 00:00000000 00000000 1000 0 4018811 1 00000000 24 4 30 10 -1 5: 0000000000000000FFFF00007665A8C0:E83C 0000000000000000FFFF00009F173379:0050 08 00000000:00000001 00:00000000 00000000 1000 0 4018828 1 00000000 23 4 30 10 -1
将本端16进制端口号转化为10进制可以看到 是一个与8080端口在通信的socket。
目前初步猜测是端口争夺导致demo没有获取到端口,就会隔段时间重试去申请该端口。
首先去java端排除,全局搜索发现并没有找到对应的8080端口申请情况
那就只有可能是linphone库里或者webrtc库里做了8080相关的操作了。
请linphone端的李工排查,发现在一段前离职同事的代码里,有一段申请8080端口的相关操作。查看了一下,发现和猜测的一致,因为要和底层通讯,同事使用了socket并通过8080端口,但是在申请资源后并未释放改socket,当系统自带的拨号服务起来之后,因为系统自带拨号和sdk的demo使用的linphone库是相同的,导致两个进程都在抢占8080,那个进程服务先拿到,另一个进程就拿不到该端口,会隔10s重新发起申请,但是之前创建的socket又没有释放,就会导致句柄泄露。
我将系统自带的拨号进程彻底杀死,同事运行起demo,然后再将系统拨号运行起来,发现这时候 系统自带拨号也出现了句柄泄露。而demo就没有出现过了。
应征我之前的猜测。解决这个问题就很简单了,在linphone的代码里将改socket释放。