monkey测试有如下FATAL log
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'LeEco/X7_CN/le_x7:6.0/KGXCNFN5902011171S/1479358948:userdebug/test-keys'
Revision: '0'
ABI: 'arm'
pid: 32138, tid: 32144, name: JDWP >>> com.letv.bbs <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE'
backtrace:
#00 pc 00041c7c /system/lib/libc.so (tgkill+12)
#01 pc 00040e79 /system/lib/libc.so (pthread_kill+32)
#02 pc 0001c7ef /system/lib/libc.so (raise+10)
#03 pc 000199bd /system/lib/libc.so (__libc_android_abort+34)
#04 pc 00017570 /system/lib/libc.so (abort+4)
#05 pc 0001b405 /system/lib/libc.so (__libc_fatal+16)
#06 pc 0001b41b /system/lib/libc.so (__fortify_chk_fail+18)
#07 pc 00046fd1 /system/lib/libc.so (__FD_SET_chk+24)
#08 pc 003e7bb3 /system/lib/libart.so (_ZN3art4JDWP12JdwpAdbState15ProcessIncomingEv+162)
#09 pc 0025adab /system/lib/libart.so (_ZN3art4JDWP9JdwpState3RunEv+298)
#10 pc 0025bc17 /system/lib/libart.so (_ZN3art4JDWPL15StartJdwpThreadEPv+10)
#11 pc 0004077b /system/lib/libc.so (_ZL15__pthread_startPv+30)
#12 pc 0001a041 /system/lib/libc.so (__start_thread+6)
从log上看有abort原因是:Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE'
但这是什么意思?
从 backtrace:看 #12开启线程, #00线程被kill了。上面abort的原因就是kill的原因。
既然有Abort message提示原因,又不知道这个信息在哪里打印的,只好在Android所有源码搜索(相当耗时,几个小时)。
最终搜到在bionic/libc/bionic/__FD_chk.cpp搜到 如下:
59 extern "C" void __FD_SET_chk(int fd, fd_set* set, size_t set_size) {
60 if (__predict_false(fd < 0)) {
61 __fortify_chk_fail("FD_SET: file descriptor < 0", 0);
62 }
63 if (__predict_false(fd >= FD_SETSIZE)) {
64 __fortify_chk_fail("FD_SET: file descriptor >= FD_SETSIZE", 0);
65 }
66 if (__predict_false(set_size < sizeof(fd_set))) {
67 __fortify_chk_fail("FD_SET: set is too small", 0);
68 }
69 FD_SET(fd, set); //这里的FD_SET 是 70 #define FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
因为这时的(__BIONIC_FORTIFY)定义已经取消定义了
70 }
bionic/libc/include/sys/select.h 中定义了FD_SETSIZE = 1024 和FD_SET
39 #define FD_SETSIZE 1024
60 extern void __FD_CLR_chk(int, fd_set*, size_t);
61 extern void __FD_SET_chk(int, fd_set*, size_t);
62 extern int __FD_ISSET_chk(int, fd_set*, size_t);
63
64 #if defined(__BIONIC_FORTIFY)
65 #define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
66 #define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
67 #define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
68 #else
69 #define FD_CLR(fd, set) (__FDS_BITS(set)[__FDELT(fd)] &= ~__FDMASK(fd))
70 #define FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
71 #define FD_ISSET(fd, set) ((__FDS_BITS(set)[__FDELT(fd)] & __FDMASK(fd)) != 0)
72 #endif /* defined(__BIONIC_FORTIFY) */
上面代码通过(__BIONIC_FORTIFY)宏动态的切换了FD_SET执行路径。
分析到这里发现整个实现,实际是select的实现,在使用select时,abort并提示了原因。
从backtrace的#07 #12看是libc.so调用libart.so再调用ProcessIncoming函数调用FD_SET了。
对应代码:
art/runtime/jdwp/jdwp_adb.cc
297 bool JdwpAdbState::ProcessIncoming() {
314 fd = control_sock_;
315 if (fd >= 0) {
316 FD_SET(fd, &readfds);
317 if (maxfd < fd) {
318 maxfd = fd;
319 }
320 }
321 fd = clientSock;
322 if (fd >= 0) {
323 FD_SET(fd, &readfds);
324 if (maxfd < fd) {
325 maxfd = fd;
326 }
327 }
328 fd = wake_pipe_[0];
329 if (fd >= 0) {
330 FD_SET(fd, &readfds);
331 if (maxfd < fd) {
332 maxfd = fd;
333 }
334 }
从#12到#00可以看到处是,创建线程没法再创建了,因数量超过了文件句柄最大值FD_SETSIZE。
简单说就是,应用app开启线程之类的太多了,没有复用。需要重新检查app中的线程使用。
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'LeEco/X7_CN/le_x7:6.0/KGXCNFN5902011171S/1479358948:userdebug/test-keys'
Revision: '0'
ABI: 'arm'
pid: 32138, tid: 32144, name: JDWP >>> com.letv.bbs <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE'
backtrace:
#00 pc 00041c7c /system/lib/libc.so (tgkill+12)
#01 pc 00040e79 /system/lib/libc.so (pthread_kill+32)
#02 pc 0001c7ef /system/lib/libc.so (raise+10)
#03 pc 000199bd /system/lib/libc.so (__libc_android_abort+34)
#04 pc 00017570 /system/lib/libc.so (abort+4)
#05 pc 0001b405 /system/lib/libc.so (__libc_fatal+16)
#06 pc 0001b41b /system/lib/libc.so (__fortify_chk_fail+18)
#07 pc 00046fd1 /system/lib/libc.so (__FD_SET_chk+24)
#08 pc 003e7bb3 /system/lib/libart.so (_ZN3art4JDWP12JdwpAdbState15ProcessIncomingEv+162)
#09 pc 0025adab /system/lib/libart.so (_ZN3art4JDWP9JdwpState3RunEv+298)
#10 pc 0025bc17 /system/lib/libart.so (_ZN3art4JDWPL15StartJdwpThreadEPv+10)
#11 pc 0004077b /system/lib/libc.so (_ZL15__pthread_startPv+30)
#12 pc 0001a041 /system/lib/libc.so (__start_thread+6)
从log上看有abort原因是:Abort message: 'FORTIFY: FD_SET: file descriptor >= FD_SETSIZE'
但这是什么意思?
从 backtrace:看 #12开启线程, #00线程被kill了。上面abort的原因就是kill的原因。
既然有Abort message提示原因,又不知道这个信息在哪里打印的,只好在Android所有源码搜索(相当耗时,几个小时)。
最终搜到在bionic/libc/bionic/__FD_chk.cpp搜到 如下:
59 extern "C" void __FD_SET_chk(int fd, fd_set* set, size_t set_size) {
60 if (__predict_false(fd < 0)) {
61 __fortify_chk_fail("FD_SET: file descriptor < 0", 0);
62 }
63 if (__predict_false(fd >= FD_SETSIZE)) {
64 __fortify_chk_fail("FD_SET: file descriptor >= FD_SETSIZE", 0);
65 }
66 if (__predict_false(set_size < sizeof(fd_set))) {
67 __fortify_chk_fail("FD_SET: set is too small", 0);
68 }
69 FD_SET(fd, set); //这里的FD_SET 是 70 #define FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
因为这时的(__BIONIC_FORTIFY)定义已经取消定义了
70 }
bionic/libc/include/sys/select.h 中定义了FD_SETSIZE = 1024 和FD_SET
39 #define FD_SETSIZE 1024
60 extern void __FD_CLR_chk(int, fd_set*, size_t);
61 extern void __FD_SET_chk(int, fd_set*, size_t);
62 extern int __FD_ISSET_chk(int, fd_set*, size_t);
63
64 #if defined(__BIONIC_FORTIFY)
65 #define FD_CLR(fd, set) __FD_CLR_chk(fd, set, __bos(set))
66 #define FD_SET(fd, set) __FD_SET_chk(fd, set, __bos(set))
67 #define FD_ISSET(fd, set) __FD_ISSET_chk(fd, set, __bos(set))
68 #else
69 #define FD_CLR(fd, set) (__FDS_BITS(set)[__FDELT(fd)] &= ~__FDMASK(fd))
70 #define FD_SET(fd, set) (__FDS_BITS(set)[__FDELT(fd)] |= __FDMASK(fd))
71 #define FD_ISSET(fd, set) ((__FDS_BITS(set)[__FDELT(fd)] & __FDMASK(fd)) != 0)
72 #endif /* defined(__BIONIC_FORTIFY) */
上面代码通过(__BIONIC_FORTIFY)宏动态的切换了FD_SET执行路径。
分析到这里发现整个实现,实际是select的实现,在使用select时,abort并提示了原因。
从backtrace的#07 #12看是libc.so调用libart.so再调用ProcessIncoming函数调用FD_SET了。
对应代码:
art/runtime/jdwp/jdwp_adb.cc
297 bool JdwpAdbState::ProcessIncoming() {
314 fd = control_sock_;
315 if (fd >= 0) {
316 FD_SET(fd, &readfds);
317 if (maxfd < fd) {
318 maxfd = fd;
319 }
320 }
321 fd = clientSock;
322 if (fd >= 0) {
323 FD_SET(fd, &readfds);
324 if (maxfd < fd) {
325 maxfd = fd;
326 }
327 }
328 fd = wake_pipe_[0];
329 if (fd >= 0) {
330 FD_SET(fd, &readfds);
331 if (maxfd < fd) {
332 maxfd = fd;
333 }
334 }
从#12到#00可以看到处是,创建线程没法再创建了,因数量超过了文件句柄最大值FD_SETSIZE。
简单说就是,应用app开启线程之类的太多了,没有复用。需要重新检查app中的线程使用。