Track in-flight requests

This allows for verification of callbacks, and will also be helpful
when implementing flush.

BUG: 31653306
TEST: unit tests pass, test program runs
Change-Id: Id43d6cb3c2b9ca4adc96fc08282f88e0b7b904e1
diff --git a/modules/camera/3_4/camera.cpp b/modules/camera/3_4/camera.cpp
index 04d4c89..d4be03d 100644
--- a/modules/camera/3_4/camera.cpp
+++ b/modules/camera/3_4/camera.cpp
@@ -58,7 +58,8 @@
     mBusy(false),
     mCallbackOps(NULL),
     mStreams(NULL),
-    mNumStreams(0)
+    mNumStreams(0),
+    mInFlightTracker(new RequestTracker)
 {
     memset(&mTemplates, 0, sizeof(mTemplates));
     memset(&mDevice, 0, sizeof(mDevice));
@@ -249,6 +250,9 @@
     mStreams = newStreams;
     mNumStreams = stream_config->num_streams;
 
+    // Update the request tracker.
+    mInFlightTracker->SetStreamConfiguration(*stream_config);
+
     return 0;
 
 err_out:
@@ -256,7 +260,10 @@
     destroyStreams(newStreams, stream_config->num_streams);
     // Set error if it wasn't specified.
     if (!res) {
-      res = -EINVAL;
+        res = -EINVAL;
+    } else if (res != -EINVAL) {
+        // Fatal error, clear stream configuration.
+        mInFlightTracker->ClearStreamConfiguration();
     }
     return res;
 }
@@ -437,27 +444,40 @@
             return -ENODEV;
     }
 
+    // Add the request to tracking.
+    if (!mInFlightTracker->Add(request)) {
+        ALOGE("%s:%d: Failed to track request for frame %d.",
+              __func__, mId, request->frame_number);
+        return -ENODEV;
+    }
+
     // Send the request off to the device for completion.
     enqueueRequest(request);
 
     // Request is now in flight. The device will call completeRequest
     // asynchronously when it is done filling buffers and metadata.
-    // TODO(b/31653306): Track requests in flight to ensure not too many are
-    // sent at a time, and so they can be dumped even if the device loses them.
     return 0;
 }
 
 void Camera::completeRequest(std::shared_ptr<CaptureRequest> request, int err)
 {
-    // TODO(b/31653306): make sure this is actually a request in flight,
-    // and not a random new one or a cancelled one. If so, stop tracking.
-    if (err) {
-        ALOGE("%s:%d: Error completing request for frame %d.",
-              __func__, mId, request->frame_number);
-        completeRequestWithError(request);
+    if (!mInFlightTracker->Remove(request)) {
+        ALOGE("%s:%d: Completed request %p is not being tracked.",
+              __func__, mId, request.get());
         return;
     }
 
+    // Since |request| has been removed from the tracking, this method
+    // MUST call sendResult (can still return a result in an error state, e.g.
+    // through completeRequestWithError) so the frame doesn't get lost.
+
+    if (err) {
+      ALOGE("%s:%d: Error completing request for frame %d.",
+            __func__, mId, request->frame_number);
+      completeRequestWithError(request);
+      return;
+    }
+
     // Notify the framework with the shutter time (extracted from the result).
     int64_t timestamp = 0;
     // TODO(b/31360070): The general metadata methods should be part of the