diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index c23bd5bcee472..b10c341eb5ec7 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -286,23 +286,29 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession } @Override - public synchronized void abortCaptures() throws CameraAccessException { - checkNotClosed(); + public void abortCaptures() throws CameraAccessException { + synchronized (this) { + checkNotClosed(); - if (DEBUG) { - Log.v(TAG, mIdString + "abortCaptures"); + if (DEBUG) { + Log.v(TAG, mIdString + "abortCaptures"); + } + + if (mAborting) { + Log.w(TAG, mIdString + "abortCaptures - Session is already aborting; doing nothing"); + return; + } + + mAborting = true; + mAbortDrainer.taskStarted(); } - if (mAborting) { - Log.w(TAG, mIdString + "abortCaptures - Session is already aborting; doing nothing"); - return; + synchronized (mDeviceImpl.mInterfaceLock) { + synchronized (this) { + mDeviceImpl.flush(); + // The next BUSY -> IDLE set of transitions will mark the end of the abort. + } } - - mAborting = true; - mAbortDrainer.taskStarted(); - - mDeviceImpl.flush(); - // The next BUSY -> IDLE set of transitions will mark the end of the abort. } @Override @@ -330,78 +336,86 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession * @see CameraCaptureSession#close */ @Override - public synchronized void replaceSessionClose() { - /* - * In order for creating new sessions to be fast, the new session should be created - * before the old session is closed. - * - * Otherwise the old session will always unconfigure if there is no new session to - * replace it. - * - * Unconfiguring could add hundreds of milliseconds of delay. We could race and attempt - * to skip unconfigure if a new session is created before the captures are all drained, - * but this would introduce nondeterministic behavior. - */ + public void replaceSessionClose() { + synchronized (this) { + /* + * In order for creating new sessions to be fast, the new session should be created + * before the old session is closed. + * + * Otherwise the old session will always unconfigure if there is no new session to + * replace it. + * + * Unconfiguring could add hundreds of milliseconds of delay. We could race and attempt + * to skip unconfigure if a new session is created before the captures are all drained, + * but this would introduce nondeterministic behavior. + */ - if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose"); - - // Set up fast shutdown. Possible alternative paths: - // - This session is active, so close() below starts the shutdown drain - // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener. - // - This session is already closed and has executed the idle drain listener, and - // configureOutputsChecked(null) has already been called. - // - // Do not call configureOutputsChecked(null) going forward, since it would race with the - // configuration for the new session. If it was already called, then we don't care, since it - // won't get called again. - mSkipUnconfigure = true; + if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose"); + // Set up fast shutdown. Possible alternative paths: + // - This session is active, so close() below starts the shutdown drain + // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener. + // - This session is already closed and has executed the idle drain listener, and + // configureOutputsChecked(null) has already been called. + // + // Do not call configureOutputsChecked(null) going forward, since it would race with the + // configuration for the new session. If it was already called, then we don't care, + // since it won't get called again. + mSkipUnconfigure = true; + } close(); } @Override - public synchronized void close() { + public void close() { + synchronized (this) { + if (mClosed) { + if (DEBUG) Log.v(TAG, mIdString + "close - reentering"); + return; + } - if (mClosed) { - if (DEBUG) Log.v(TAG, mIdString + "close - reentering"); - return; + if (DEBUG) Log.v(TAG, mIdString + "close - first time"); + + mClosed = true; } - if (DEBUG) Log.v(TAG, mIdString + "close - first time"); + synchronized (mDeviceImpl.mInterfaceLock) { + synchronized (this) { + /* + * Flush out any repeating request. Since camera is closed, no new requests + * can be queued, and eventually the entire request queue will be drained. + * + * If the camera device was already closed, short circuit and do nothing; since + * no more internal device callbacks will fire anyway. + * + * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure + * the camera. Once that's done, fire #onClosed. + */ + try { + mDeviceImpl.stopRepeating(); + } catch (IllegalStateException e) { + // OK: Camera device may already be closed, nothing else to do - mClosed = true; + // TODO: Fire onClosed anytime we get the device onClosed or the ISE? + // or just suppress the ISE only and rely onClosed. + // Also skip any of the draining work if this is already closed. - /* - * Flush out any repeating request. Since camera is closed, no new requests - * can be queued, and eventually the entire request queue will be drained. - * - * If the camera device was already closed, short circuit and do nothing; since - * no more internal device callbacks will fire anyway. - * - * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure the - * camera. Once that's done, fire #onClosed. - */ - try { - mDeviceImpl.stopRepeating(); - } catch (IllegalStateException e) { - // OK: Camera device may already be closed, nothing else to do + // Short-circuit; queue callback immediately and return + mStateCallback.onClosed(this); + return; + } catch (CameraAccessException e) { + // OK: close does not throw checked exceptions. + Log.e(TAG, mIdString + "Exception while stopping repeating: ", e); - // TODO: Fire onClosed anytime we get the device onClosed or the ISE? - // or just suppress the ISE only and rely onClosed. - // Also skip any of the draining work if this is already closed. - - // Short-circuit; queue callback immediately and return - mStateCallback.onClosed(this); - return; - } catch (CameraAccessException e) { - // OK: close does not throw checked exceptions. - Log.e(TAG, mIdString + "Exception while stopping repeating: ", e); - - // TODO: call onError instead of onClosed if this happens + // TODO: call onError instead of onClosed if this happens + } + } } - // If no sequences are pending, fire #onClosed immediately - mSequenceDrainer.beginDrain(); + synchronized (this) { + // If no sequences are pending, fire #onClosed immediately + mSequenceDrainer.beginDrain(); + } } /**