Camera: Keep a list of outstanding buffers

Keep a list of outstanding buffers in Camera3Stream so that
it won't return invalid buffers or the same buffers twice back
to the buffer queue.

Bug: 27894484
Change-Id: I9f96629b4f531778433c2e1ec32a142f2040832b
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index a4714a7..80dce84 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -476,16 +476,51 @@
     res = getBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
+        if (buffer->buffer) {
+            mOutstandingBuffers.push_back(*buffer->buffer);
+        }
     }
 
     return res;
 }
 
+bool Camera3Stream::isOutstandingBuffer(const camera3_stream_buffer &buffer) {
+    if (buffer.buffer == nullptr) {
+        return false;
+    }
+
+    for (auto b : mOutstandingBuffers) {
+        if (b == *buffer.buffer) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void Camera3Stream::removeOutstandingBuffer(const camera3_stream_buffer &buffer) {
+    if (buffer.buffer == nullptr) {
+        return;
+    }
+
+    for (auto b = mOutstandingBuffers.begin(); b != mOutstandingBuffers.end(); b++) {
+        if (*b == *buffer.buffer) {
+            mOutstandingBuffers.erase(b);
+            return;
+        }
+    }
+}
+
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
         nsecs_t timestamp) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
+    // Check if this buffer is outstanding.
+    if (!isOutstandingBuffer(buffer)) {
+        ALOGE("%s: Stream %d: Returning an unknown buffer.", __FUNCTION__, mId);
+        return BAD_VALUE;
+    }
+
     /**
      * TODO: Check that the state is valid first.
      *
@@ -503,6 +538,7 @@
     // buffer to be returned.
     mOutputBufferReturnedSignal.signal();
 
+    removeOutstandingBuffer(buffer);
     return res;
 }
 
@@ -535,6 +571,9 @@
     res = getInputBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false);
+        if (buffer->buffer) {
+            mOutstandingBuffers.push_back(*buffer->buffer);
+        }
     }
 
     return res;
@@ -544,11 +583,19 @@
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
+    // Check if this buffer is outstanding.
+    if (!isOutstandingBuffer(buffer)) {
+        ALOGE("%s: Stream %d: Returning an unknown buffer.", __FUNCTION__, mId);
+        return BAD_VALUE;
+    }
+
     status_t res = returnInputBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false);
         mInputBufferReturnedSignal.signal();
     }
+
+    removeOutstandingBuffer(buffer);
     return res;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index c932e253..810383d 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -457,6 +457,12 @@
 
     status_t        cancelPrepareLocked();
 
+    // Return whether the buffer is in the list of outstanding buffers.
+    bool isOutstandingBuffer(const camera3_stream_buffer& buffer);
+
+    // Remove the buffer from the list of outstanding buffers.
+    void removeOutstandingBuffer(const camera3_stream_buffer& buffer);
+
     // Tracking for PREPARING state
 
     // State of buffer preallocation. Only true if either prepareNextBuffer
@@ -470,6 +476,9 @@
     // Number of buffers allocated on last prepare call.
     size_t mLastMaxCount;
 
+    // Outstanding buffers dequeued from the stream's buffer queue.
+    List<buffer_handle_t> mOutstandingBuffers;
+
 }; // class Camera3Stream
 
 }; // namespace camera3