Camera: Stop repeating request if its output is abandoned

Stop repeating request if any of its output stream is abandoned.
Add a callback to notify the repeating request has been stopped
with frame number of the last frame.

Update NDK with the new callback and behavior.

Bug: 21270879

Change-Id: I3553775c7807a77104aa1650609480ca3321310c
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index ab57db5..755ec8e 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -37,4 +37,11 @@
     oneway void onResultReceived(in CameraMetadataNative result,
                                  in CaptureResultExtras resultExtras);
     oneway void onPrepared(int streamId);
+
+    /**
+     * Repeating request encountered an error and was stopped.
+     *
+     * @param lastFrameNumber Frame number of the last frame of the streaming request.
+     */
+    oneway void onRepeatingRequestError(in long lastFrameNumber);
 }
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 250f15e..1e8744b 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -36,7 +36,10 @@
      * Cancel the repeating request specified by requestId
      * Returns the frame number of the last frame that will be produced from this
      * repeating request, or NO_IN_FLIGHT_REPEATING_FRAMES if no frames were produced
-     * by this repeating request
+     * by this repeating request.
+     *
+     * Repeating request may be stopped by camera device due to an error. Canceling a stopped
+     * repeating request will trigger ERROR_ILLEGAL_ARGUMENT.
      */
     long cancelRequest(int requestId);
 
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 0b758b6..bff5547 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -380,7 +380,11 @@
 
         int64_t lastFrameNumber;
         binder::Status remoteRet = mRemote->cancelRequest(repeatingSequenceId, &lastFrameNumber);
-        if (!remoteRet.isOk()) {
+        if (remoteRet.serviceSpecificErrorCode() ==
+                hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT) {
+            ALOGV("Repeating request is already stopped.");
+            return ACAMERA_OK;
+        } else if (!remoteRet.isOk()) {
             ALOGE("Stop repeating request fails in remote: %s", remoteRet.toString8().string());
             return ACAMERA_ERROR_UNKNOWN;
         }
@@ -1342,4 +1346,24 @@
     return binder::Status::ok();
 }
 
+binder::Status
+CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
+    binder::Status ret = binder::Status::ok();
+
+    sp<CameraDevice> dev = mDevice.promote();
+    if (dev == nullptr) {
+        return ret; // device has been closed
+    }
+
+    Mutex::Autolock _l(dev->mDeviceLock);
+
+    int repeatingSequenceId = dev->mRepeatingSequenceId;
+    dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+
+    dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+
+    return ret;
+}
+
+
 } // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 3ccf95a..71e364d 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -74,6 +74,7 @@
         binder::Status onResultReceived(const CameraMetadata& metadata,
                               const CaptureResultExtras& resultExtras) override;
         binder::Status onPrepared(int streamId) override;
+        binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
       private:
         const wp<CameraDevice> mDevice;
     };
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 0b687b4..828a758 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -149,7 +149,8 @@
         PREPARED,
         RUNNING,
         SENT_RESULT,
-        UNINITIALIZED
+        UNINITIALIZED,
+        REPEATING_REQUEST_ERROR,
     };
 
 protected:
@@ -215,6 +216,15 @@
         return binder::Status::ok();
     }
 
+    virtual binder::Status onRepeatingRequestError(int64_t lastFrameNumber) {
+        (void) lastFrameNumber;
+        Mutex::Autolock l(mLock);
+        mLastStatus = REPEATING_REQUEST_ERROR;
+        mStatusesHit.push_back(mLastStatus);
+        mStatusCondition.broadcast();
+        return binder::Status::ok();
+    }
+
     // Test helper functions:
 
     bool hadError() const {