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

Commit caa1a655 authored by Emilian Peev's avatar Emilian Peev
Browse files

Camera: Try to recover from failing stopRepeating requests

In case the camera client disconnects from an output surface referenced
by an active repeating request, a race could occur between the client
and camera service. Camera service will notify the client about the
failed repeating request and will reset the request id internally.
During this time period the client can also try to call "stopRepeating"
which will trigger an IAE, reset the client repeating request id value
and return immediately. Once the "onRepeatingRequestError" gets
scheduled or unblocked, the framework will just ignore it since it
doesn't have any information about an active repeating request.
The framework will be unable to track the last frame id in the repeating
sequence. The sequence will never complete and the 'onClosed' callback
will not get triggered as well.
To mitigate this, cache the request id in case of IAE during
"stopRepeating" and try to resume the last frame id sequence tracking
once "onRepeatingRequestError" arrives.

Bug: 205895636
Test: Camera CTS
Change-Id: I5da4a82d156227568aaebe74a5e0b2400de1d01e
parent d7d5f316
Loading
Loading
Loading
Loading
+26 −2
Original line number Diff line number Diff line
@@ -110,6 +110,11 @@ public class CameraDeviceImpl extends CameraDevice
    private int mRepeatingRequestId = REQUEST_ID_NONE;
    // Latest repeating request list's types
    private int[] mRepeatingRequestTypes;

    // Cache failed requests to process later in case of a repeating error callback
    private int mFailedRepeatingRequestId = REQUEST_ID_NONE;
    private int[] mFailedRepeatingRequestTypes;

    // Map stream IDs to input/output configurations
    private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
            new SimpleEntry<>(REQUEST_ID_NONE, null);
@@ -1326,16 +1331,25 @@ public class CameraDeviceImpl extends CameraDevice

                int requestId = mRepeatingRequestId;
                mRepeatingRequestId = REQUEST_ID_NONE;
                mFailedRepeatingRequestId = REQUEST_ID_NONE;
                int[] requestTypes = mRepeatingRequestTypes;
                mRepeatingRequestTypes = null;
                mFailedRepeatingRequestTypes = null;

                long lastFrameNumber;
                try {
                    lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
                } catch (IllegalArgumentException e) {
                    if (DEBUG) {
                        Log.v(TAG, "Repeating request was already stopped for request " + requestId);
                        Log.v(TAG, "Repeating request was already stopped for request " +
                                requestId);
                    }
                    // Cache request id and request types in case of a race with
                    // "onRepeatingRequestError" which may no yet be scheduled on another thread
                    // or blocked by us.
                    mFailedRepeatingRequestId = requestId;
                    mFailedRepeatingRequestTypes = requestTypes;

                    // Repeating request was already stopped. Nothing more to do.
                    return;
                }
@@ -1965,7 +1979,17 @@ public class CameraDeviceImpl extends CameraDevice
            synchronized(mInterfaceLock) {
                // Camera is already closed or no repeating request is present.
                if (mRemoteDevice == null || mRepeatingRequestId == REQUEST_ID_NONE) {
                    return; // Camera already closed
                    if ((mFailedRepeatingRequestId == repeatingRequestId) &&
                            (mFailedRepeatingRequestTypes != null) && (mRemoteDevice != null)) {
                        Log.v(TAG, "Resuming stop of failed repeating request with id: " +
                                mFailedRepeatingRequestId);

                        checkEarlyTriggerSequenceCompleteLocked(mFailedRepeatingRequestId,
                                lastFrameNumber, mFailedRepeatingRequestTypes);
                        mFailedRepeatingRequestId = REQUEST_ID_NONE;
                        mFailedRepeatingRequestTypes = null;
                    }
                    return;
                }

                // Redirect device callback to the offline session in case we are in the middle