这是一个耗时一个多月才解决的native crash(2)

1,104 阅读22分钟

一、背景

1、长久以来,线上长期出现关于socket native crash的闪退(此类型大部分是后台闪退,没有用户反馈使用app的过程中出现闪退)

内容如下:

Thread-1504(24253)

SIGSEGV(SEGV_MAPERR)
解析原始
1
#00 pc 00000000000b396c /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.xx.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
2
#01 pc 00000000000b3980 /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.linxxgan.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
3
#02 pc 00000000000b3a10 /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.linxxgan.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
4
#03 pc 00000000000b2d30 /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.x.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
5
#04 pc 00000000000b20e4 /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.xx.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
6
#05 pc 000000000006bd04 /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.xx.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
7
#06 pc 00000000000745cc /data/app/~~mSyo_ZlnL5Gr3SuMGGseVA==/com.xx.seeyou-LAWMFJQ7xddipfrQ6MVimw==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
8
#07 pc 00000000000eb828 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) [arm64-v8a::5f57d25b37c043ed36c0e4147dcc8b3f]
9
#08 pc 000000000008ba48 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) [arm64-v8a::5f57d25b37c043ed36c0e4147dcc8b3f]
10
java:
11
[Failed to get Java stack]

由于大部分都是后台闪退,不影响用户使用,原因可能是系统后台回收导致,因此在854版本以前,长期以来,我们使用bugly 对socket的libclientsdk.so库的闪退进行的屏蔽,以方便整体闪退率的统计;

2、然而,在854版本上线后,出现了以下的前台闪退,用于的反馈是:”一打开就闪退“或者”每次都要打开好几次才能进入app“

内容如下:

SIGABRT
解析原始
1
#00 pc 000000000007066c /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
2
#01 pc 00000000000babec /apex/com.android.runtime/lib64/bionic/libc.so (__stack_chk_fail+20) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
3
#02 pc 0000000000067d5c /data/app/com.zz.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
4
#03 pc 0000000000067e4c /data/app/com.xx.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
5
#04 pc 000000000006cb78 /data/app/com.xx.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
6
#05 pc 000000000007310c /data/app/com.xx.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
7
#06 pc 000000000006cf18 /data/app/com.xx.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
8
#07 pc 00000000000745b8 /data/app/com.xx.seeyou-6mpLTCQW-oI4eWYYjRA5EQ==/lib/arm64/libclientsdk.so [arm64-v8a::de63b5e1d2007ebbad9c3e7b9001d192]
9
#08 pc 00000000000cf7c0 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
10
#09 pc 00000000000721a8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]

通过之前的文章:juejin.cn/spost/72886…

我们解决了因为升级bugly sdk 导致 app启动后 概率性的 在未进入首页后立刻出现crash的问题;

主要原因是,新版bugly 废弃了屏蔽功能,并且启动app的时候会偶发性的触发某个回调,造成KillProcess。

在855临近封包的一两天,我们的解决方案是:去除屏蔽socket libclientsdk.so库的闪退,去除bugly的回调,禁止调用KillProcess。

最后我们在复盘后了遗留了2个问题和1个待办:

2个问题是:

    1、socket的crash 是如何发生的,没有定位到;

    2、socket的闪退类型是:SIGABRT,而不是SIGSEGV,也就是说,从后台闪退,变成了前台闪退,但是很久以来,Socket库本身没有更新,也没有找造成socket闪退对应的原因;

1个待办是:

   1、提升定位native crash的能力

3、随着855版本,依然出现了2的闪退,只是从用户反馈的情况上看,现象变成了:" 进入首页后,才发生的闪退 "

二、排查过程

1、通过学习,我们先掌握了排查socket native crash的以下技能

  • 熟练掌握addr2line工具的使用

  • 了解了不同ndk打包出的so的pc堆栈可能是不一样的;比如线上的socket so库是ndk r10e打包的,新版我们采用ndk r22打包;

  • 通过不断的阅读socket库的源码,逐步熟悉了整个库要如何编译,如何运行,以及编译的产物,以及一些编译属性的影响;

2、排查思路

  • 不论是业务引发的闪退,还是socket库本身的闪退,一切以闪退日志为源头开始排查,不采取 ”通过需求检查或者代码review的方式进行排查“,这种方式找到概率性闪退根源的概率微乎其微;

  • 我们打算通过重新编译 socket debug so库,让测试通过压测等手段,尝试复现出闪退;

  • 通过addr2line命令,查找到闪退的代码行;

  • 根据查找到的代码行,找到解决方案;

1、历史so库版本的追溯,确认追溯方案

     经过一翻追溯,我们发现线上版本的so库,是2020-1-20打包的,历史太悠久,当时打包的时候,并没有保留对应的debug.so库(新版本已经规范化,保留全部产物),因此无法使用add2line工具找到对应的代码行;

并且我们尝试过通过追溯聊天记录,使用ndk r10e重新编译2020年的代码,但是也匹配不上,这种方式可能无法追溯了,主要是因为就算追溯到了,也不敢保证追溯的代码行数是对的,可能会造成方向误导;

所以我们还是决定,重新编译so库;

我们先编译了个一个debug.so库,并手动构造了一个native crash,内容如下,主要用于确认debug.so库闪退的时候,是可以直接看到堆栈和函数的:

Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x9c in tid 30316 (example.meetyou), pid 30272 (example.meetyou)
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Softversion: PD2020C_A_7.10.11
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Time: 2023-04-07 15:16:59
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Build fingerprint: 'vivo/PD2020/PD2020:10/QP1A.190711.020/compiler02071532:user/release-keys'
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Revision: '0'
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  ABI: 'arm64'
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Timestamp: 2023-04-07 15:16:59+0800
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  pid: 30272, tid: 30316, name: example.meetyou  >>> com.example.meetyou <<<
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  uid: 10220
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x9c
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A  Cause: null pointer dereference
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x0  00000000000000a0  x1  00000070c804e5e0  x2  00000070c8000000  x3  0000000000000009
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x4  000000000000004e  x5  ffffffffffff8000  x6  27650615173e0000  x7  0080ffffffffffff
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x8  000000000000009c  x9  ab47f973a0173289  x10 00000000000000e1  x11 0000000000000094
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x12 0000000000000008  x13 ffffffffffffffff  x14 ffffffffffff0000  x15 ffffffffffffffff
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x16 0000007156b2e768  x17 0000007156b226bc  x18 0000007064fba000  x19 0000000000000093
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x20 00000070c804e5e0  x21 00000000000000a0  x22 00000070b8e112b0  x23 0000007068965020
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x24 0000007068964d50  x25 0000007068964d50  x26 0000007068965020  x27 000000715a8ba020
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      x28 0000007feeda38b0  x29 0000007068964cf0
2023-04-07 15:16:59.288 30320-30320 DEBUG                   crash_dump64                         A      sp  00000070689643c0  lr  0000007065fa5d90  pc  0000007065fa5d94
2023-04-07 15:16:59.296 30320-30320 DEBUG                   crash_dump64                         A  
backtrace:
2023-04-07 15:16:59.296 30320-30320 DEBUG                   crash_dump64                         A        #00 pc 00000000000e4d94  /data/app/com.example.meetyou-OAuno40ZMifLuMg-8Oq6NQ==/lib/arm64/libclientsdk.so (meet_you::ClientCore::workThreadProcess(meet_you::ClientCore*)+356) (BuildId: 7e94cedda384a753b36878824c12c0b46777c51c)
2023-04-07 15:16:59.296 30320-30320 DEBUG                   crash_dump64                         A        #01 pc 00000000000d6ed8  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) (BuildId: bd43e969ad4563b25263b9efb013f03d)
2023-04-07 15:16:59.296 30320-30320 DEBUG                   crash_dump64                         A        #02 pc 0000000000075314  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId:

我们使用add42line工具追溯堆栈里的pc地址:00000000000e4d94,是可以追溯到代码行数的;

2、压测和复现:全员使用和压力随机测试

      我们重新基于最新代码,打出debug.so库,然后集成到app中,进行全员使用和测试压测,经过2天之后,得到了第一个socket相关的前台闪退日志:

内容:https://bugly.qq.com/v2/crash-reporting/crashes/5dd058bf61/3804092?pid=1

Thread-1742(30261)

SIGABRT
解析原始
1
#00 pc 000000000007066c /apex/com.android.runtime/lib64/bionic/libc.so (abort+160) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
2
#01 pc 0000000000095bc8 /apex/com.android.runtime/lib64/bionic/libc.so (__fortify_fatal(char const*, ...)+116) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
3
#02 pc 0000000000095aec /apex/com.android.runtime/lib64/bionic/libc.so (__FD_SET_chk+120) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
4
#03 pc 00000000000df674 /data/app/com.xx.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (connect_with_timeout(int, sockaddr*, int, int)+208) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
5
#04 pc 00000000000df9ac /data/app/com.xx.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (tcp_connect_pauto+200) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
6
#05 pc 00000000000e5cf8 /data/app/com.xx.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (meet_you::ClientCore::connectServer(std::__ndk1::basic_string<char, std::__ndk1::char_traits, std::__ndk1::allocator > const&, int)+644) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
7
#06 pc 00000000000e6bb4 /data/app/com.linxxgan.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (meet_you::ClientCore::doConnectAndLogin()+24) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
8
#07 pc 00000000000e3e08 /data/app/com.linxxgan.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (meet_you::ClientCore::processOps()+252) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
9
#08 pc 00000000000e2fd8 /data/app/com.xx.seeyou-_pCHGvFn0zUma3cREezdWg==/lib/arm64/libclientsdk.so (meet_you::ClientCore::workThreadProcess(meet_you::ClientCore*)+440) [arm64-v8a::7f6592185f64ad19edaba7a457e66128]
10
#09 pc 00000000000cf7c0 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
11
#10 pc 00000000000721a8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]
12
java:
13
[Failed to get Java stack]

3、分析日志

       从以上日志看,可以很清楚的看到,闪退是在这一行出现的connect_with_timeout(int, sockaddr*, int, int)+208) [arm64-v8a::7f6592185f64ad19edaba7a457e66128];

但是这个还不够具体,于是我们采用addr2line工具继续追踪:

[ice@icedeMacBook-Pro bin]$ ./aarch64-linux-android-addr2line -f -e /Users/ice/MeiyouCode/imsdk/app/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/libclientsdk.so 00000000000df674

_Z20connect_with_timeoutiP8sockaddrii

/Users/ice/MeiyouCode/imsdk/app/src/main/jni/common/ef_sock.cpp:46

我们发现这行代码如下:

image.png

通过网上的一些资料查询,怀疑出现闪退的原因可能如下:

在Linux内核中,select所用到的FD_SET是有限的,即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数
一般定义为 1024个, 定义在/usr/include/sys/select.h或<bits/types.h>中
你会发现sizeof(fd_set)的结果是128(*8 = FD_SETSIZE=1024).

Select用到了fd_set结构,从man page里可以知道fd_set能容纳的句柄和FD_SETSIZE相
关。实际上fd_set在*nix下是一个bit标志数组,每个bit表示对应下标的fd是不是在
fd_set中。fd_set只能容纳编号小于 FD_SETSIZE的那些句柄。

FD_SETSIZE默认是1024,如果向fd_set里放入过大的句柄,宏FD_SET会引起fd_set数组越界以后程序就会垮
掉。系统默认限制了一个进程最大的句柄号不超过1024,但是可以通过ulimit -n命令
/setrlimit函数来扩大这一限制。如果不幸一个程序在FD_SETSIZE=1024的环境下编
译,运行时又遇到ulimit –n > 1024的,那就只有祈求上帝保佑不会垮掉了。

过大的句柄导致crash的解决方案有2种:

1)在程序的一个头文件中重新定义__FD_SETSIZE为一个大值(如32768), 并且保证这个头文件被每个cpp或头文件第一个包含.

如:
#include <bits/types.h>
#ifdef __FD_SETSIZE
#undef __FD_SETSIZE
#endif

#define __FD_SETSIZE 32768

2)采用poll或其他IO模型来代替select

4、尝试复现:

****从上一步的分析和网络资料查找,我们知道Socket 里的select框架里的FD_SET引起的;也就是说:App启动到首页后,出现了大量的fd被打开了,造成fd数量超过1024个,最终造成socket native crash;

于是我们使用 以下代码:(尝试申请大量的fd,但是不进行关闭),可以稳定的复现出socket FD_SET的闪退;

private void testFD(){
for(int i=0;i<=1025;i++){
String fileName = i + "temp";
File file = new File(getCacheDir(), fileName);
Log.i("testFD","testFD index:"+i);
FileOutputStream out = null;
try {
file.createNewFile();
out = new FileOutputStream(file);
} catch(Exception e) {
} /final {
if(out != null){
out.close();
}
}
/
}
}

或者C++的

        for(int i=0; i< 1025; i++) {
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SDK_LOG(LOG_LEVEL_TRACE, " workThreadProcess socket %d", fd);

        }

5、解决方案:

****我们针对socket库里可能出现FD_SET的地方进行的校验,如果超过1024,就中断select流程,避免用户闪退;

第一个修复版本打出后,已经无法再压测出闪退了,我们认为已经解决,但无法验证使我们感到不安,于是我们找到了一个反馈的用户,让她帮忙安装我们的修复包,安装后重启,发现依然会闪退,因此我们得到了第二个日志:

bugly.qq.com/v2/crash-re…

通过add2line我们追踪到了另外一个FD_SET的方法:

[ice@icedeMacBook-Pro bin]$ ./aarch64-linux-android-addr2line -f -e /Users/ice/Downloads/v1.0.0/debug/arm64-v8a/libclientsdk.so 00000000001198e0

ZN8meet_you10ClientCore17workThreadProcessEPS0

/Users/meetyou/meetyou/im-group/im-sdk/jniwks/MeetYou/jni/client_sdk/client_core.cpp:202

然后再次生成正式包,给了闪退的用户进行验证,用户反馈:问题已得到修复;

6、事情尚未结束,有几个疑惑还需要解答:

  • socket libclientsdk.so库明明已经两年没有更新,为何会无故躺枪出现FD_SET crash?

****- socket 实现网络框架采用select框架,受限fd最大为1024,当app使用的fd没超过1024的时候,不会有问题,当超过了之后,就会立刻触发闪退;

           - 是哪个业务启动app后,超限制使用了fd,这个我们暂时还没定位到,fd的问题需要进一步研究和治理

  • 一个设备只能打开1024个fd吗?

****- 我们通过此命令 adb shell ulimit -n 可以查询 某个设备可以打开的fd数量,一般是32768个,目前只有select框架才会收到1024 fd的限制;

  • 如何查询某个app使用的fd情况(以app为例子),通过观察,包含系统的fd,一般情况是在300-800之间

           - adb shell ps | grep 'com.xx.seeyou' 获取pid

           - adb shell run-as com.xx.seeyou ls -l /proc/6230/fd > 2.txt,其中6230为pid  可以查看当前打开的fd有哪些;

           - adb shell ps -T | grep 17285 其中17285是进程ID 此命令可以查看某进程的线程情况

           - 在查询和测试的过程中,发现1024并不是以此命令行查出的数量为主,比如我开1025个java file会crash,但是我开10000个腾讯mmkv的fd,却不会crash

           - 关于Android fd泄漏的文章:blog.csdn.net/ws601348077…

  • 为何线上闪退的堆栈和我们复现的堆栈有一点点不一样

我们复现的闪退日志,以及用户使用新版打包的so库复现的闪退日志是:

02 pc 0000000000095aec /apex/com.android.runtime/lib64/bionic/libc.so (__FD_SET_chk+120) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]

而线上的闪退日志是:

#01 pc 00000000000babec /apex/com.android.runtime/lib64/bionic/libc.so (__stack_chk_fail+20) [arm64-v8a::b91c775ccc9b0556e91bc575a2511cd0]

          这个问题目前还没有得到解答。

          我们重新研究了一下__stack_chk_fail发生的原理,大概是这样的:

 数组越界写入,导致 canary值被修改。在函数退出时检查canary,发现canary被修改,函数不能安全返回,call到__stack_chk_fail函数,abort当前线程

也就是说,大概率是启动socket的时候出现了数据越界的情况

由于从代码层面排查数组溢出方向太广,如大海捞针,所以还是从追溯日志开始;

我们通过反编译线上so库,找到libsclientsdk.so的md5,然后追溯到当时打包的源码位置:

然后切换到此分支,用r10c 的ndk,在application.mk加入APP_STRIP_MODE := none,然后需要进行重新编译出新的so库,用于匹配线上的堆栈代码;

这个编译有点复杂,最终是采用r10c成功编译debug so库,然后使用r10c的ndk addr2line对线上pc堆栈做了追踪:

[ice@icedeMacBook-Pro bin]$ ./aarch64-linux-android-addr2line -f -e  /Users/ice/MeiyouCode/im-sdk/jniwks/MeetYou/obj/local/arm64-v8a/libclientsdk.so 00000000000babec

Java_com_rtc_RTCClient_getDT

/Users/ice/MeiyouCode/im-sdk/jniwks/MeetYou/jni/android/com_rtc_RTCClient.cpp:254 (discriminator 2)

这个方法是每个接口请求的时候,会调用此方法获取一个加密字符串,设置给头部参数”elder“,传给服务端,以前的”动态授权头功能“;

深入看了一下这个方法,会使用sprintf方法进行内容赋值,而这个方法经过查阅有栈溢出的风险,blog.csdn.net/qq_39864882…

由于启动时候,接口大量请求,并且是多线程,可能造成溢出,然后出现闪退;

但是我们通过开启500个线程,每个线程循环调用getDT,并无法复现出此种场景的闪退;经过多方沟通,发现elder参数已经无用,于是在客户端进行移除。

  • 回过头来 思考一下854关于bugly的闪退问题是如何发生的?

通过855闪退的一系列分析和解决,854版本发生bugly sdk闪退的原因逐步清晰了起来,用户的场景应该是这样的:

1、用户升级或者安装 854版本后,因为某些场景App使用fd超过了1024,导致socket发生闪退;

2、因为安全整改的需要,bugly sdk升级到最新的版本,此时,bugly 过滤socket 功能已失效,然后将 socket crash捕获,然后在用户重新启动app后,bugly sdk 偶然性的触发crash回调,造成killprocess,这就是有些用户”一打开app还没到首页就闪退“的原因

3、当我们解决了bugly sdk的问题后,用户的闪退变成了进入到首页过一会后才闪退,这是因为socket的初始化,是在进首页之后,当socket开启线程后,某种场景概率性的触发FD>1024的限制,然后就出现socke natvie crash;

6、临时解决方案

在创建Socket 是如果返回fd >1024,则不让连接通道创建。避免fd_set 超过 FD_SETSIZE 超时应用退出情况。弊端im和站内信将无法使用,根治需要确认app 大量文件描述符未关闭问题

7、后续待推进事项:

  • 排查App使用fd过多的场景以及治理方案确认和执行
  • 完善Socket测试用例;
  • Socket库废弃select方案,改为epoll方案,因为app其实是用可能使用fd超过1024的。
  • 为何线上闪退的堆栈和我们复现的堆栈有一点点不一样?这是因为FD_SET是ndk的,不同版本的ndk实现源码不一致;

8、最终结论:

 1、经过856版本5w用户的灰度,已经确认Socket前台闪退已修复,还有一个后台socket闪退堆栈已抓到,已发给xx定位;
2、闪退直接原因:用户使用app fd数量超过1024,触发socket select框架的限制,然后闪退;
3、为什么从854和855版本开始发生:我们通过抓去用户超过本地fd的文件情况发现,大部分用户使用都在1024以下,小部分在1100左右,有发现一个在1600左右,
通过分析,触发时机基本都是在启动后 图片上传引起的:图片上传开启多线程并发,以及操作数据库,OSS上传等,均会使用较多fd,所以辣妈身份的概率会大一些;
从854和855开始主要原因归结为:因为业务使用fd增量以及855版本开启了多线程上传,导致fd的使用在某一瞬间突破临界值;

后续方案:
1、全局治理fd
2、由于无法精确控制app整体fd不能超过1024(业务+第三方,系统通讯等),现在设备基本可开放的fd都是3w多,若要兼容这部分用户的IM功能正常稳定,建议socket后续采用epoll方案实践,废弃select方案;