5

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.

Kaleb
  • 1,855
  • 1
  • 18
  • 24

3 Answers3

2

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.

Community
  • 1
  • 1
AxeEffect
  • 6,345
  • 4
  • 37
  • 33
  • stopping and preventing the draw calls at onPause actually worked for me! a good temporary solution to this weird bug. hopefully they will fix it soon. – doomsdaymachine Jun 06 '15 at 00:02
  • Can't you just `Thread.join()` the renderer thread in `onPause()`? That should ensure that it has stopped executing before TextureView starts cleaning stuff up. `interrupt()` is not synchronous; it just sets a flag and kicks the other thread out of `wait()`. If the renderer thread is continuing to execute after `onPause()` returns, that's an app bug, not a framework issue. – fadden Jun 19 '15 at 16:22
0

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.

Iwo Banas
  • 892
  • 8
  • 12
  • 1
    I came back to this today and I can confirm the issue still exists on 4.4.4, although it seems more difficult to reproduce. I have put try/catch statements around every method call I make, I still can't seem to catch the error. My error is SIGSEGV = segmentation fault in native code, so that probably explains why no exceptions are being thrown. – Kaleb Jul 10 '14 at 15:36
-1

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

Hemang
  • 7
  • 5
  • This, unfortunately, did not fix the issue. – Kaleb Jul 10 '14 at 15:38
  • This answer would be much more useful with an explanation of what it was trying to accomplish and why it helped. My best guess is that this would change the odds of a race condition being hit, which doesn't really solve the problem. – fadden Jun 19 '15 at 16:25
  • this is completely not related to issue – Yevgen Kulik Feb 22 '17 at 17:36