Android记录Could not read input channel file descriptors from parcel导致App奔溃/卡死.

目录

 

背景:

卡死/黑屏log信息,原因分析:


背景:

一个盘点扫描的APP,可以离线在线操作,运行平台为PDA,客户在使用过程中反馈经过多次扫描后会出现屏幕卡死/黑屏的情况,但是PDA系统可以正常使用,由此可见是我的APP导致的。客户一次盘点会盘点近千个物品,也就是说会扫描近千次,扫描过程中会有人声提示音播放。收到了客户的反馈后,拿了设备回来自己测,通过几回合的连续扫描后,复现出了这个问题,每回合都是扫到237次就出现黑屏或者报错。拿到了出现问题的log信息,但是一看logcat,很难确定原因,不是常规的代码崩溃。以下看下我拿到的logcat信息

卡死/黑屏log信息,原因分析:

08-25 18:18:58.028 17875-17875/com.pda.wph E/Surface: dequeueBuffer failed (Invalid argument)
08-25 18:18:58.038 17875-17875/com.pda.wph E/ViewRootImpl: Could not lock surface
                                                           java.lang.IllegalArgumentException
                                                               at android.view.Surface.nativeLockCanvas(Native Method)
                                                               at android.view.Surface.lockCanvas(Surface.java:236)
                                                               at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2495)
                                                               at android.view.ViewRootImpl.draw(ViewRootImpl.java:2469)
                                                               at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2313)
                                                               at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1946)
                                                               at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1078)
                                                               at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5887)
                                                               at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
                                                               at android.view.Choreographer.doCallbacks(Choreographer.java:562)
                                                               at android.view.Choreographer.doFrame(Choreographer.java:532)
                                                               at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
                                                               at android.os.Handler.handleCallback(Handler.java:730)
                                                               at android.os.Handler.dispatchMessage(Handler.java:92)
                                                               at android.os.Looper.loop(Looper.java:137)
                                                               at android.app.ActivityThread.main(ActivityThread.java:5136)
                                                               at java.lang.reflect.Method.invokeNative(Native Method)
                                                               at java.lang.reflect.Method.invoke(Method.java:525)
                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                                                               at dalvik.system.NativeStart.main(Native Method)
08-26 11:05:56.994 3741-3741/com.pda.wph E/InputChannel-JNI: Error 24 dup channel fd 1011.
08-26 11:05:57.004 3741-3741/com.pda.wph D/AndroidRuntime: Shutting down VM
08-26 11:05:57.004 3741-3741/com.pda.wph W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41b5a898)
08-26 11:05:57.004 3741-3741/com.pda.wph E/AndroidRuntime: FATAL EXCEPTION: main
                                                           java.lang.RuntimeException: Could not read input channel file descriptors from parcel.
                                                               at android.view.InputChannel.nativeReadFromParcel(Native Method)
                                                               at android.view.InputChannel.readFromParcel(InputChannel.java:148)
                                                               at android.view.IWindowSession$Stub$Proxy.addToDisplay(IWindowSession.java:690)
                                                               at android.view.ViewRootImpl.setView(ViewRootImpl.java:595)
                                                               at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:269)
                                                               at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
                                                               at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2857)
                                                               at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2269)
                                                               at android.app.ActivityThread.access$600(ActivityThread.java:144)
                                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1259)
                                                               at android.os.Handler.dispatchMessage(Handler.java:99)
                                                               at android.os.Looper.loop(Looper.java:137)
                                                               at android.app.ActivityThread.main(ActivityThread.java:5136)
                                                               at java.lang.reflect.Method.invokeNative(Native Method)
                                                               at java.lang.reflect.Method.invoke(Method.java:525)
                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                                                               at dalvik.system.NativeStart.main(Native Method)

从上面的logcat日志看 很难定位到问题发生的所在位置,所以也是耗费我大量的时间去网上搜寻答案。但是基本可以排除掉的是第一部分的logcat原因,我的APP中并没有使用过surfaceview之类的控件,所以这个可能是由其他报错影响导致。

这个时候,我们就重点看第二个报错信息Could not read input channel file descriptors from parcel

通过百度得到了一些信息,可能导致出现这个报错的几个原因

  • RemoteView中添加的图片太大了,超过40K会报这个异常(PS:排除,项目中没有用到这个)
  • Intent传递的数据太大了超过1M也会报这个错误(PS:排除)
  • FileDescripter太多而且没有关闭,looper太多没有quit。
  • 试试在AndroidManefest.xml中对当前Activity配置 (PS:项目中是强制竖屏)
    configchange=“orientation|keyboardHidden”强制在Activity横竖屏切换的时候不重新onCreate。

通过排除最终定位到了FileDescripter太多而且没有关闭这个可疑的原因,这个是什么东西,我也不知道,只能再百度下。

可以参考https://www.jianshu.com/p/e3830e7be8b2

可以知道这个是句柄泄露照成的,一个进程拥有的最大句柄数一般是1024,一旦超过这个值,该进程就会出现句柄泄露,进而引发一些报错情况。

在linux中一个文件、一个串口、一个socket、一个线程都可以是一个文件,而一个文件会占用一个句柄,linux中一个进程默认的句柄最大数值是1024,当超过这个数值,linux就会对当前的进程进行kill,而kill的对象可以是任意对象,所以会造成各种异常原因的崩溃。

这句资料参考至:http://www.cnblogs.com/dongweiq/p/9494033.html

好了 又要排除原因了,

项目中没有用到socket,排除;

项目中有sqlite数据库备份还原操作,涉及到文件流操作,检查后都有close,排除;

项目中没有较多以及导致死循环的线程,排除;

排除后又陷入了迷茫当中,到底还有什么会导致句柄泄露。

经过一段时间的分析后,关于文件的操作还有一个地方,播放人声提示音,这里播放提示音是使用SoundPool去实现的,在一次扫描中会播放两个提示音,经过237次的扫描,也就是播放了484的提示音,SoundPool的load方法生成一个AssetFileDescriptor对象,可能是没有关闭进而导致句柄超过了1024泄露了,

参考至https://www.cnblogs.com/l2rf/p/6051169.html。

所以 针对SoundPool做下修改

以下是我自己修改后的工具类

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.SoundPool;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;


/**
 *
 * 声音播放类
 * Created by ZYB on 2017/7/21 0021.
 */

public class SoundPoolUtil {


    private static SoundPoolUtil soundPoolUtil;
    private static SoundPool soundPool;
    private static List FileDescriptors ;

    private SoundPoolUtil(){

        FileDescriptors = new ArrayList<>();
        soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 100);
    }

    /**
     * 单例模式
     * @return
     */
    public static SoundPoolUtil newInstance()
    {
        if (soundPoolUtil == null) {
            soundPoolUtil = new SoundPoolUtil();
        }
        //清除soundpool资源,防止加载超过300次后没声音
        if (soundPool != null)
        {
            soundPool.release();
            soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 100);
        }
        return soundPoolUtil;

    }

    /**
     * 播放声音
     * @param resid 资源id
     * @param context   上下文对象
     */
    public  void playSoundPool(int resid, Context context)
    {

        try {

            AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
            final int soundid = soundPool.load(afd,1);
            FileDescriptors.add(afd);
            soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
                @Override
                public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                    soundPool.play(soundid,1,1,0,0,1f);
                    Log.w("sound_play", soundid +"");
                    soundPool.unload(soundid);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //释放FD资源,防止出现句柄超过1024泄露
    public void releaseFileDescriptor()
    {
        for (AssetFileDescriptor item : FileDescriptors)
        {
            try {
                //释放FileDescriptor句柄
                item.close();
                item = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //清空列表
        FileDescriptors.clear();
    }
}

在使用SoundPool的Activity中的onDestory方法调用SoundPool.newInstance().releaseFileDescriptor()。

修改后经过一轮测试,连续扫描1000多次也不会出现屏幕卡死/黑屏的问题了,问题解决。

多亏以下这些博客 我才解决了这个繁琐的问题:

https://www.cnblogs.com/l2rf/p/6051169.html

http://www.cnblogs.com/dongweiq/p/9494033.html

https://www.jianshu.com/p/e3830e7be8b2

 

你可能感兴趣的:(android)