Could not read input channel file descriptors from parce问题分析解决

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abm1993/article/details/80582458

最近项目Monkey测试的时候A应用总是出现如下问题,导致Crash

06-30 11:43:36.160 23438 23438 E InputChannel-JNI: Error 24 dup channel fd 74.
06-30 11:43:36.161 23438 23438 D AndroidRuntime: Shutting down VM
06-30 11:43:36.161 23438 23438 E AndroidRuntime: FATAL EXCEPTION: main
06-30 11:43:36.161 23438 23438 E AndroidRuntime: Process: ****, PID: 23438
06-30 11:43:36.161 23438 23438 E AndroidRuntime: java.lang.RuntimeException: Could not read input channel file descriptors from parcel.
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.InputChannel.nativeReadFromParcel(Native Method)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.InputChannel.readFromParcel(InputChannel.java:148)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.IWindowSession$Stub$Proxy.addToDisplay(IWindowSession.java:804)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.ViewRootImpl.setView(ViewRootImpl.java:773)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.widget.Toast$TN.handleShow(Toast.java:496)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.widget.Toast$TN$1.handleMessage(Toast.java:400)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:164)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6558)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
06-30 11:43:36.161 23438 23438 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:826)
06-30 11:43:36.210  1384  5096 I am_crash: [23438,0,****,954908228,java.lang.RuntimeException,Could not read input channel file descriptors from parcel.,InputChannel.java,-2]

遇到这个问题,咋一看Log相当的糊人,貌似很难解决,我们这里就废话不多说了,直接正常的分析问题思路走起。

从Log中来看我们最终是在调用nativeReadFromParcel方法出了问题,直接定位关键代码

static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
        jobject parcelObj) {
    if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "This object already has a native input channel.");
        return;
    }

    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel) {
        bool isInitialized = parcel->readInt32();
        if (isInitialized) {
            String8 name = parcel->readString8();
            int rawFd = parcel->readFileDescriptor();
            int dupFd = dup(rawFd);
            if (dupFd < 0) {
                ALOGE("Error %d dup channel fd %d.", errno, rawFd);//此处还会打印错误的原因
                jniThrowRuntimeException(env,
                        "Could not read input channel file descriptors from parcel.");
                return;
            }//异常就是从这里抛出的。

            InputChannel* inputChannel = new InputChannel(name, dupFd);
            NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);

            android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
        }
    }
}
定位关键Log,06-30 11:43:36.160 23438 23438 E InputChannel-JNI: Error 24 dup channel fd 74. 24就是整个问题出错的原因,我们可以在系统源码中找到它的定义 ERRNO_VALUE(EMFILE, 24);关于EMFILE相关的解释,可以百度一下,具体可以参考一下文章最后的一个博客链接。我们这里EMFILE 24指的就是我们的应用进程fd泄漏,越过上限值。Android中fd大体指的就是那个epoll,IO多路复用技术,直白点就是进程线程间通信的方式。一般创建带有Looper的线程,创建Window的时候会创建fd,Looper的fd就是为什么Android应用进程执行Looper死循环而不卡死主线程的根本原理所在,Window的fd就是InputChannel通信的fd
查看进程FD上限方法:这里以系统system_server进程为例。adb shell进入手机根目录,cd到system_server进程目录下,ls查看一下。
/proc/916 # ls                                                 
attr      clear_refs      cpuset  fd     make-it-fail mounts     oom_adj       personality sched_group_id       smaps status        wchan 
autogroup cmdline         cwd     fdinfo maps         mountstats oom_score     reclaim     sched_init_task_load stack syscall       
auxv      comm            environ io     mem          net        oom_score_adj root        sched_wake_up_idle   stat  task          
cgroup    coredump_filter exe     limits mountinfo    ns         pagemap       sched       schedstat            statm timerslack_ns    
主需要关注fd和limits,先cat limits
/proc/916 # cat limits                                               
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             21911                21911                processes 
Max open files            1024                 4096                 files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       21911                21911                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         40                   40                   
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us
实际测试证明这个1024就是系统对当前进程fd打开数量的限制。
cd到fd目录,执行ls -l | wc -l,查看进程创建了多少fd
/proc/916/fd # ls -l | wc -l                            
372//这里就是当前进程fd创建的数量

我们知道问题可能发生的原因之后,又知道应用创建Window和Looper会创建fd,那我们就得去定位自己的代码了,不断的检查应用的代码,我们发现问题应用存在Activity leak,而泄漏的Activity中又使用了HandlerThread,并且还会不停的Toast.show。最终优化完代码之后,monkey测试问题应用48小时,该问题不再复现。

这里只是介绍了最终是由于Toast.show,系统申请fd失败,应用crash的原因,而实际开发中如果我们不当的使用HandlerThread,或者自定义带有looper的线程时(没有调用Looper.quit),也会造成fd泄漏,具体的错误如下

looper fd泄漏
05-31 07:32:38.634 12175 12175 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
05-31 07:32:38.634 12175 12175 F DEBUG   : Build fingerprint: ********************
05-31 07:32:38.634 12175 12175 F DEBUG   : Revision: '0'
05-31 07:32:38.634 12175 12175 F DEBUG   : ABI: 'arm64'
05-31 07:32:38.635 12175 12175 F DEBUG   : pid: 11288, tid: 12172, name: 481 HandlerThre  >>> com.example.procfdtest <<<
05-31 07:32:38.635 12175 12175 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
05-31 07:32:38.648 12175 12175 F DEBUG   : Abort message: 'Could not create epoll instance: Too many open files'
05-31 07:32:38.648 12175 12175 F DEBUG   :     x0   0000000000000000  x1   0000000000002f8c  x2   0000000000000006  x3   0000000000000008
05-31 07:32:38.648 12175 12175 F DEBUG   :     x4   0000000000000000  x5   0000000000000000  x6   0000000000000000  x7   7f7f7f7f7f7f7f7f
05-31 07:32:38.649 12175 12175 F DEBUG   :     x8   0000000000000083  x9   8aa80fbb5b3cecfd  x10  0000000000000000  x11  0000000000000001
05-31 07:32:38.649 12175 12175 F DEBUG   :     x12  ffffffffffffffff  x13  ffffffffffffffff  x14  ff00000000000000  x15  ffffffffffffffff
05-31 07:32:38.649 12175 12175 F DEBUG   :     x16  0000002196029fa8  x17  000000438adf684c  x18  0000000000000008  x19  0000000000002c18
05-31 07:32:38.650 12175 12175 F DEBUG   :     x20  0000000000002f8c  x21  0000000000000001  x22  00000042cf373588  x23  00000042cf373588
05-31 07:32:38.650 12175 12175 F DEBUG   :     x24  0000000000000008  x25  00000042cf373588  x26  00000042da2cbca0  x27  0000000000000002
05-31 07:32:38.650 12175 12175 F DEBUG   :     x28  0000000000000001  x29  00000042cf372030  x30  000000438adac0ac
05-31 07:32:38.651 12175 12175 F DEBUG   :     sp   00000042cf371ff0  pc   000000438adac0c8  pstate 0000000060000000
05-31 07:32:38.912 12175 12175 F DEBUG   : 
05-31 07:32:38.912 12175 12175 F DEBUG   : backtrace:
05-31 07:32:38.912 12175 12175 F DEBUG   :     #00 pc 000000000001e0c8  /system/lib64/libc.so (abort+104)
05-31 07:32:38.913 12175 12175 F DEBUG   :     #01 pc 0000000000007f10  /system/lib64/liblog.so (__android_log_assert+304)
05-31 07:32:38.913 12175 12175 F DEBUG   :     #02 pc 00000000000156a8  /system/lib64/libutils.so (android::Looper::rebuildEpollLocked()+348)
05-31 07:32:38.913 12175 12175 F DEBUG   :     #03 pc 0000000000015508  /system/lib64/libutils.so (android::Looper::Looper(bool)+236)
05-31 07:32:38.913 12175 12175 F DEBUG   :     #04 pc 000000000011094c  /system/lib64/libandroid_runtime.so (android::NativeMessageQueue::NativeMessageQueue()+160)
05-31 07:32:38.914 12175 12175 F DEBUG   :     #05 pc 000000000011127c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativeInit(_JNIEnv*, _jclass*)+28)
05-31 07:32:38.914 12175 12175 F DEBUG   :     #06 pc 000000000062d420  /system/framework/arm64/boot-framework.oat (offset 0x62d000) (android.os.Binder.clearCallingIdentity [DEDUPED]+144)
05-31 07:32:38.914 12175 12175 F DEBUG   :     #07 pc 0000000000003690  /dev/ashmem/dalvik-jit-code-cache (deleted)

总结一句话,合理的规范的去写自己的代码,避免错误的发生。

参考:
https://blog.csdn.net/sdn_prc/article/details/28661661

猜你喜欢

转载自blog.csdn.net/abm1993/article/details/80582458
今日推荐