Merge "Fix ImageReader onImageAvailable synchronization" into klp-dev

This commit is contained in:
Jesse Hall
2013-09-18 03:32:17 +00:00
committed by Android (Google) Code Review

View File

@@ -20,6 +20,7 @@ import android.graphics.ImageFormat;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message;
import android.view.Surface; import android.view.Surface;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@@ -377,17 +378,21 @@ public class ImageReader implements AutoCloseable {
* @throws IllegalArgumentException * @throws IllegalArgumentException
* If no handler specified and the calling thread has no looper. * If no handler specified and the calling thread has no looper.
*/ */
public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) { public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
mImageListener = listener; synchronized (mListenerLock) {
if (listener != null) {
Looper looper; Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
mHandler = handler; if (looper == null) {
if (listener != null && mHandler == null) { throw new IllegalArgumentException(
if ((looper = Looper.myLooper()) != null) { "handler is null but the current thread is not a looper");
mHandler = new Handler(); }
if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
mListenerHandler = new ListenerHandler(looper);
}
mListener = listener;
} else { } else {
throw new IllegalArgumentException( mListener = null;
"Looper doesn't exist in the calling thread"); mListenerHandler = null;
} }
} }
} }
@@ -426,6 +431,7 @@ public class ImageReader implements AutoCloseable {
*/ */
@Override @Override
public void close() { public void close() {
setOnImageAvailableListener(null, null);
nativeClose(); nativeClose();
} }
@@ -474,6 +480,9 @@ public class ImageReader implements AutoCloseable {
/** /**
* Called from Native code when an Event happens. * Called from Native code when an Event happens.
*
* This may be called from an arbitrary Binder thread, so access to the ImageReader must be
* synchronized appropriately.
*/ */
private static void postEventFromNative(Object selfRef) { private static void postEventFromNative(Object selfRef) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -483,16 +492,16 @@ public class ImageReader implements AutoCloseable {
return; return;
} }
if (ir.mHandler != null && ir.mImageListener != null) { final Handler handler;
ir.mHandler.post(new Runnable() { synchronized (ir.mListenerLock) {
@Override handler = ir.mListenerHandler;
public void run() { }
ir.mImageListener.onImageAvailable(ir); if (handler != null) {
} handler.sendEmptyMessage(0);
});
} }
} }
private final int mWidth; private final int mWidth;
private final int mHeight; private final int mHeight;
private final int mFormat; private final int mFormat;
@@ -500,14 +509,35 @@ public class ImageReader implements AutoCloseable {
private final int mNumPlanes; private final int mNumPlanes;
private final Surface mSurface; private final Surface mSurface;
private Handler mHandler; private final Object mListenerLock = new Object();
private OnImageAvailableListener mImageListener; private OnImageAvailableListener mListener;
private ListenerHandler mListenerHandler;
/** /**
* This field is used by native code, do not access or modify. * This field is used by native code, do not access or modify.
*/ */
private long mNativeContext; private long mNativeContext;
/**
* This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
*/
private final class ListenerHandler extends Handler {
public ListenerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
OnImageAvailableListener listener;
synchronized (mListenerLock) {
listener = mListener;
}
if (listener != null) {
listener.onImageAvailable(ImageReader.this);
}
}
}
private class SurfaceImage extends android.media.Image { private class SurfaceImage extends android.media.Image {
public SurfaceImage() { public SurfaceImage() {
mIsImageValid = false; mIsImageValid = false;