Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c8e788e authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Fix crash due to texture view callback threading invariants."

parents a9095ba4 c7282e57
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -10734,6 +10734,7 @@ package android.graphics {
    method public void releaseTexImage();
    method public void releaseTexImage();
    method public void setDefaultBufferSize(int, int);
    method public void setDefaultBufferSize(int, int);
    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener, android.os.Handler);
    method public void updateTexImage();
    method public void updateTexImage();
  }
  }
+11 −19
Original line number Original line Diff line number Diff line
@@ -23,7 +23,6 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.SurfaceTexture;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Log;


@@ -119,8 +118,6 @@ public class TextureView extends View {
    private boolean mUpdateLayer;
    private boolean mUpdateLayer;
    private boolean mUpdateSurface;
    private boolean mUpdateSurface;


    private SurfaceTexture.OnFrameAvailableListener mUpdateListener;

    private Canvas mCanvas;
    private Canvas mCanvas;
    private int mSaveCount;
    private int mSaveCount;


@@ -370,21 +367,7 @@ public class TextureView extends View {
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
            nCreateNativeWindow(mSurface);
            nCreateNativeWindow(mSurface);


            mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
            mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
                @Override
                public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                    // Per SurfaceTexture's documentation, the callback may be invoked
                    // from an arbitrary thread
                    updateLayer();

                    if (Looper.myLooper() == Looper.getMainLooper()) {
                        invalidate();
                    } else {
                        postInvalidate();
                    }
                }
            };
            mSurface.setOnFrameAvailableListener(mUpdateListener);


            if (mListener != null && !mUpdateSurface) {
            if (mListener != null && !mUpdateSurface) {
                mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
                mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
@@ -422,7 +405,7 @@ public class TextureView extends View {
            // To cancel updates, the easiest thing to do is simply to remove the
            // To cancel updates, the easiest thing to do is simply to remove the
            // updates listener
            // updates listener
            if (visibility == VISIBLE) {
            if (visibility == VISIBLE) {
                mSurface.setOnFrameAvailableListener(mUpdateListener);
                mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
                updateLayerAndInvalidate();
                updateLayerAndInvalidate();
            } else {
            } else {
                mSurface.setOnFrameAvailableListener(null);
                mSurface.setOnFrameAvailableListener(null);
@@ -767,6 +750,15 @@ public class TextureView extends View {
        mListener = listener;
        mListener = listener;
    }
    }


    private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
            new SurfaceTexture.OnFrameAvailableListener() {
        @Override
        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
            updateLayer();
            invalidate();
        }
    };

    /**
    /**
     * This listener can be used to be notified when the surface texture
     * This listener can be used to be notified when the surface texture
     * associated with this texture view is available.
     * associated with this texture view is available.
+2 −2
Original line number Original line Diff line number Diff line
@@ -221,7 +221,7 @@ static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
    }
    }


    fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
    fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
            "(Ljava/lang/Object;)V");
            "(Ljava/lang/ref/WeakReference;)V");
    if (fields.postEvent == NULL) {
    if (fields.postEvent == NULL) {
        ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
        ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
    }
    }
@@ -338,7 +338,7 @@ static void SurfaceTexture_release(JNIEnv* env, jobject thiz)


static JNINativeMethod gSurfaceTextureMethods[] = {
static JNINativeMethod gSurfaceTextureMethods[] = {
    {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
    {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
    {"nativeInit",                 "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init },
    {"nativeInit",                 "(IZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
    {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
    {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
    {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
    {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
    {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
    {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
+58 −47
Original line number Original line Diff line number Diff line
@@ -62,9 +62,8 @@ import android.view.Surface;
 * #updateTexImage} should not be called directly from the callback.
 * #updateTexImage} should not be called directly from the callback.
 */
 */
public class SurfaceTexture {
public class SurfaceTexture {

    private final Looper mCreatorLooper;
    private EventHandler mEventHandler;
    private Handler mOnFrameAvailableHandler;
    private OnFrameAvailableListener mOnFrameAvailableListener;


    /**
    /**
     * These fields are used by native code, do not access or modify.
     * These fields are used by native code, do not access or modify.
@@ -83,7 +82,8 @@ public class SurfaceTexture {
    /**
    /**
     * Exception thrown when a SurfaceTexture couldn't be created or resized.
     * Exception thrown when a SurfaceTexture couldn't be created or resized.
     *
     *
     * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
     * @deprecated No longer thrown. {@link android.view.Surface.OutOfResourcesException}
     * is used instead.
     */
     */
    @SuppressWarnings("serial")
    @SuppressWarnings("serial")
    @Deprecated
    @Deprecated
@@ -100,10 +100,10 @@ public class SurfaceTexture {
     *
     *
     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
     *
     *
     * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
     * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
     */
     */
    public SurfaceTexture(int texName) {
    public SurfaceTexture(int texName) {
        init(texName, false);
        this(texName, false);
    }
    }


    /**
    /**
@@ -121,20 +121,58 @@ public class SurfaceTexture {
     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
     * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
     * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
     * @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
     *
     *
     * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
     * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
     */
     */
    public SurfaceTexture(int texName, boolean singleBufferMode) {
    public SurfaceTexture(int texName, boolean singleBufferMode) {
        init(texName, singleBufferMode);
        mCreatorLooper = Looper.myLooper();
        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    }
    }


    /**
    /**
     * Register a callback to be invoked when a new image frame becomes available to the
     * Register a callback to be invoked when a new image frame becomes available to the
     * SurfaceTexture.  Note that this callback may be called on an arbitrary thread, so it is not
     * SurfaceTexture.
     * <p>
     * This callback may be called on an arbitrary thread, so it is not
     * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
     * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
     * thread invoking the callback.
     * thread invoking the callback.
     * </p>
     *
     * @param listener The listener to set.
     */
    public void setOnFrameAvailableListener(OnFrameAvailableListener listener) {
        setOnFrameAvailableListener(listener, null);
    }

    /**
     * Register a callback to be invoked when a new image frame becomes available to the
     * SurfaceTexture.
     * <p>
     * If no handler is specified, then this callback may be called on an arbitrary thread,
     * so it is not safe to call {@link #updateTexImage} without first binding the OpenGL ES
     * context to the thread invoking the callback.
     * </p>
     *
     * @param listener The listener to set.
     * @param handler The handler on which the listener should be invoked, or null
     * to use an arbitrary thread.
     */
     */
    public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
    public void setOnFrameAvailableListener(final OnFrameAvailableListener listener,
        mOnFrameAvailableListener = l;
            Handler handler) {
        if (listener != null) {
            // Although we claim the thread is arbitrary, earlier implementation would
            // prefer to send the callback on the creating looper or the main looper
            // so we preserve this behavior here.
            Looper looper = handler != null ? handler.getLooper() :
                    mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
            mOnFrameAvailableHandler = new Handler(looper, null, true /*async*/) {
                @Override
                public void handleMessage(Message msg) {
                    listener.onFrameAvailable(SurfaceTexture.this);
                }
            };
        } else {
            mOnFrameAvailableHandler = null;
        }
    }
    }


    /**
    /**
@@ -285,49 +323,22 @@ public class SurfaceTexture {
        }
        }
    }
    }


    private class EventHandler extends Handler {
        public EventHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mOnFrameAvailableListener != null) {
                mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
            }
        }
    }

    /**
    /**
     * This method is invoked from native code only.
     * This method is invoked from native code only.
     */
     */
    @SuppressWarnings({"UnusedDeclaration"})
    @SuppressWarnings({"UnusedDeclaration"})
    private static void postEventFromNative(Object selfRef) {
    private static void postEventFromNative(WeakReference<SurfaceTexture> weakSelf) {
        WeakReference weakSelf = (WeakReference)selfRef;
        SurfaceTexture st = weakSelf.get();
        SurfaceTexture st = (SurfaceTexture)weakSelf.get();
        if (st != null) {
        if (st == null) {
            Handler handler = st.mOnFrameAvailableHandler;
            return;
            if (handler != null) {
        }
                handler.sendEmptyMessage(0);

        if (st.mEventHandler != null) {
            Message m = st.mEventHandler.obtainMessage();
            st.mEventHandler.sendMessage(m);
            }
            }
        }
        }

    private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(looper);
        } else {
            mEventHandler = null;
        }
        nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
    }
    }


    private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
    private native void nativeInit(int texName, boolean singleBufferMode,
            WeakReference<SurfaceTexture> weakSelf)
            throws Surface.OutOfResourcesException;
            throws Surface.OutOfResourcesException;
    private native void nativeFinalize();
    private native void nativeFinalize();
    private native void nativeGetTransformMatrix(float[] mtx);
    private native void nativeGetTransformMatrix(float[] mtx);