Loading media/java/android/media/ImageReader.java +42 −20 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.StampedLock; /** * <p>The ImageReader class allows direct application access to image data Loading Loading @@ -675,7 +676,8 @@ public class ImageReader implements AutoCloseable { * If no handler specified and the calling thread has no looper. */ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) { synchronized (mListenerLock) { long writeStamp = mListenerLock.writeLock(); try { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper == null) { Loading @@ -691,6 +693,8 @@ public class ImageReader implements AutoCloseable { mListenerExecutor = null; } mListener = listener; } finally { mListenerLock.unlockWrite(writeStamp); } } Loading @@ -713,9 +717,12 @@ public class ImageReader implements AutoCloseable { throw new IllegalArgumentException("executor must not be null"); } synchronized (mListenerLock) { long writeStamp = mListenerLock.writeLock(); try { mListenerExecutor = executor; mListener = listener; } finally { mListenerLock.unlockWrite(writeStamp); } } Loading @@ -731,6 +738,8 @@ public class ImageReader implements AutoCloseable { /** * Callback that is called when a new image is available from ImageReader. * * This callback must not modify or close the passed {@code reader}. * * @param reader the ImageReader the callback is associated with. * @see ImageReader * @see Image Loading Loading @@ -889,28 +898,41 @@ public class ImageReader implements AutoCloseable { return; } synchronized (ir.mCloseLock) { if (!ir.mIsReaderValid) { // It's dangerous to fire onImageAvailable() callback when the ImageReader // is being closed, as application could acquire next image in the // onImageAvailable() callback. return; } } final Executor executor; final OnImageAvailableListener listener; synchronized (ir.mListenerLock) { final long readStamp = ir.mListenerLock.readLock(); try { executor = ir.mListenerExecutor; listener = ir.mListener; if (executor == null) { return; } final boolean isReaderValid; synchronized (ir.mCloseLock) { isReaderValid = ir.mIsReaderValid; } finally { ir.mListenerLock.unlockRead(readStamp); } // It's dangerous to fire onImageAvailable() callback when the ImageReader // is being closed, as application could acquire next image in the // onImageAvailable() callback. if (executor != null && listener != null && isReaderValid) { executor.execute(new Runnable() { @Override public void run() { listener.onImageAvailable(ir); executor.execute(() -> { // Acquire readlock to ensure that the ImageReader does not change its // state while a listener is actively processing. final long rStamp = ir.mListenerLock.readLock(); try { // Fire onImageAvailable of the latest non-null listener // This ensures that if the listener changes while messages are in queue, the // in-flight messages will call onImageAvailable of the new listener instead if (ir.mListener != null) { ir.mListener.onImageAvailable(ir); } }); } finally { ir.mListenerLock.unlockRead(rStamp); } }); } /** Loading Loading @@ -1070,7 +1092,7 @@ public class ImageReader implements AutoCloseable { private Surface mSurface; private int mEstimatedNativeAllocBytes; private final Object mListenerLock = new Object(); private final StampedLock mListenerLock = new StampedLock(); private final Object mCloseLock = new Object(); private boolean mIsReaderValid = false; private OnImageAvailableListener mListener; Loading Loading
media/java/android/media/ImageReader.java +42 −20 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.StampedLock; /** * <p>The ImageReader class allows direct application access to image data Loading Loading @@ -675,7 +676,8 @@ public class ImageReader implements AutoCloseable { * If no handler specified and the calling thread has no looper. */ public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) { synchronized (mListenerLock) { long writeStamp = mListenerLock.writeLock(); try { if (listener != null) { Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); if (looper == null) { Loading @@ -691,6 +693,8 @@ public class ImageReader implements AutoCloseable { mListenerExecutor = null; } mListener = listener; } finally { mListenerLock.unlockWrite(writeStamp); } } Loading @@ -713,9 +717,12 @@ public class ImageReader implements AutoCloseable { throw new IllegalArgumentException("executor must not be null"); } synchronized (mListenerLock) { long writeStamp = mListenerLock.writeLock(); try { mListenerExecutor = executor; mListener = listener; } finally { mListenerLock.unlockWrite(writeStamp); } } Loading @@ -731,6 +738,8 @@ public class ImageReader implements AutoCloseable { /** * Callback that is called when a new image is available from ImageReader. * * This callback must not modify or close the passed {@code reader}. * * @param reader the ImageReader the callback is associated with. * @see ImageReader * @see Image Loading Loading @@ -889,28 +898,41 @@ public class ImageReader implements AutoCloseable { return; } synchronized (ir.mCloseLock) { if (!ir.mIsReaderValid) { // It's dangerous to fire onImageAvailable() callback when the ImageReader // is being closed, as application could acquire next image in the // onImageAvailable() callback. return; } } final Executor executor; final OnImageAvailableListener listener; synchronized (ir.mListenerLock) { final long readStamp = ir.mListenerLock.readLock(); try { executor = ir.mListenerExecutor; listener = ir.mListener; if (executor == null) { return; } final boolean isReaderValid; synchronized (ir.mCloseLock) { isReaderValid = ir.mIsReaderValid; } finally { ir.mListenerLock.unlockRead(readStamp); } // It's dangerous to fire onImageAvailable() callback when the ImageReader // is being closed, as application could acquire next image in the // onImageAvailable() callback. if (executor != null && listener != null && isReaderValid) { executor.execute(new Runnable() { @Override public void run() { listener.onImageAvailable(ir); executor.execute(() -> { // Acquire readlock to ensure that the ImageReader does not change its // state while a listener is actively processing. final long rStamp = ir.mListenerLock.readLock(); try { // Fire onImageAvailable of the latest non-null listener // This ensures that if the listener changes while messages are in queue, the // in-flight messages will call onImageAvailable of the new listener instead if (ir.mListener != null) { ir.mListener.onImageAvailable(ir); } }); } finally { ir.mListenerLock.unlockRead(rStamp); } }); } /** Loading Loading @@ -1070,7 +1092,7 @@ public class ImageReader implements AutoCloseable { private Surface mSurface; private int mEstimatedNativeAllocBytes; private final Object mListenerLock = new Object(); private final StampedLock mListenerLock = new StampedLock(); private final Object mCloseLock = new Object(); private boolean mIsReaderValid = false; private OnImageAvailableListener mListener; Loading