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

Commit 2da496f1 authored by Chien-Yu Chen's avatar Chien-Yu Chen
Browse files

Camera2: Stop repeating request for abandoned output

Stop repeating request if any of its output stream is abandoned
and notify that repeating request has been stopped.

Update binder tests for binder interface changes.

Update CameraDeviceImpl to expect an exception when canceling
a repeating request that is already stopped.

Bug: 21270879
Change-Id: I9fa72ae7218948aac88cb1a8e57839bd022c4a5e
parent 95a4791d
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -921,7 +921,16 @@ public class CameraDeviceImpl extends CameraDevice
                int requestId = mRepeatingRequestId;
                mRepeatingRequestId = REQUEST_ID_NONE;

                long lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
                long lastFrameNumber;
                try {
                    lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
                } catch (IllegalArgumentException e) {
                    if (DEBUG) {
                        Log.v(TAG, "Repeating request was already stopped for request " + requestId);
                    }
                    // Repeating request was already stopped. Nothing more to do.
                    return;
                }

                checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
            }
@@ -1685,6 +1694,24 @@ public class CameraDeviceImpl extends CameraDevice
            }
        }

        @Override
        public void onRepeatingRequestError(long lastFrameNumber) {
            if (DEBUG) {
                Log.d(TAG, "Repeating request error received. Last frame number is " +
                        lastFrameNumber);
            }

            synchronized(mInterfaceLock) {
                // Camera is already closed or no repeating request is present.
                if (mRemoteDevice == null || mRepeatingRequestId == REQUEST_ID_NONE) {
                    return; // Camera already closed
                }

                checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
                mRepeatingRequestId = REQUEST_ID_NONE;
            }
        }

        @Override
        public void onDeviceIdle() {
            if (DEBUG) {
+17 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ public class CameraDeviceState {
        void onBusy();
        void onCaptureStarted(RequestHolder holder, long timestamp);
        void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
        void onRepeatingRequestError(long lastFrameNumber);
    }

    /**
@@ -200,6 +201,22 @@ public class CameraDeviceState {
        return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
    }

    /**
     * Set repeating request error.
     *
     * <p>Repeating request has been stopped due to an error such as abandoned output surfaces.</p>
     *
     * @param lastFrameNumber Frame number of the last repeating request before it is stopped.
     */
    public synchronized void setRepeatingRequestError(final long lastFrameNumber) {
        mCurrentHandler.post(new Runnable() {
            @Override
            public void run() {
                mCurrentListener.onRepeatingRequestError(lastFrameNumber);
            }
        });
    }

    /**
     * Set the listener for state transition callbacks.
     *
+16 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
        private static final int CAPTURE_STARTED = 2;
        private static final int RESULT_RECEIVED = 3;
        private static final int PREPARED = 4;
        private static final int REPEATING_REQUEST_ERROR = 5;

        private final HandlerThread mHandlerThread;
        private Handler mHandler;
@@ -261,6 +262,15 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
            getHandler().sendMessage(msg);
        }


        @Override
        public void onRepeatingRequestError(long lastFrameNumber) {
            Message msg = getHandler().obtainMessage(REPEATING_REQUEST_ERROR,
                    /*arg1*/ (int) (lastFrameNumber & 0xFFFFFFFFL),
                    /*arg2*/ (int) ( (lastFrameNumber >> 32) & 0xFFFFFFFFL));
            getHandler().sendMessage(msg);
        }

        @Override
        public IBinder asBinder() {
            // This is solely intended to be used for in-process binding.
@@ -311,6 +321,12 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
                            mCallbacks.onPrepared(streamId);
                            break;
                        }
                        case REPEATING_REQUEST_ERROR: {
                            long lastFrameNumber = msg.arg2 & 0xFFFFFFFFL;
                            lastFrameNumber = (lastFrameNumber << 32) | (msg.arg1 & 0xFFFFFFFFL);
                            mCallbacks.onRepeatingRequestError(lastFrameNumber);
                            break;
                        }
                        default:
                            throw new IllegalArgumentException(
                                "Unknown callback message " + msg.what);
+45 −7
Original line number Diff line number Diff line
@@ -242,6 +242,25 @@ public class LegacyCameraDevice implements AutoCloseable {
                }
            });
        }

        @Override
        public void onRepeatingRequestError(final long lastFrameNumber) {
            mResultHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (DEBUG) {
                        Log.d(TAG, "doing onRepeatingRequestError callback.");
                    }
                    try {
                        mDeviceCallbacks.onRepeatingRequestError(lastFrameNumber);
                    } catch (RemoteException e) {
                        throw new IllegalStateException(
                                "Received remote exception during onRepeatingRequestError " +
                                "callback: ", e);
                    }
                }
            });
        }
    };

    private final RequestThreadManager mRequestThreadManager;
@@ -397,8 +416,15 @@ public class LegacyCameraDevice implements AutoCloseable {
                    "submitRequestList - Empty/null requests are not allowed");
        }

        List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
        List<Long> surfaceIds;

        try {
            surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
                    getSurfaceIds(mConfiguredSurfaces);
        } catch (BufferQueueAbandonedException e) {
            throw new ServiceSpecificException(BAD_VALUE,
                    "submitRequestList - configured surface is abandoned.");
        }

        // Make sure that there all requests have at least 1 surface; all surfaces are non-null
        for (CaptureRequest request : requestList) {
@@ -674,12 +700,17 @@ public class LegacyCameraDevice implements AutoCloseable {
        LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
    }

    static long getSurfaceId(Surface surface) {
    static long getSurfaceId(Surface surface) throws BufferQueueAbandonedException {
        checkNotNull(surface);
        try {
            return nativeGetSurfaceId(surface);
        } catch (IllegalArgumentException e) {
            throw new BufferQueueAbandonedException();
        }
    }

    static List<Long> getSurfaceIds(SparseArray<Surface> surfaces) {
    static List<Long> getSurfaceIds(SparseArray<Surface> surfaces)
            throws BufferQueueAbandonedException {
        if (surfaces == null) {
            throw new NullPointerException("Null argument surfaces");
        }
@@ -696,7 +727,8 @@ public class LegacyCameraDevice implements AutoCloseable {
        return surfaceIds;
    }

    static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
    static List<Long> getSurfaceIds(Collection<Surface> surfaces)
            throws BufferQueueAbandonedException {
        if (surfaces == null) {
            throw new NullPointerException("Null argument surfaces");
        }
@@ -713,7 +745,13 @@ public class LegacyCameraDevice implements AutoCloseable {
    }

    static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
        long id = getSurfaceId(s);
        long id = 0;
        try {
            id = getSurfaceId(s);
        } catch (BufferQueueAbandonedException e) {
            // If surface is abandoned, return false.
            return false;
        }
        return ids.contains(id);
    }

+14 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ public class RequestHolder {
    private final int mNumJpegTargets;
    private final int mNumPreviewTargets;
    private volatile boolean mFailed = false;
    private boolean mOutputAbandoned = false;

    private final Collection<Long> mJpegSurfaceIds;

@@ -266,4 +267,17 @@ public class RequestHolder {
        return mFailed;
    }

    /**
     * Mark at least one of this request's output surfaces is abandoned.
     */
    public void setOutputAbandoned() {
        mOutputAbandoned = true;
    }

    /**
     * Return if any of this request's output surface is abandoned.
     */
    public boolean isOutputAbandoned() {
        return mOutputAbandoned;
    }
}
Loading