Merge "audioflinger: fix pre processing effect leak" into lmp-dev
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index d8ed836..511871d 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1176,12 +1176,14 @@
 void NuPlayer::GenericSource::readBuffer(
         media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
     Track *track;
+    size_t maxBuffers = 1;
     switch (trackType) {
         case MEDIA_TRACK_TYPE_VIDEO:
             track = &mVideoTrack;
             break;
         case MEDIA_TRACK_TYPE_AUDIO:
             track = &mAudioTrack;
+            maxBuffers = 64;
             break;
         case MEDIA_TRACK_TYPE_SUBTITLE:
             track = &mSubtitleTrack;
@@ -1214,7 +1216,7 @@
         options.setNonBlocking();
     }
 
-    for (;;) {
+    for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
         MediaBuffer *mbuf;
         status_t err = track->mSource->read(&mbuf, &options);
 
@@ -1245,7 +1247,7 @@
 
             sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
             track->mPackets->queueAccessUnit(buffer);
-            break;
+            ++numBuffers;
         } else if (err == WOULD_BLOCK) {
             break;
         } else if (err == INFO_FORMAT_CHANGED) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index df3e992..9020a8d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -50,6 +50,10 @@
 
 namespace android {
 
+// TODO optimize buffer size for power consumption
+// The offload read buffer size is 32 KB but 24 KB uses less power.
+const size_t NuPlayer::kAggregateBufferSizeBytes = 24 * 1024;
+
 struct NuPlayer::Action : public RefBase {
     Action() {}
 
@@ -730,7 +734,7 @@
 
                 if (err == -EWOULDBLOCK) {
                     if (mSource->feedMoreTSData() == OK) {
-                        msg->post(10000ll);
+                        msg->post(10 * 1000ll);
                     }
                 }
             } else if (what == Decoder::kWhatEOS) {
@@ -995,6 +999,7 @@
     ALOGV("both audio and video are flushed now.");
 
     mPendingAudioAccessUnit.clear();
+    mAggregateBuffer.clear();
 
     if (mTimeDiscontinuityPending) {
         mRenderer->signalTimeDiscontinuity();
@@ -1256,14 +1261,8 @@
     // Aggregate smaller buffers into a larger buffer.
     // The goal is to reduce power consumption.
     // Unfortunately this does not work with the software AAC decoder.
-    // TODO optimize buffer size for power consumption
-    // The offload read buffer size is 32 KB but 24 KB uses less power.
-    const int kAudioBigBufferSizeBytes = 24 * 1024;
-    bool doBufferAggregation = (audio && mOffloadAudio);
-    sp<ABuffer> biggerBuffer;
+    bool doBufferAggregation = (audio && mOffloadAudio);;
     bool needMoreData = false;
-    int numSmallBuffers = 0;
-    bool gotTime = false;
 
     bool dropAccessUnit;
     do {
@@ -1279,14 +1278,10 @@
         }
 
         if (err == -EWOULDBLOCK) {
-            if (biggerBuffer == NULL) {
-                return err;
-            } else {
-                break; // Reply with data that we already have.
-            }
+            return err;
         } else if (err != OK) {
             if (err == INFO_DISCONTINUITY) {
-                if (biggerBuffer != NULL) {
+                if (mAggregateBuffer != NULL) {
                     // We already have some data so save this for later.
                     mPendingAudioErr = err;
                     mPendingAudioAccessUnit = accessUnit;
@@ -1401,46 +1396,45 @@
 
         size_t smallSize = accessUnit->size();
         needMoreData = false;
-        if (doBufferAggregation && (biggerBuffer == NULL)
+        if (doBufferAggregation && (mAggregateBuffer == NULL)
                 // Don't bother if only room for a few small buffers.
-                && (smallSize < (kAudioBigBufferSizeBytes / 3))) {
+                && (smallSize < (kAggregateBufferSizeBytes / 3))) {
             // Create a larger buffer for combining smaller buffers from the extractor.
-            biggerBuffer = new ABuffer(kAudioBigBufferSizeBytes);
-            biggerBuffer->setRange(0, 0); // start empty
+            mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
+            mAggregateBuffer->setRange(0, 0); // start empty
         }
 
-        if (biggerBuffer != NULL) {
+        if (mAggregateBuffer != NULL) {
             int64_t timeUs;
+            int64_t dummy;
             bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs);
+            bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy);
             // Will the smaller buffer fit?
-            size_t bigSize = biggerBuffer->size();
-            size_t roomLeft = biggerBuffer->capacity() - bigSize;
+            size_t bigSize = mAggregateBuffer->size();
+            size_t roomLeft = mAggregateBuffer->capacity() - bigSize;
             // Should we save this small buffer for the next big buffer?
             // If the first small buffer did not have a timestamp then save
             // any buffer that does have a timestamp until the next big buffer.
             if ((smallSize > roomLeft)
-                || (!gotTime && (numSmallBuffers > 0) && smallTimestampValid)) {
+                || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) {
                 mPendingAudioErr = err;
                 mPendingAudioAccessUnit = accessUnit;
                 accessUnit.clear();
             } else {
+                // Grab time from first small buffer if available.
+                if ((bigSize == 0) && smallTimestampValid) {
+                    mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
+                }
                 // Append small buffer to the bigger buffer.
-                memcpy(biggerBuffer->base() + bigSize, accessUnit->data(), smallSize);
+                memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
                 bigSize += smallSize;
-                biggerBuffer->setRange(0, bigSize);
+                mAggregateBuffer->setRange(0, bigSize);
 
-                // Keep looping until we run out of room in the biggerBuffer.
+                // Keep looping until we run out of room in the mAggregateBuffer.
                 needMoreData = true;
 
-                // Grab time from first small buffer if available.
-                if ((numSmallBuffers == 0) && smallTimestampValid) {
-                    biggerBuffer->meta()->setInt64("timeUs", timeUs);
-                    gotTime = true;
-                }
-
-                ALOGV("feedDecoderInputData() #%d, smallSize = %zu, bigSize = %zu, capacity = %zu",
-                        numSmallBuffers, smallSize, bigSize, biggerBuffer->capacity());
-                numSmallBuffers++;
+                ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu",
+                        smallSize, bigSize, mAggregateBuffer->capacity());
             }
         }
     } while (dropAccessUnit || needMoreData);
@@ -1459,9 +1453,11 @@
         mCCDecoder->decode(accessUnit);
     }
 
-    if (biggerBuffer != NULL) {
-        ALOGV("feedDecoderInputData() reply with aggregated buffer, %d", numSmallBuffers);
-        reply->setBuffer("buffer", biggerBuffer);
+    if (mAggregateBuffer != NULL) {
+        ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu",
+                mAggregateBuffer->size());
+        reply->setBuffer("buffer", mAggregateBuffer);
+        mAggregateBuffer.clear();
     } else {
         reply->setBuffer("buffer", accessUnit);
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 89ae11c..2e951bd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -67,6 +67,8 @@
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select);
 
+    static const size_t kAggregateBufferSizeBytes;
+
 protected:
     virtual ~NuPlayer();
 
@@ -158,8 +160,11 @@
     // notion of time has changed.
     bool mTimeDiscontinuityPending;
 
+    // Used by feedDecoderInputData to aggregate small buffers into
+    // one large buffer.
     sp<ABuffer> mPendingAudioAccessUnit;
     status_t    mPendingAudioErr;
+    sp<ABuffer> mAggregateBuffer;
 
     FlushStatus mFlushingAudio;
     FlushStatus mFlushingVideo;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index ab7906a..f7aacdd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -30,8 +30,10 @@
 
 namespace android {
 
-static const int kMaxPendingBuffers = 10;
-static const int kMaxCachedBytes = 200000;
+static const size_t kMaxCachedBytes = 200000;
+// The buffers will contain a bit less than kAggregateBufferSizeBytes.
+// So we can start off with just enough buffers to keep the cache full.
+static const size_t kMaxPendingBuffers = 1 + (kMaxCachedBytes / NuPlayer::kAggregateBufferSizeBytes);
 
 NuPlayer::DecoderPassThrough::DecoderPassThrough(
         const sp<AMessage> &notify)
@@ -39,7 +41,8 @@
       mNotify(notify),
       mBufferGeneration(0),
       mReachedEOS(true),
-      mPendingBuffers(0),
+      mPendingBuffersToFill(0),
+      mPendingBuffersToDrain(0),
       mCachedBytes(0),
       mComponentName("pass through decoder") {
     mDecoderLooper = new ALooper;
@@ -79,12 +82,13 @@
 
 void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
     ALOGV("[%s] onConfigure", mComponentName.c_str());
-    mPendingBuffers = 0;
     mCachedBytes = 0;
+    mPendingBuffersToFill = 0;
+    mPendingBuffersToDrain = 0;
     mReachedEOS = false;
     ++mBufferGeneration;
 
-    requestABuffer();
+    requestMaxBuffers();
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatOutputFormatChanged);
@@ -98,12 +102,15 @@
     return generation != mBufferGeneration;
 }
 
-void NuPlayer::DecoderPassThrough::requestABuffer() {
-    if (mCachedBytes >= kMaxCachedBytes || mReachedEOS) {
-        ALOGV("[%s] mReachedEOS=%d, max pending buffers(%d:%d)",
-                mComponentName.c_str(), (mReachedEOS ? 1 : 0),
-                mPendingBuffers, kMaxPendingBuffers);
-        return;
+bool NuPlayer::DecoderPassThrough::requestABuffer() {
+    if (mCachedBytes >= kMaxCachedBytes) {
+        ALOGV("[%s] mCachedBytes = %zu",
+                mComponentName.c_str(), mCachedBytes);
+        return false;
+    }
+    if (mReachedEOS) {
+        ALOGV("[%s] reached EOS", mComponentName.c_str());
+        return false;
     }
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
@@ -113,19 +120,16 @@
     notify->setInt32("what", kWhatFillThisBuffer);
     notify->setMessage("reply", reply);
     notify->post();
-    mPendingBuffers++;
+    mPendingBuffersToFill++;
+    ALOGV("requestABuffer: #ToFill = %zu, #ToDrain = %zu", mPendingBuffersToFill,
+            mPendingBuffersToDrain);
 
-    // pending buffers will already result in requestABuffer
-    if (mPendingBuffers < kMaxPendingBuffers) {
-        sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
-        message->setInt32("generation", mBufferGeneration);
-        message->post();
-    }
-    return;
+    return true;
 }
 
 void android::NuPlayer::DecoderPassThrough::onInputBufferFilled(
         const sp<AMessage> &msg) {
+    --mPendingBuffersToFill;
     if (mReachedEOS) {
         return;
     }
@@ -153,11 +157,16 @@
     notify->setBuffer("buffer", buffer);
     notify->setMessage("reply", reply);
     notify->post();
+    ++mPendingBuffersToDrain;
+    ALOGV("onInputBufferFilled: #ToFill = %zu, #ToDrain = %zu, cachedBytes = %zu",
+            mPendingBuffersToFill, mPendingBuffersToDrain, mCachedBytes);
 }
 
 void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) {
-    mPendingBuffers--;
+    --mPendingBuffersToDrain;
     mCachedBytes -= size;
+    ALOGV("onBufferConsumed: #ToFill = %zu, #ToDrain = %zu, cachedBytes = %zu",
+           mPendingBuffersToFill, mPendingBuffersToDrain, mCachedBytes);
     requestABuffer();
 }
 
@@ -167,11 +176,20 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatFlushCompleted);
     notify->post();
-    mPendingBuffers = 0;
+    mPendingBuffersToFill = 0;
+    mPendingBuffersToDrain = 0;
     mCachedBytes = 0;
     mReachedEOS = false;
 }
 
+void NuPlayer::DecoderPassThrough::requestMaxBuffers() {
+    for (size_t i = 0; i < kMaxPendingBuffers; i++) {
+        if (!requestABuffer()) {
+            break;
+        }
+    }
+}
+
 void NuPlayer::DecoderPassThrough::onShutdown() {
     ++mBufferGeneration;
 
@@ -229,7 +247,7 @@
 
         case kWhatResume:
         {
-            requestABuffer();
+            requestMaxBuffers();
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 8590856..fb20257 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -55,19 +55,26 @@
     sp<AMessage> mNotify;
     sp<ALooper> mDecoderLooper;
 
-    void requestABuffer();
+    /** Returns true if a buffer was requested.
+     * Returns false if at EOS or cache already full.
+     */
+    bool requestABuffer();
     bool isStaleReply(const sp<AMessage> &msg);
 
     void onConfigure(const sp<AMessage> &format);
     void onFlush();
     void onInputBufferFilled(const sp<AMessage> &msg);
     void onBufferConsumed(int32_t size);
+    void requestMaxBuffers();
     void onShutdown();
 
     int32_t mBufferGeneration;
-    bool mReachedEOS;
-    int32_t mPendingBuffers;
-    int32_t mCachedBytes;
+    bool    mReachedEOS;
+    // TODO mPendingBuffersToFill and mPendingBuffersToDrain are only for
+    // debugging. They can be removed when the power investigation is done.
+    size_t  mPendingBuffersToFill;
+    size_t  mPendingBuffersToDrain;
+    size_t  mCachedBytes;
     AString mComponentName;
 
     DISALLOW_EVIL_CONSTRUCTORS(DecoderPassThrough);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9cfbe6a..e200857 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -803,9 +803,14 @@
     }
 
     AutoMutex lock(mHardwareLock);
-    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
-    ret = dev->set_mic_mute(dev, state);
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+        status_t result = dev->set_mic_mute(dev, state);
+        if (result != NO_ERROR) {
+            ret = result;
+        }
+    }
     mHardwareStatus = AUDIO_HW_IDLE;
     return ret;
 }
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index abdbc5c..d5f6c1e 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -3670,8 +3670,11 @@
 
 void AudioPolicyManager::checkOutputForAllStrategies()
 {
-    checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+    if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
     checkOutputForStrategy(STRATEGY_PHONE);
+    if (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
     checkOutputForStrategy(STRATEGY_SONIFICATION);
     checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
     checkOutputForStrategy(STRATEGY_MEDIA);
@@ -3752,23 +3755,28 @@
     }
 
     // check the following by order of priority to request a routing change if necessary:
-    // 1: the strategy enforced audible is active on the output:
+    // 1: the strategy enforced audible is active and enforced on the output:
     //      use device for strategy enforced audible
     // 2: we are in call or the strategy phone is active on the output:
     //      use device for strategy phone
-    // 3: the strategy sonification is active on the output:
+    // 3: the strategy for enforced audible is active but not enforced on the output:
+    //      use the device for strategy enforced audible
+    // 4: the strategy sonification is active on the output:
     //      use device for strategy sonification
-    // 4: the strategy "respectful" sonification is active on the output:
+    // 5: the strategy "respectful" sonification is active on the output:
     //      use device for strategy "respectful" sonification
-    // 5: the strategy media is active on the output:
+    // 6: the strategy media is active on the output:
     //      use device for strategy media
-    // 6: the strategy DTMF is active on the output:
+    // 7: the strategy DTMF is active on the output:
     //      use device for strategy DTMF
-    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE) &&
+        mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
         device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (isInCall() ||
                     outputDesc->isStrategyActive(STRATEGY_PHONE)) {
         device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
     } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
         device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
     } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index ed9137f..aa9d746 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -983,6 +983,13 @@
     bool fixedLens = minFocusDistance.count == 0 ||
         minFocusDistance.data.f[0] == 0;
 
+    camera_metadata_ro_entry_t focusDistanceCalibration =
+            staticInfo(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, 0, 0,
+                    false);
+    bool canFocusInfinity = (focusDistanceCalibration.count &&
+            focusDistanceCalibration.data.u8[0] !=
+            ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED);
+
     camera_metadata_ro_entry_t availableFocalLengths =
         staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
     if (!availableFocalLengths.count) return NO_INIT;
@@ -1033,6 +1040,13 @@
                     sceneModeOverrides.data.u8[i * kModesPerSceneMode + 2];
             switch(afMode) {
                 case ANDROID_CONTROL_AF_MODE_OFF:
+                    if (!fixedLens && !canFocusInfinity) {
+                        ALOGE("%s: Camera %d: Scene mode override lists asks for"
+                                " fixed focus on a device with focuser but not"
+                                " calibrated for infinity focus", __FUNCTION__,
+                                cameraId);
+                        return NO_INIT;
+                    }
                     modes.focusMode = fixedLens ?
                             FOCUS_MODE_FIXED : FOCUS_MODE_INFINITY;
                     break;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index fa65b74..de31e23 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -244,6 +244,46 @@
     return mZslStreamId;
 }
 
+status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+    sp<Camera2Client> client = mClient.promote();
+    if (client == 0) {
+        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+    sp<Camera3Device> device =
+        static_cast<Camera3Device*>(client->getCameraDevice().get());
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    CameraMetadata stillTemplate;
+    device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+    // Find some of the post-processing tags, and assign the value from template to the request.
+    // Only check the aberration mode and noise reduction mode for now, as they are very important
+    // for image quality.
+    uint32_t postProcessingTags[] = {
+            ANDROID_NOISE_REDUCTION_MODE,
+            ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+            ANDROID_COLOR_CORRECTION_MODE,
+            ANDROID_TONEMAP_MODE,
+            ANDROID_SHADING_MODE,
+            ANDROID_HOT_PIXEL_MODE,
+            ANDROID_EDGE_MODE
+    };
+
+    camera_metadata_entry_t entry;
+    for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+        entry = stillTemplate.find(postProcessingTags[i]);
+        if (entry.count > 0) {
+            request.update(postProcessingTags[i], entry.data.u8, 1);
+        }
+    }
+
+    return OK;
+}
+
 status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
     ALOGV("%s: Send in reprocess request with id %d",
             __FUNCTION__, requestId);
@@ -369,6 +409,13 @@
             }
         }
 
+        // Update post-processing settings
+        res = updateRequestWithDefaultStillRequest(request);
+        if (res != OK) {
+            ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+                    "may be compromised", __FUNCTION__);
+        }
+
         mLatestCapturedRequest = request;
         res = client->getCameraDevice()->capture(request);
         if (res != OK ) {
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
index 2975f7c..fc9f70c 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
@@ -135,6 +135,9 @@
     nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
 
     bool isFixedFocusMode(uint8_t afMode) const;
+
+    // Update the post-processing metadata with the default still capture request template
+    status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
 };
 
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index fafe349..6a7f9e7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1044,6 +1044,11 @@
             return INVALID_OPERATION;
     }
 
+    if (!mRequestTemplateCache[templateId].isEmpty()) {
+        *request = mRequestTemplateCache[templateId];
+        return OK;
+    }
+
     const camera_metadata_t *rawRequest;
     ATRACE_BEGIN("camera3->construct_default_request_settings");
     rawRequest = mHal3Device->ops->construct_default_request_settings(
@@ -1055,6 +1060,7 @@
         return DEAD_OBJECT;
     }
     *request = rawRequest;
+    mRequestTemplateCache[templateId] = rawRequest;
 
     return OK;
 }
@@ -1086,6 +1092,10 @@
 
     ALOGV("%s: Camera %d: Waiting until idle", __FUNCTION__, mId);
     status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+    if (res != OK) {
+        SET_ERR_L("Error waiting for HAL to drain: %s (%d)", strerror(-res),
+                res);
+    }
     return res;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index b99ed7e..ec6bba1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -174,6 +174,8 @@
 
     CameraMetadata             mDeviceInfo;
 
+    CameraMetadata             mRequestTemplateCache[CAMERA3_TEMPLATE_COUNT];
+
     uint32_t                   mDeviceVersion;
 
     enum Status {