TextureView throwing fatal signal 11 after resumin

2019-06-22 11:15发布

问题:

I have a TextureView based on Romain Guy's example which can be found here. On Android 4.3 and 4.4, after a few rounds of pausing and resuming the application, the application crashes and the only trace of an error is a fatal signal 11 in LogCat. I created a test application which uses Romain Guy's exact code to see if it was something I had done in my code and Romain's code crashes with the fatal signal 11, too.

I have determined that if I run the code with a Handler instead of a Thread, it does not seem to crash the application. The Handler should be running on the main UI thread (or at least I believe it is), which is perhaps suggesting it is a threading issue.

I have also determined that the crash occurs during a call to canvas.drawX (drawColor, drawBitmap, drawRect, etc...). Locking and unlocking the canvas does not seem to be an issue. I suspect that the thread is being cancelled while some other code is still using the canvas, but I am having a very difficult time tracking the issue due to a lack of any real exceptions being thrown and the crash being fairly inconsistent.

Any insights would be greatly appreciated.

回答1:

When the TextureView loses visibility (either because the screen is rotated, other Activity comes to the front or you press the Home button) it nullifies its SurfaceTexture.OnFrameAvailableListener (on GrepCode). It looks like when this happens and at that very moment the Canvas instance is executing drawX() methods natively on C++ code the app will crash because for some reason the memory containing that canvas is cleared before the method is finished. However, because Canvas.drawX() methods make use of Android native C++ code, C++ doesn't throw a NullPointerException (How to catch the null pointer exception?) and hence the Java exception handling system is in this case useless.

This issue renders unusable the TextureView class as long as you call drawX() methods more than a bunch of times or you draw some complex stuff on the Canvas.

Pretty much like a bug on threading and/or on the C++ code side. I've opened an issue reporting this: https://code.google.com/p/android/issues/detail?id=85380.

EDIT: I've found a reliable way to avoid calling drawX() methods when the TextureView isn't visible any more and hence the app starts crashing: interrupt the thread that is drawing on the Canvas and check before every call to any drawX() method that the thread is interrupted. Prior onPause() is called drawX() methods won't throw any error.

mThread = new Thread() {
    @Override
    public void run() {
        Canvas canvas = mTV.lockCanvas();

        /** Draw your stuff on the canvas but check before every
            single drawX() call whether mThread has been interrupted **/
        Paint p = new Paint();
        p.setColor(Color.RED);
        for (int n=0; n<5000; ++n) {
            if (mThread.isInterrupted())
                break;
            canvas.drawCircle(0, 0, 300, p);
        }
        /** **/

        mTV.unlockCanvasAndPost(canvas);
    };
mThread.start();

And then on onPause() –just the moment before when calling Canvas.drawX() will start to crash the app– interrupt the thread:

@Override
public void onPause() {
    super.onPause();
    if (mThread != null) {
        mThread.interrupt();
        mThread = null;
    }
}

Add also the same code to onStop() and to onDestroy(). I've also tried to use the TextureView.onVisibilityChanged() method by overriding it to interrupt the thread. But this method is invoked almost 500 ms after onPause() is called when it's too late and drawX() calls start to crash the app.



回答2:

I had similar issue and it turned out it was a trivial NullPointerException in my code which somehow caused segmentation fault (signal 11) of the whole process. Apparently exceptions inside SurfaceTextureListener.onSurfaceTextureAvailable() callbacks are not handled correctly. It's probably some JNI issue.

As a dirty workaround you can catch all exceptions from SurfaceTextureListener with

try {
} catch (Throwable t) {
    //do some tear down - better than signal 11
}

I decided not to report the Android bug as I can't reproduce it on 4.4.2 so it probably got fixed.



回答3:

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);