Camera: handle HAL buffer manager + stream sharing case

Test: CTS MultiViewTest
Bug: 109829698
Change-Id: I98a7438d6bb9c01f95ae69c7556d7ed965629410
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index fa4e036..f0d9475 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1084,6 +1084,11 @@
                             __FUNCTION__, streamId, strerror(-res), res);
                 }
             }
+            for (size_t b = 0; b < numAllocatedBuffers; b++) {
+                camera3_stream_buffer_t& sb = streamBuffers[b];
+                sb.acquire_fence = -1;
+                sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+            }
             returnOutputBuffers(streamBuffers.data(), numAllocatedBuffers, 0);
         }
     }
@@ -1744,7 +1749,8 @@
     } else if (isShared) {
         newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
                 width, height, format, consumerUsage, dataSpace, rotation,
-                mTimestampOffset, physicalCameraId, streamSetId);
+                mTimestampOffset, physicalCameraId, streamSetId,
+                mUseHalBufManager);
     } else if (consumers.size() == 0 && hasDeferredConsumer) {
         newStream = new Camera3OutputStream(mNextStreamId,
                 width, height, format, consumerUsage, dataSpace, rotation,
@@ -3030,13 +3036,14 @@
         int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
         bool hasAppCallback, nsecs_t maxExpectedDuration,
         std::set<String8>& physicalCameraIds, bool isStillCapture,
-        bool isZslCapture) {
+        bool isZslCapture, const SurfaceMap& outputSurfaces) {
     ATRACE_CALL();
     Mutex::Autolock l(mInFlightLock);
 
     ssize_t res;
     res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
-            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture));
+            hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture,
+            outputSurfaces));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
@@ -3054,18 +3061,55 @@
 
 void Camera3Device::returnOutputBuffers(
         const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
-        nsecs_t timestamp, bool timestampIncreasing) {
+        nsecs_t timestamp, bool timestampIncreasing,
+        const SurfaceMap& outputSurfaces,
+        const CaptureResultExtras &inResultExtras) {
 
     for (size_t i = 0; i < numBuffers; i++)
     {
-        Camera3Stream *stream = Camera3Stream::cast(outputBuffers[i].stream);
-        status_t res = stream->returnBuffer(outputBuffers[i], timestamp, timestampIncreasing);
+        Camera3StreamInterface *stream = Camera3Stream::cast(outputBuffers[i].stream);
+        int streamId = stream->getId();
+        const auto& it = outputSurfaces.find(streamId);
+        status_t res = OK;
+        if (it != outputSurfaces.end()) {
+            res = stream->returnBuffer(
+                    outputBuffers[i], timestamp, timestampIncreasing, it->second);
+        } else {
+            res = stream->returnBuffer(
+                    outputBuffers[i], timestamp, timestampIncreasing);
+        }
+
         // Note: stream may be deallocated at this point, if this buffer was
         // the last reference to it.
         if (res != OK) {
             ALOGE("Can't return buffer to its stream: %s (%d)",
                 strerror(-res), res);
         }
+
+        // Long processing consumers can cause returnBuffer timeout for shared stream
+        // If that happens, cancel the buffer and send a buffer error to client
+        if (it != outputSurfaces.end() && res == TIMED_OUT &&
+                outputBuffers[i].status == CAMERA3_BUFFER_STATUS_OK) {
+            // cancel the buffer
+            camera3_stream_buffer_t sb = outputBuffers[i];
+            sb.status = CAMERA3_BUFFER_STATUS_ERROR;
+            stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing);
+
+            // notify client buffer error
+            sp<NotificationListener> listener;
+            {
+                Mutex::Autolock l(mOutputLock);
+                listener = mListener.promote();
+            }
+
+            if (listener != nullptr) {
+                CaptureResultExtras extras = inResultExtras;
+                extras.errorStreamId = streamId;
+                listener->notifyError(
+                        hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER,
+                        extras);
+            }
+        }
     }
 }
 
@@ -3124,7 +3168,8 @@
         assert(request.requestStatus != OK ||
                request.pendingOutputBuffers.size() == 0);
         returnOutputBuffers(request.pendingOutputBuffers.array(),
-            request.pendingOutputBuffers.size(), 0);
+            request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
+            request.outputSurfaces, request.resultExtras);
 
         removeInFlightMapEntryLocked(idx);
         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
@@ -3148,7 +3193,9 @@
         for (size_t idx = 0; idx < mInFlightMap.size(); idx++) {
             const InFlightRequest &request = mInFlightMap.valueAt(idx);
             returnOutputBuffers(request.pendingOutputBuffers.array(),
-                request.pendingOutputBuffers.size(), 0);
+                request.pendingOutputBuffers.size(), 0,
+                /*timestampIncreasing*/true, request.outputSurfaces,
+                request.resultExtras);
         }
         mInFlightMap.clear();
         mExpectedInflightDuration = 0;
@@ -3506,7 +3553,8 @@
         } else {
             bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
             returnOutputBuffers(result->output_buffers,
-                result->num_output_buffers, shutterTimestamp, timestampIncreasing);
+                result->num_output_buffers, shutterTimestamp, timestampIncreasing,
+                request.outputSurfaces, request.resultExtras);
         }
 
         if (result->result != NULL && !isPartialResult) {
@@ -3639,6 +3687,9 @@
                         // In case of missing result check whether the buffers
                         // returned. If they returned, then remove inflight
                         // request.
+                        // TODO: should we call this for ERROR_CAMERA_REQUEST as well?
+                        //       otherwise we are depending on HAL to send the buffers back after
+                        //       calling notifyError. Not sure if that's in the spec.
                         removeInFlightRequestIfReadyLocked(idx);
                     }
                 } else {
@@ -3714,7 +3765,8 @@
             }
             bool timestampIncreasing = !(r.zslCapture || r.hasInputBuffer);
             returnOutputBuffers(r.pendingOutputBuffers.array(),
-                r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing);
+                    r.pendingOutputBuffers.size(), r.shutterTimestamp, timestampIncreasing,
+                    r.outputSurfaces, r.resultExtras);
             r.pendingOutputBuffers.clear();
 
             removeInFlightRequestIfReadyLocked(idx);
@@ -5266,8 +5318,11 @@
         }
         nsecs_t waitDuration = kBaseGetBufferWait + parent->getExpectedInFlightDuration();
 
+        SurfaceMap uniqueSurfaceIdMap;
         for (size_t j = 0; j < captureRequest->mOutputStreams.size(); j++) {
-            sp<Camera3OutputStreamInterface> outputStream = captureRequest->mOutputStreams.editItemAt(j);
+            sp<Camera3OutputStreamInterface> outputStream =
+                    captureRequest->mOutputStreams.editItemAt(j);
+            int streamId = outputStream->getId();
 
             // Prepare video buffers for high speed recording on the first video request.
             if (mPrepareVideoStream && outputStream->isVideoStream()) {
@@ -5286,6 +5341,20 @@
                 }
             }
 
+            std::vector<size_t> uniqueSurfaceIds;
+            res = outputStream->getUniqueSurfaceIds(
+                    captureRequest->mOutputSurfaces[streamId],
+                    &uniqueSurfaceIds);
+            // INVALID_OPERATION is normal output for streams not supporting surfaceIds
+            if (res != OK && res != INVALID_OPERATION) {
+                ALOGE("%s: failed to query stream %d unique surface IDs",
+                        __FUNCTION__, streamId);
+                return res;
+            }
+            if (res == OK) {
+                uniqueSurfaceIdMap.insert({streamId, std::move(uniqueSurfaceIds)});
+            }
+
             if (mUseHalBufManager) {
                 // HAL will request buffer through requestStreamBuffer API
                 camera3_stream_buffer_t& buffer = outputBuffers->editItemAt(j);
@@ -5297,7 +5366,7 @@
             } else {
                 res = outputStream->getBuffer(&outputBuffers->editItemAt(j),
                         waitDuration,
-                        captureRequest->mOutputSurfaces[outputStream->getId()]);
+                        captureRequest->mOutputSurfaces[streamId]);
                 if (res != OK) {
                     // Can't get output buffer from gralloc queue - this could be due to
                     // abandoned queue or other consumer misbehavior, so not a fatal
@@ -5351,7 +5420,9 @@
                 /*hasInput*/halRequest->input_buffer != NULL,
                 hasCallback,
                 calculateMaxExpectedDuration(halRequest->settings),
-                requestedPhysicalCameras, isStillCapture, isZslCapture);
+                requestedPhysicalCameras, isStillCapture, isZslCapture,
+                (mUseHalBufManager) ? uniqueSurfaceIdMap :
+                                      SurfaceMap{});
         ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
                ", burstId = %" PRId32 ".",
                 __FUNCTION__,
@@ -5427,7 +5498,7 @@
             if (s.first == streamId) {
                 const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
                 if (it != s.second.end()) {
-                  return true;
+                    return true;
                 }
             }
         }
@@ -5438,7 +5509,7 @@
             if (s.first == streamId) {
                 const auto &it = std::find(s.second.begin(), s.second.end(), surfaceId);
                 if (it != s.second.end()) {
-                  return true;
+                    return true;
                 }
             }
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 4f5be6b..3fe48fb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1031,6 +1031,9 @@
         // Indicates a ZSL capture request
         bool zslCapture;
 
+        // What shared surfaces an output should go to
+        SurfaceMap outputSurfaces;
+
         // Default constructor needed by KeyedVector
         InFlightRequest() :
                 shutterTimestamp(0),
@@ -1049,7 +1052,8 @@
         InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
                 bool hasAppCallback, nsecs_t maxDuration,
                 const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
-                bool isZslCapture) :
+                bool isZslCapture,
+                const SurfaceMap& outSurfaces = SurfaceMap{}) :
                 shutterTimestamp(0),
                 sensorTimestamp(0),
                 requestStatus(OK),
@@ -1062,7 +1066,8 @@
                 skipResultMetadata(false),
                 physicalCameraIds(physicalCameraIdSet),
                 stillCapture(isStillCapture),
-                zslCapture(isZslCapture) {
+                zslCapture(isZslCapture),
+                outputSurfaces(outSurfaces) {
         }
     };
 
@@ -1079,7 +1084,8 @@
     status_t registerInFlight(uint32_t frameNumber,
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
             bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
-            bool isStillCapture, bool isZslCapture);
+            bool isStillCapture, bool isZslCapture,
+            const SurfaceMap& outputSurfaces);
 
     /**
      * Returns the maximum expected time it'll take for all currently in-flight
@@ -1189,7 +1195,11 @@
 
     // helper function to return the output buffers to the streams.
     void returnOutputBuffers(const camera3_stream_buffer_t *outputBuffers,
-            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true);
+            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
+            // The following arguments are only meant for surface sharing use case
+            const SurfaceMap& outputSurfaces = SurfaceMap{},
+            // Used to send buffer error callback when failing to return buffer
+            const CaptureResultExtras &resultExtras = CaptureResultExtras{});
 
     // Send a partial capture result.
     void sendPartialCaptureResult(const camera_metadata_t * partialResult,
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index fb1ff77..b637160 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -48,7 +48,7 @@
 
 status_t Camera3DummyStream::returnBufferLocked(
         const camera3_stream_buffer &,
-        nsecs_t) {
+        nsecs_t, const std::vector<size_t>&) {
     ATRACE_CALL();
     ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
@@ -58,6 +58,7 @@
             const camera3_stream_buffer &,
             nsecs_t,
             bool,
+            const std::vector<size_t>&,
             /*out*/
             sp<Fence>*) {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 4627548..4b67ea5 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -87,6 +87,9 @@
      */
     virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
 
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>&,
+            /*out*/std::vector<size_t>*) { return INVALID_OPERATION; };
+
     /**
      * Update the stream output surfaces.
      */
@@ -104,6 +107,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
@@ -128,7 +132,7 @@
             const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp, const std::vector<size_t>& surface_ids);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 18b8c4d..2e909a0 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -219,7 +219,8 @@
 status_t Camera3IOStreamBase::returnAnyBufferLocked(
         const camera3_stream_buffer &buffer,
         nsecs_t timestamp,
-        bool output) {
+        bool output,
+        const std::vector<size_t>& surface_ids) {
     status_t res;
 
     // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be
@@ -235,7 +236,7 @@
     }
 
     sp<Fence> releaseFence;
-    res = returnBufferCheckedLocked(buffer, timestamp, output,
+    res = returnBufferCheckedLocked(buffer, timestamp, output, surface_ids,
                                     &releaseFence);
     // Res may be an error, but we still want to decrement our owned count
     // to enable clean shutdown. So we'll just return the error but otherwise
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 48e9bbf..750f64d 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -66,12 +66,14 @@
     status_t         returnAnyBufferLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
-            bool output);
+            bool output,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     virtual status_t returnBufferCheckedLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut) = 0;
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 017d7be..fc83684 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -98,6 +98,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>&,
             /*out*/
             sp<Fence> *releaseFenceOut) {
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 0732464..97a627a 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -62,6 +62,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index ecbcf76..219cc24 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -187,16 +187,17 @@
 }
 
 status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>&) {
     return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
 }
 
 status_t Camera3OutputStream::returnBufferLocked(
         const camera3_stream_buffer &buffer,
-        nsecs_t timestamp) {
+        nsecs_t timestamp, const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
 
-    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true);
+    status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true, surface_ids);
 
     if (res != OK) {
         return res;
@@ -212,6 +213,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut) {
 
@@ -281,7 +283,7 @@
             return res;
         }
 
-        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence);
+        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error queueing buffer to native window: "
                   "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 6f36f92..410905d 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -190,6 +190,9 @@
      */
     virtual ssize_t getSurfaceId(const sp<Surface> &/*surface*/) { return 0; }
 
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>&,
+            /*out*/std::vector<size_t>*) { return INVALID_OPERATION; };
+
     /**
      * Update the stream output surfaces.
      */
@@ -213,6 +216,7 @@
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp,
             bool output,
+            const std::vector<size_t>& surface_ids,
             /*out*/
             sp<Fence> *releaseFenceOut);
 
@@ -285,10 +289,11 @@
 
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp, const std::vector<size_t>& surface_ids);
 
     virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& surface_ids);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index a711a6d..2bde949 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -67,6 +67,18 @@
     virtual ssize_t getSurfaceId(const sp<Surface> &surface) = 0;
 
     /**
+     * Query the unique surface IDs of current surfaceIds.
+     * When passing unique surface IDs in returnBuffer(), if the
+     * surfaceId has been removed from the stream, the output corresponding to
+     * the unique surface ID will be ignored and not delivered to client.
+     *
+     * Return INVALID_OPERATION if and only if the stream does not support
+     * surface sharing.
+     */
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>& surfaceIds,
+            /*out*/std::vector<size_t>* outUniqueIds) = 0;
+
+    /**
      * Update the stream output surfaces.
      */
     virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 1c13950..e3b74d7 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "Camera3-SharedOuStrm"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
 #include "Camera3SharedOutputStream.h"
 
 namespace android {
@@ -28,16 +32,17 @@
         uint64_t consumerUsage, android_dataspace dataSpace,
         camera3_stream_rotation_t rotation,
         nsecs_t timestampOffset, const String8& physicalCameraId,
-        int setId) :
+        int setId, bool useHalBufManager) :
         Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
                             format, dataSpace, rotation, physicalCameraId,
-                            consumerUsage, timestampOffset, setId) {
+                            consumerUsage, timestampOffset, setId),
+        mUseHalBufManager(useHalBufManager) {
     size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
     if (surfaces.size() > consumerCount) {
         ALOGE("%s: Trying to add more consumers than the maximum ", __func__);
     }
     for (size_t i = 0; i < consumerCount; i++) {
-        mSurfaces[i] = surfaces[i];
+        mSurfaceUniqueIds[i] = std::make_pair(surfaces[i], mNextUniqueSurfaceId++);
     }
 }
 
@@ -48,15 +53,15 @@
 status_t Camera3SharedOutputStream::connectStreamSplitterLocked() {
     status_t res = OK;
 
-    mStreamSplitter = new Camera3StreamSplitter();
+    mStreamSplitter = new Camera3StreamSplitter(mUseHalBufManager);
 
     uint64_t usage;
     getEndpointUsage(&usage);
 
     std::unordered_map<size_t, sp<Surface>> initialSurfaces;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] != nullptr) {
-            initialSurfaces.emplace(i, mSurfaces[i]);
+        if (mSurfaceUniqueIds[i].first != nullptr) {
+            initialSurfaces.emplace(i, mSurfaceUniqueIds[i].first);
         }
     }
 
@@ -71,6 +76,31 @@
     return res;
 }
 
+status_t Camera3SharedOutputStream::attachBufferToSplitterLocked(
+        ANativeWindowBuffer* anb,
+        const std::vector<size_t>& surface_ids) {
+    status_t res = OK;
+
+    // Attach the buffer to the splitter output queues. This could block if
+    // the output queue doesn't have any empty slot. So unlock during the course
+    // of attachBufferToOutputs.
+    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
+    mLock.unlock();
+    res = splitter->attachBufferToOutputs(anb, surface_ids);
+    mLock.lock();
+    if (res != OK) {
+        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+        // let prepareNextBuffer handle the error.)
+        if (res == NO_INIT && mState == STATE_CONFIGURED) {
+            mState = STATE_ABANDONED;
+        }
+    }
+    return res;
+}
+
+
 status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -89,7 +119,7 @@
         return true;
     }
 
-    return (mSurfaces[surface_id] == nullptr);
+    return (mSurfaceUniqueIds[surface_id].first == nullptr);
 }
 
 status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
@@ -112,7 +142,7 @@
             return NO_MEMORY;
         }
 
-        mSurfaces[id] = surface;
+        mSurfaceUniqueIds[id] = std::make_pair(surface, mNextUniqueSurfaceId++);
 
         // Only call addOutput if the splitter has been connected.
         if (mStreamSplitter != nullptr) {
@@ -128,7 +158,7 @@
 }
 
 status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
-        const std::vector<size_t>& surface_ids) {
+        const std::vector<size_t>& surfaceIds) {
     ANativeWindowBuffer* anb;
     int fenceFd = -1;
 
@@ -138,27 +168,11 @@
         return res;
     }
 
-    // TODO: need to refactor this to support requestStreamBuffers API
-    // Need to wait until processCaptureResult to decide the source buffer
-    // to attach to output...
-
-    // Attach the buffer to the splitter output queues. This could block if
-    // the output queue doesn't have any empty slot. So unlock during the course
-    // of attachBufferToOutputs.
-    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
-    mLock.unlock();
-    res = splitter->attachBufferToOutputs(anb, surface_ids);
-    mLock.lock();
-    if (res != OK) {
-        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
-        // let prepareNextBuffer handle the error.)
-        if (res == NO_INIT && mState == STATE_CONFIGURED) {
-            mState = STATE_ABANDONED;
+    if (!mUseHalBufManager) {
+        res = attachBufferToSplitterLocked(anb, surfaceIds);
+        if (res != OK) {
+            return res;
         }
-
-        return res;
     }
 
     /**
@@ -172,8 +186,38 @@
 }
 
 status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence) {
-    status_t res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& uniqueSurfaceIds) {
+    status_t res = OK;
+    if (mUseHalBufManager) {
+        if (uniqueSurfaceIds.size() == 0) {
+            ALOGE("%s: uniqueSurfaceIds must not be empty!", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        Mutex::Autolock l(mLock);
+        std::vector<size_t> surfaceIds;
+        for (const auto& uniqueId : uniqueSurfaceIds) {
+            bool uniqueIdFound = false;
+            for (size_t i = 0; i < kMaxOutputs; i++) {
+                if (mSurfaceUniqueIds[i].second == uniqueId) {
+                    surfaceIds.push_back(i);
+                    uniqueIdFound = true;
+                    break;
+                }
+            }
+            if (!uniqueIdFound) {
+                ALOGV("%s: unknown unique surface ID %zu for stream %d: "
+                        "output might have been removed.",
+                        __FUNCTION__, uniqueId, mId);
+            }
+        }
+        res = attachBufferToSplitterLocked(buffer, surfaceIds);
+        if (res != OK) {
+            return res;
+        }
+    }
+
+    res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
 
     // After queuing buffer to the internal consumer queue, check whether the buffer is
     // successfully queued to the output queues.
@@ -232,8 +276,8 @@
         *usage = getPresetConsumerUsage();
 
         for (size_t id = 0; id < kMaxOutputs; id++) {
-            if (mSurfaces[id] != nullptr) {
-                res = getEndpointUsageForSurface(&u, mSurfaces[id]);
+            if (mSurfaceUniqueIds[id].first != nullptr) {
+                res = getEndpointUsageForSurface(&u, mSurfaceUniqueIds[id].first);
                 *usage |= u;
             }
         }
@@ -249,7 +293,7 @@
 ssize_t Camera3SharedOutputStream::getNextSurfaceIdLocked() {
     ssize_t id = -1;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] == nullptr) {
+        if (mSurfaceUniqueIds[i].first == nullptr) {
             id = i;
             break;
         }
@@ -262,7 +306,7 @@
     Mutex::Autolock l(mLock);
     ssize_t id = -1;
     for (size_t i = 0; i < kMaxOutputs; i++) {
-        if (mSurfaces[i] == surface) {
+        if (mSurfaceUniqueIds[i].first == surface) {
             id = i;
             break;
         }
@@ -271,6 +315,26 @@
     return id;
 }
 
+status_t Camera3SharedOutputStream::getUniqueSurfaceIds(
+        const std::vector<size_t>& surfaceIds,
+        /*out*/std::vector<size_t>* outUniqueIds) {
+    Mutex::Autolock l(mLock);
+    if (outUniqueIds == nullptr || surfaceIds.size() > kMaxOutputs) {
+        return BAD_VALUE;
+    }
+
+    outUniqueIds->clear();
+    outUniqueIds->reserve(surfaceIds.size());
+
+    for (const auto& surfaceId : surfaceIds) {
+        if (surfaceId >= kMaxOutputs) {
+            return BAD_VALUE;
+        }
+        outUniqueIds->push_back(mSurfaceUniqueIds[surfaceId].second);
+    }
+    return OK;
+}
+
 status_t Camera3SharedOutputStream::revertPartialUpdateLocked(
         const KeyedVector<sp<Surface>, size_t> &removedSurfaces,
         const KeyedVector<sp<Surface>, size_t> &attachedSurfaces) {
@@ -284,7 +348,7 @@
                 return UNKNOWN_ERROR;
             }
         }
-        mSurfaces[index] = nullptr;
+        mSurfaceUniqueIds[index] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
     }
 
     for (size_t i = 0; i < removedSurfaces.size(); i++) {
@@ -295,7 +359,8 @@
                 return UNKNOWN_ERROR;
             }
         }
-        mSurfaces[index] = removedSurfaces.keyAt(i);
+        mSurfaceUniqueIds[index] = std::make_pair(
+                removedSurfaces.keyAt(i), mNextUniqueSurfaceId++);
     }
 
     return ret;
@@ -347,8 +412,8 @@
 
             }
         }
-        mSurfaces[it] = nullptr;
-        removedSurfaces.add(mSurfaces[it], it);
+        removedSurfaces.add(mSurfaceUniqueIds[it].first, it);
+        mSurfaceUniqueIds[it] = std::make_pair(nullptr, mNextUniqueSurfaceId++);
     }
 
     //Next add the new outputs
@@ -373,7 +438,7 @@
                 return ret;
             }
         }
-        mSurfaces[surfaceId] = it;
+        mSurfaceUniqueIds[surfaceId] = std::make_pair(it, mNextUniqueSurfaceId++);
         outputMap->add(it, surfaceId);
     }
 
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 02b1c09..b5e37c2 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA3_SHARED_OUTPUT_STREAM_H
 #define ANDROID_SERVERS_CAMERA3_SHARED_OUTPUT_STREAM_H
 
+#include <array>
 #include "Camera3StreamSplitter.h"
 #include "Camera3OutputStream.h"
 
@@ -37,7 +38,8 @@
             uint64_t consumerUsage, android_dataspace dataSpace,
             camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
             const String8& physicalCameraId,
-            int setId = CAMERA3_STREAM_SET_ID_INVALID);
+            int setId = CAMERA3_STREAM_SET_ID_INVALID,
+            bool useHalBufManager = false);
 
     virtual ~Camera3SharedOutputStream();
 
@@ -49,6 +51,15 @@
 
     virtual ssize_t getSurfaceId(const sp<Surface> &surface);
 
+    /**
+     * Query the unique surface IDs of current surfaceIds.
+     * When passing unique surface IDs in returnBuffer(), if the
+     * surfaceId has been removed from the stream, the output corresponding to
+     * the unique surface ID will be ignored and not delivered to client.
+     */
+    virtual status_t getUniqueSurfaceIds(const std::vector<size_t>& surfaceIds,
+            /*out*/std::vector<size_t>* outUniqueIds) override;
+
     virtual status_t updateStream(const std::vector<sp<Surface>> &outputSurfaces,
             const std::vector<OutputStreamInfo> &outputInfo,
             const std::vector<size_t> &removedSurfaceIds,
@@ -58,8 +69,17 @@
 
     static const size_t kMaxOutputs = 4;
 
-    // Map surfaceId -> output surfaces
-    sp<Surface> mSurfaces[kMaxOutputs];
+    // Whether HAL is in control for buffer management. Surface sharing behavior
+    // depends on this flag.
+    const bool mUseHalBufManager;
+
+    // Pair of an output Surface and its unique ID
+    typedef std::pair<sp<Surface>, size_t> SurfaceUniqueId;
+
+    // Map surfaceId -> (output surface, unique surface ID)
+    std::array<SurfaceUniqueId, kMaxOutputs> mSurfaceUniqueIds;
+
+    size_t mNextUniqueSurfaceId = 0;
 
     ssize_t getNextSurfaceIdLocked();
 
@@ -78,13 +98,24 @@
     status_t connectStreamSplitterLocked();
 
     /**
+     * Attach the output buffer to stream splitter.
+     * When camera service is doing buffer management, this method will be called
+     * before the buffer is handed out to HAL in request thread.
+     * When HAL is doing buffer management, this method will be called when
+     * the buffer is returned from HAL in hwbinder callback thread.
+     */
+    status_t attachBufferToSplitterLocked(ANativeWindowBuffer* anb,
+            const std::vector<size_t>& surface_ids);
+
+    /**
      * Internal Camera3Stream interface
      */
     virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
             const std::vector<size_t>& surface_ids);
 
     virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
-            ANativeWindowBuffer* buffer, int anwReleaseFence);
+            ANativeWindowBuffer* buffer, int anwReleaseFence,
+            const std::vector<size_t>& uniqueSurfaceIds);
 
     virtual status_t configureQueueLocked();
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 0a30a97..24d1c1b 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -655,7 +655,8 @@
 }
 
 status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
-        nsecs_t timestamp, bool timestampIncreasing) {
+        nsecs_t timestamp, bool timestampIncreasing,
+         const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
@@ -684,7 +685,7 @@
      *
      * Do this for getBuffer as well.
      */
-    status_t res = returnBufferLocked(b, timestamp);
+    status_t res = returnBufferLocked(b, timestamp, surface_ids);
     if (res == OK) {
         fireBufferListenersLocked(b, /*acquired*/false, /*output*/true);
     }
@@ -843,7 +844,7 @@
     return INVALID_OPERATION;
 }
 status_t Camera3Stream::returnBufferLocked(const camera3_stream_buffer &,
-                                           nsecs_t) {
+                                           nsecs_t, const std::vector<size_t>&) {
     ALOGE("%s: This type of stream does not support output", __FUNCTION__);
     return INVALID_OPERATION;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index e29c3e0..ddba9f6 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -322,11 +322,17 @@
     /**
      * Return a buffer to the stream after use by the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to attach
+     * buffers for those surfaces.
+     *
      * This method may only be called for buffers provided by getBuffer().
      * For bidirectional streams, this method applies to the output-side buffers
      */
     status_t         returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp, bool timestampIncreasing);
+            nsecs_t timestamp, bool timestampIncreasing,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
@@ -478,7 +484,8 @@
     virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
             const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp);
+            nsecs_t timestamp,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
     virtual status_t returnInputBufferLocked(
             const camera3_stream_buffer &buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 866b722..a84720b 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -248,11 +248,18 @@
     /**
      * Return a buffer to the stream after use by the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to attach
+     * buffers for those surfaces. For the case of single surface for a HAL
+     * stream, surface_ids parameter has no effect.
+     *
      * This method may only be called for buffers provided by getBuffer().
      * For bidirectional streams, this method applies to the output-side buffers
      */
     virtual status_t returnBuffer(const camera3_stream_buffer &buffer,
-            nsecs_t timestamp, bool timestampIncreasing = true) = 0;
+            nsecs_t timestamp, bool timestampIncreasing = true,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
 
     /**
      * Fill in the camera3_stream_buffer with the next valid buffer for this
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 8bc208d..13a1567 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -150,6 +150,8 @@
     SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
+Camera3StreamSplitter::Camera3StreamSplitter(bool useHalBufManager) :
+        mUseHalBufManager(useHalBufManager) {}
 
 Camera3StreamSplitter::~Camera3StreamSplitter() {
     disconnect();
@@ -237,7 +239,9 @@
     uint64_t usage = 0;
     res = native_window_get_consumer_usage(static_cast<ANativeWindow*>(outputQueue.get()), &usage);
     if (!(usage & (GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE))) {
-        outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
+        nsecs_t timeout = mUseHalBufManager ?
+                kHalBufMgrDequeueBufferTimeout : kNormalDequeueBufferTimeout;
+        outputQueue->setDequeueTimeout(timeout);
     }
 
     res = gbp->allowAllocation(false);
@@ -430,8 +434,9 @@
         res = gbp->attachBuffer(&slot, gb);
         mMutex.lock();
         if (res != OK) {
-            SP_LOGE("%s: Cannot acquireBuffer from GraphicBufferProducer %p: %s (%d)",
+            SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)",
                     __FUNCTION__, gbp.get(), strerror(-res), res);
+            // TODO: might need to detach/cleanup the already attached buffers before return?
             return res;
         }
         if ((slot < 0) || (slot > BufferQueue::NUM_BUFFER_SLOTS)) {
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index fea1bdb..8c7181c 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -49,7 +49,7 @@
 public:
 
     // Constructor
-    Camera3StreamSplitter() = default;
+    Camera3StreamSplitter(bool useHalBufManager = false);
 
     // Connect to the stream splitter by creating buffer queue and connecting it
     // with output surfaces.
@@ -226,7 +226,10 @@
     android::PixelFormat mFormat = android::PIXEL_FORMAT_NONE;
     uint64_t mProducerUsage = 0;
 
-    static const nsecs_t kDequeueBufferTimeout   = s2ns(1); // 1 sec
+    // The attachBuffer call will happen on different thread according to mUseHalBufManager and have
+    // different timing constraint.
+    static const nsecs_t kNormalDequeueBufferTimeout    = s2ns(1);  // 1 sec
+    static const nsecs_t kHalBufMgrDequeueBufferTimeout = ms2ns(1); // 1 msec
 
     Mutex mMutex;
 
@@ -270,6 +273,8 @@
     std::atomic<status_t> mOnFrameAvailableRes{0};
 
     String8 mConsumerName;
+
+    const bool mUseHalBufManager;
 };
 
 } // namespace android