Merge "CameraService: fix waitUntilIdle bug revealed by TestingCamera2."
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index a39d837..1663d47 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -16,7 +16,8 @@
 
 #define LOG_TAG "EffectDownmix"
 //#define LOG_NDEBUG 0
-#include <cutils/log.h>
+#include <log/log.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
@@ -99,7 +100,7 @@
 // strictly for testing, logs the indices of the channels for a given mask,
 // uses the same code as Downmix_foldGeneric()
 void Downmix_testIndexComputation(uint32_t mask) {
-    ALOGI("Testing index computation for 0x%x:", mask);
+    ALOGI("Testing index computation for 0x%" PRIx32 ":", mask);
     // check against unsupported channels
     if (mask & kUnsupported) {
         ALOGE("Unsupported channels (top or front left/right of center)");
@@ -220,7 +221,7 @@
 
     *pHandle = (effect_handle_t) module;
 
-    ALOGV("DownmixLib_Create() %p , size %d", module, sizeof(downmix_module_t));
+    ALOGV("DownmixLib_Create() %p , size %zu", module, sizeof(downmix_module_t));
 
     return 0;
 }
@@ -254,7 +255,7 @@
         ALOGV("DownmixLib_GetDescriptor() i=%d", i);
         if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
             memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
-            ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %x",
+            ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %" PRIx32,
                  i, gDescriptors[i]->uuid.timeLow);
             return 0;
         }
@@ -328,7 +329,7 @@
           // bypass the optimized downmix routines for the common formats
           if (!Downmix_foldGeneric(
                   downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
-              ALOGE("Multichannel configuration 0x%x is not supported", downmixInputChannelMask);
+              ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask);
               return -EINVAL;
           }
           break;
@@ -352,7 +353,7 @@
         default:
             if (!Downmix_foldGeneric(
                     downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
-                ALOGE("Multichannel configuration 0x%x is not supported", downmixInputChannelMask);
+                ALOGE("Multichannel configuration 0x%" PRIx32 " is not supported", downmixInputChannelMask);
                 return -EINVAL;
             }
             break;
@@ -380,7 +381,7 @@
 
     pDownmixer = (downmix_object_t*) &pDwmModule->context;
 
-    ALOGV("Downmix_Command command %d cmdSize %d",cmdCode, cmdSize);
+    ALOGV("Downmix_Command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
 
     switch (cmdCode) {
     case EFFECT_CMD_INIT:
@@ -404,7 +405,7 @@
         break;
 
     case EFFECT_CMD_GET_PARAM:
-        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %d, pReplyData: %p",
+        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %" PRIu32 ", pReplyData: %p",
                 pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
                 pReplyData == NULL ||
@@ -413,7 +414,7 @@
         }
         effect_param_t *rep = (effect_param_t *) pReplyData;
         memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
-        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %d, replySize %d",
+        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %" PRId32 ", replySize %" PRIu32,
                 *(int32_t *)rep->data, rep->vsize);
         rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize,
                 rep->data + sizeof(int32_t));
@@ -421,8 +422,8 @@
         break;
 
     case EFFECT_CMD_SET_PARAM:
-        ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, " \
-                "pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
+        ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %" PRIu32
+                ", pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
                 || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
             return -EINVAL;
@@ -471,7 +472,7 @@
             return -EINVAL;
         }
         // FIXME change type if playing on headset vs speaker
-        ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08x", *(uint32_t *)pCmdData);
+        ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08" PRIx32, *(uint32_t *)pCmdData);
         break;
 
     case EFFECT_CMD_SET_VOLUME: {
@@ -491,7 +492,7 @@
         if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
             return -EINVAL;
         }
-        ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %d", *(uint32_t *)pCmdData);
+        ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %" PRIu32, *(uint32_t *)pCmdData);
         break;
 
     case EFFECT_CMD_SET_CONFIG_REVERSE:
@@ -500,7 +501,7 @@
         break;
 
     default:
-        ALOGW("Downmix_Command invalid command %d",cmdCode);
+        ALOGW("Downmix_Command invalid command %" PRIu32, cmdCode);
         return -EINVAL;
     }
 
@@ -702,28 +703,28 @@
 int Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, uint32_t size, void *pValue) {
 
     int16_t value16;
-    ALOGV("Downmix_setParameter, context %p, param %d, value16 %d, value32 %d",
+    ALOGV("Downmix_setParameter, context %p, param %" PRId32 ", value16 %" PRId16 ", value32 %" PRId32,
             pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue);
 
     switch (param) {
 
       case DOWNMIX_PARAM_TYPE:
         if (size != sizeof(downmix_type_t)) {
-            ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %u, should be %zu",
+            ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %" PRIu32 ", should be %zu",
                     size, sizeof(downmix_type_t));
             return -EINVAL;
         }
         value16 = *(int16_t *)pValue;
-        ALOGV("set DOWNMIX_PARAM_TYPE, type %d", value16);
+        ALOGV("set DOWNMIX_PARAM_TYPE, type %" PRId16, value16);
         if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) {
-            ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %d", value16);
+            ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %" PRId16, value16);
             return -EINVAL;
         } else {
             pDownmixer->type = (downmix_type_t) value16;
         break;
 
       default:
-        ALOGE("Downmix_setParameter unknown parameter %d", param);
+        ALOGE("Downmix_setParameter unknown parameter %" PRId32, param);
         return -EINVAL;
     }
 }
@@ -762,17 +763,17 @@
 
     case DOWNMIX_PARAM_TYPE:
       if (*pSize < sizeof(int16_t)) {
-          ALOGE("Downmix_getParameter invalid parameter size %zu for DOWNMIX_PARAM_TYPE", *pSize);
+          ALOGE("Downmix_getParameter invalid parameter size %" PRIu32 " for DOWNMIX_PARAM_TYPE", *pSize);
           return -EINVAL;
       }
       pValue16 = (int16_t *)pValue;
       *pValue16 = (int16_t) pDownmixer->type;
       *pSize = sizeof(int16_t);
-      ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %d", *pValue16);
+      ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %" PRId16, *pValue16);
       break;
 
     default:
-      ALOGE("Downmix_getParameter unknown parameter %d", param);
+      ALOGE("Downmix_getParameter unknown parameter %" PRId16, param);
       return -EINVAL;
     }
 
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 5bdaa03..47cab62 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -16,8 +16,9 @@
 
 #define LOG_TAG "EffectVisualizer"
 //#define LOG_NDEBUG 0
-#include <cutils/log.h>
+#include <log/log.h>
 #include <assert.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <new>
@@ -226,8 +227,8 @@
 //
 
 int VisualizerLib_Create(const effect_uuid_t *uuid,
-                         int32_t sessionId,
-                         int32_t ioId,
+                         int32_t /*sessionId*/,
+                         int32_t /*ioId*/,
                          effect_handle_t *pHandle) {
     int ret;
     int i;
@@ -418,7 +419,7 @@
         return -EINVAL;
     }
 
-//    ALOGV("Visualizer_command command %d cmdSize %d",cmdCode, cmdSize);
+//    ALOGV("Visualizer_command command %" PRIu32 " cmdSize %" PRIu32, cmdCode, cmdSize);
 
     switch (cmdCode) {
     case EFFECT_CMD_INIT:
@@ -484,19 +485,19 @@
         }
         switch (*(uint32_t *)p->data) {
         case VISUALIZER_PARAM_CAPTURE_SIZE:
-            ALOGV("get mCaptureSize = %d", pContext->mCaptureSize);
+            ALOGV("get mCaptureSize = %" PRIu32, pContext->mCaptureSize);
             *((uint32_t *)p->data + 1) = pContext->mCaptureSize;
             p->vsize = sizeof(uint32_t);
             *replySize += sizeof(uint32_t);
             break;
         case VISUALIZER_PARAM_SCALING_MODE:
-            ALOGV("get mScalingMode = %d", pContext->mScalingMode);
+            ALOGV("get mScalingMode = %" PRIu32, pContext->mScalingMode);
             *((uint32_t *)p->data + 1) = pContext->mScalingMode;
             p->vsize = sizeof(uint32_t);
             *replySize += sizeof(uint32_t);
             break;
         case VISUALIZER_PARAM_MEASUREMENT_MODE:
-            ALOGV("get mMeasurementMode = %d", pContext->mMeasurementMode);
+            ALOGV("get mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
             *((uint32_t *)p->data + 1) = pContext->mMeasurementMode;
             p->vsize = sizeof(uint32_t);
             *replySize += sizeof(uint32_t);
@@ -520,19 +521,19 @@
         switch (*(uint32_t *)p->data) {
         case VISUALIZER_PARAM_CAPTURE_SIZE:
             pContext->mCaptureSize = *((uint32_t *)p->data + 1);
-            ALOGV("set mCaptureSize = %d", pContext->mCaptureSize);
+            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
             break;
         case VISUALIZER_PARAM_SCALING_MODE:
             pContext->mScalingMode = *((uint32_t *)p->data + 1);
-            ALOGV("set mScalingMode = %d", pContext->mScalingMode);
+            ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
             break;
         case VISUALIZER_PARAM_LATENCY:
             pContext->mLatency = *((uint32_t *)p->data + 1);
-            ALOGV("set mLatency = %d", pContext->mLatency);
+            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
             break;
         case VISUALIZER_PARAM_MEASUREMENT_MODE:
             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
-            ALOGV("set mMeasurementMode = %d", pContext->mMeasurementMode);
+            ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
             break;
         default:
             *(int32_t *)pReplyData = -EINVAL;
@@ -545,9 +546,9 @@
 
 
     case VISUALIZER_CMD_CAPTURE: {
-        int32_t captureSize = pContext->mCaptureSize;
+        uint32_t captureSize = pContext->mCaptureSize;
         if (pReplyData == NULL || *replySize != captureSize) {
-            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d captureSize %d",
+            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32,
                     *replySize, captureSize);
             return -EINVAL;
         }
@@ -573,7 +574,7 @@
                 int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
 
                 if (capturePoint < 0) {
-                    int32_t size = -capturePoint;
+                    uint32_t size = -capturePoint;
                     if (size > captureSize) {
                         size = captureSize;
                     }
@@ -604,7 +605,7 @@
         // measurements aren't relevant anymore and shouldn't bias the new one)
         const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
         if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) {
-            ALOGV("Discarding measurements, last measurement is %dms old", delayMs);
+            ALOGV("Discarding measurements, last measurement is %" PRId32 "ms old", delayMs);
             for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
                 pContext->mPastMeasurements[i].mIsValid = false;
                 pContext->mPastMeasurements[i].mPeakU16 = 0;
@@ -638,14 +639,14 @@
         } else {
             pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f));
         }
-        ALOGV("VISUALIZER_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)",
+        ALOGV("VISUALIZER_CMD_MEASURE peak=%" PRIu16 " (%" PRId32 "mB), rms=%.1f (%" PRId32 "mB)",
                 peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK],
                 rms, pIntReplyData[MEASUREMENT_IDX_RMS]);
         }
         break;
 
     default:
-        ALOGW("Visualizer_command invalid command %d",cmdCode);
+        ALOGW("Visualizer_command invalid command %" PRIu32, cmdCode);
         return -EINVAL;
     }
 
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index fcd825f..f2d501e 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -197,64 +197,64 @@
 
 void AString::append(int x) {
     char s[16];
-    sprintf(s, "%d", x);
-
+    int result = snprintf(s, sizeof(s), "%d", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(unsigned x) {
     char s[16];
-    sprintf(s, "%u", x);
-
+    int result = snprintf(s, sizeof(s), "%u", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(long x) {
-    char s[16];
-    sprintf(s, "%ld", x);
-
+    char s[32];
+    int result = snprintf(s, sizeof(s), "%ld", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(unsigned long x) {
-    char s[16];
-    sprintf(s, "%lu", x);
-
+    char s[32];
+    int result = snprintf(s, sizeof(s), "%lu", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(long long x) {
     char s[32];
-    sprintf(s, "%lld", x);
-
+    int result = snprintf(s, sizeof(s), "%lld", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(unsigned long long x) {
     char s[32];
-    sprintf(s, "%llu", x);
-
+    int result = snprintf(s, sizeof(s), "%llu", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(float x) {
     char s[16];
-    sprintf(s, "%f", x);
-
+    int result = snprintf(s, sizeof(s), "%f", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(double x) {
     char s[16];
-    sprintf(s, "%f", x);
-
+    int result = snprintf(s, sizeof(s), "%f", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
 void AString::append(void *x) {
-    char s[16];
-    sprintf(s, "%p", x);
-
+    char s[32];
+    int result = snprintf(s, sizeof(s), "%p", x);
+    CHECK((result > 0) && ((size_t) result) < sizeof(s));
     append(s);
 }
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 3df57b4..16f6c58 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -29,6 +29,8 @@
 #include <media/hardware/MetadataBufferType.h>
 #include <ui/GraphicBuffer.h>
 
+#include <inttypes.h>
+
 namespace android {
 
 static const bool EXTRA_CHECK = true;
@@ -763,13 +765,13 @@
 void GraphicBufferSource::onBuffersReleased() {
     Mutex::Autolock lock(mMutex);
 
-    uint32_t slotMask;
+    uint64_t slotMask;
     if (mConsumer->getReleasedBuffers(&slotMask) != NO_ERROR) {
         ALOGW("onBuffersReleased: unable to get released buffer set");
-        slotMask = 0xffffffff;
+        slotMask = 0xffffffffffffffffULL;
     }
 
-    ALOGV("onBuffersReleased: 0x%08x", slotMask);
+    ALOGV("onBuffersReleased: 0x%016" PRIx64, slotMask);
 
     for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         if ((slotMask & 0x01) != 0) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 25e97f3..729020b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -681,6 +681,8 @@
     }
     mInputStream = newStream;
 
+    mNeedConfig = true;
+
     *id = mNextStreamId++;
     *zslStream = newStream;
 
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 2257682..50a2c10 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -34,7 +34,8 @@
         Camera3Stream(id, type,
                 width, height, maxSize, format),
         mTotalBufferCount(0),
-        mDequeuedBufferCount(0),
+        mHandoutTotalBufferCount(0),
+        mHandoutOutputBufferCount(0),
         mFrameCount(0),
         mLastTimestamp(0) {
 
@@ -55,8 +56,8 @@
     nsecs_t signalTime = mCombinedFence->getSignalTime();
     ALOGV("%s: Stream %d: Has %zu outstanding buffers,"
             " buffer signal time is %" PRId64,
-            __FUNCTION__, mId, mDequeuedBufferCount, signalTime);
-    if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) {
+            __FUNCTION__, mId, mHandoutTotalBufferCount, signalTime);
+    if (mHandoutTotalBufferCount > 0 || signalTime == INT64_MAX) {
         return true;
     }
     return false;
@@ -75,7 +76,7 @@
     lines.appendFormat("      Frames produced: %d, last timestamp: %" PRId64 " ns\n",
             mFrameCount, mLastTimestamp);
     lines.appendFormat("      Total buffers: %zu, currently dequeued: %zu\n",
-            mTotalBufferCount, mDequeuedBufferCount);
+            mTotalBufferCount, mHandoutTotalBufferCount);
     write(fd, lines.string(), lines.size());
 }
 
@@ -104,6 +105,14 @@
     return mTotalBufferCount;
 }
 
+size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() {
+    return mHandoutOutputBufferCount;
+}
+
+size_t Camera3IOStreamBase::getHandoutInputBufferCountLocked() {
+    return (mHandoutTotalBufferCount - mHandoutOutputBufferCount);
+}
+
 status_t Camera3IOStreamBase::disconnectLocked() {
     switch (mState) {
         case STATE_IN_RECONFIG:
@@ -117,9 +126,9 @@
             return -ENOTCONN;
     }
 
-    if (mDequeuedBufferCount > 0) {
+    if (mHandoutTotalBufferCount > 0) {
         ALOGE("%s: Can't disconnect with %zu buffers still dequeued!",
-                __FUNCTION__, mDequeuedBufferCount);
+                __FUNCTION__, mHandoutTotalBufferCount);
         return INVALID_OPERATION;
     }
 
@@ -130,7 +139,8 @@
                                               buffer_handle_t *handle,
                                               int acquireFence,
                                               int releaseFence,
-                                              camera3_buffer_status_t status) {
+                                              camera3_buffer_status_t status,
+                                              bool output) {
     /**
      * Note that all fences are now owned by HAL.
      */
@@ -144,7 +154,7 @@
     buffer.status = status;
 
     // Inform tracker about becoming busy
-    if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+    if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG &&
             mState != STATE_IN_RECONFIG) {
         /**
          * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers
@@ -158,7 +168,11 @@
             statusTracker->markComponentActive(mStatusId);
         }
     }
-    mDequeuedBufferCount++;
+    mHandoutTotalBufferCount++;
+
+    if (output) {
+        mHandoutOutputBufferCount++;
+    }
 }
 
 status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const {
@@ -172,7 +186,7 @@
 
     // Only limit dequeue amount when fully configured
     if (mState == STATE_CONFIGURED &&
-            mDequeuedBufferCount == camera3_stream::max_buffers) {
+            mHandoutTotalBufferCount == camera3_stream::max_buffers) {
         ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous"
                 " buffers (%d)", __FUNCTION__, mId,
                 camera3_stream::max_buffers);
@@ -190,7 +204,7 @@
                 __FUNCTION__, mId, mState);
         return INVALID_OPERATION;
     }
-    if (mDequeuedBufferCount == 0) {
+    if (mHandoutTotalBufferCount == 0) {
         ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__,
                 mId);
         return INVALID_OPERATION;
@@ -228,8 +242,12 @@
         mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);
     }
 
-    mDequeuedBufferCount--;
-    if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+    if (output) {
+        mHandoutOutputBufferCount--;
+    }
+
+    mHandoutTotalBufferCount--;
+    if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG &&
             mState != STATE_IN_RECONFIG) {
         /**
          * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index fcb9d04..a35c290 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -48,7 +48,10 @@
   protected:
     size_t            mTotalBufferCount;
     // sum of input and output buffers that are currently acquired by HAL
-    size_t            mDequeuedBufferCount;
+    size_t            mHandoutTotalBufferCount;
+    // number of output buffers that are currently acquired by HAL. This will be
+    // Redundant when camera3 streams are no longer bidirectional streams.
+    size_t            mHandoutOutputBufferCount;
     Condition         mBufferReturnedSignal;
     uint32_t          mFrameCount;
     // Last received output buffer's timestamp
@@ -76,6 +79,10 @@
 
     virtual size_t   getBufferCountLocked();
 
+    virtual size_t   getHandoutOutputBufferCountLocked();
+
+    virtual size_t   getHandoutInputBufferCountLocked();
+
     virtual status_t getEndpointUsage(uint32_t *usage) = 0;
 
     status_t getBufferPreconditionCheckLocked() const;
@@ -92,7 +99,8 @@
                              buffer_handle_t *handle,
                              int acquire_fence,
                              int release_fence,
-                             camera3_buffer_status_t status);
+                             camera3_buffer_status_t status,
+                             bool output);
 
 }; // class Camera3IOStreamBase
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index dd7fb6c..319be1d 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -81,7 +81,7 @@
      * in which case we reassign it to acquire_fence
      */
     handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
-                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
     mBuffersInFlight.push_back(bufferItem);
 
     return OK;
@@ -199,7 +199,7 @@
     assert(mMaxSize == 0);
     assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB);
 
-    mDequeuedBufferCount = 0;
+    mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
 
     if (mConsumer.get() == 0) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 682755d..7ec649b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -119,7 +119,7 @@
      * in which case we reassign it to acquire_fence
      */
     handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
-                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
 
     return OK;
 }
@@ -324,7 +324,7 @@
     }
 
     mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers;
-    mDequeuedBufferCount = 0;
+    mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
     mLastTimestamp = 0;
 
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 646f286..abfb602 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -212,8 +212,30 @@
 status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
+    status_t res = OK;
 
-    status_t res = getBufferLocked(buffer);
+    // This function should be only called when the stream is configured already.
+    if (mState != STATE_CONFIGURED) {
+        ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d",
+                __FUNCTION__, mId, mState);
+        return INVALID_OPERATION;
+    }
+
+    // Wait for new buffer returned back if we are running into the limit.
+    if (getHandoutOutputBufferCountLocked() == camera3_stream::max_buffers) {
+        ALOGV("%s: Already dequeued max output buffers (%d), wait for next returned one.",
+                __FUNCTION__, camera3_stream::max_buffers);
+        res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
+        if (res != OK) {
+            if (res == TIMED_OUT) {
+                ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__,
+                        kWaitForBufferDuration / 1000000LL);
+            }
+            return res;
+        }
+    }
+
+    res = getBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
     }
@@ -237,6 +259,7 @@
     status_t res = returnBufferLocked(buffer, timestamp);
     if (res == OK) {
         fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true);
+        mOutputBufferReturnedSignal.signal();
     }
 
     return res;
@@ -245,8 +268,30 @@
 status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
+    status_t res = OK;
 
-    status_t res = getInputBufferLocked(buffer);
+    // This function should be only called when the stream is configured already.
+    if (mState != STATE_CONFIGURED) {
+        ALOGE("%s: Stream %d: Can't get input buffers if stream is not in CONFIGURED state %d",
+                __FUNCTION__, mId, mState);
+        return INVALID_OPERATION;
+    }
+
+    // Wait for new buffer returned back if we are running into the limit.
+    if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) {
+        ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.",
+                __FUNCTION__, camera3_stream::max_buffers);
+        res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
+        if (res != OK) {
+            if (res == TIMED_OUT) {
+                ALOGE("%s: wait for input buffer return timed out after %lldms", __FUNCTION__,
+                        kWaitForBufferDuration / 1000000LL);
+            }
+            return res;
+        }
+    }
+
+    res = getInputBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false);
     }
@@ -261,6 +306,7 @@
     status_t res = returnInputBufferLocked(buffer);
     if (res == OK) {
         fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false);
+        mInputBufferReturnedSignal.signal();
     }
     return res;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 766b772..14f5387 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -279,6 +279,12 @@
     // Get the total number of buffers in the queue
     virtual size_t   getBufferCountLocked() = 0;
 
+    // Get handout output buffer count.
+    virtual size_t   getHandoutOutputBufferCountLocked() = 0;
+
+    // Get handout input buffer count.
+    virtual size_t   getHandoutInputBufferCountLocked() = 0;
+
     // Get the usage flags for the other endpoint, or return
     // INVALID_OPERATION if they cannot be obtained.
     virtual status_t getEndpointUsage(uint32_t *usage) = 0;
@@ -291,6 +297,9 @@
   private:
     uint32_t oldUsage;
     uint32_t oldMaxBuffers;
+    Condition mOutputBufferReturnedSignal;
+    Condition mInputBufferReturnedSignal;
+    static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms
 
     // Gets all buffers from endpoint and registers them with the HAL.
     status_t registerBuffersLocked(camera3_device *hal3Device);
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 09e14c5..05b3d1f 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -176,7 +176,7 @@
      * in which case we reassign it to acquire_fence
      */
     handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
-                         /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+                         /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
 
     mBuffersInFlight.push_back(bufferItem);