DO NOT MERGE QCamera3: Fix Easel HDR+ mode after flush

Reset mFirstPreviewIntentSeen in flush if HAL intends to restart the
channel after flush. Without this, Easel HDR+ mode will not be
enabled after flush, unless a new session is configured.

Create a HDR+ client listener handling thread to avoid handling
HDR+ client callbacks in HAL in the callback thread, which may lead
to deadlocks.

Test: Camera CTS
Bug: 67112292
Bug: 65448794
Change-Id: I3f1ad5d6a610b8e0f21e476c49906b461d8c36b2
(cherry picked from commit 6316489bf55ba033c035bcdf044e3cb48996fb31)
diff --git a/msm8998/QCamera2/Android.mk b/msm8998/QCamera2/Android.mk
index e8a6811..184d9bc 100755
--- a/msm8998/QCamera2/Android.mk
+++ b/msm8998/QCamera2/Android.mk
@@ -30,6 +30,7 @@
 
 #HAL 3.0 source
 LOCAL_SRC_FILES += \
+        HAL3/QCamera3HdrPlusListenerThread.cpp \
         HAL3/QCamera3HWI.cpp \
         HAL3/QCamera3Mem.cpp \
         HAL3/QCamera3Stream.cpp \
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
index 69fe2cc..85d14b7 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
@@ -915,6 +915,14 @@
                 return rc;
             }
             mEaselFwUpdated = false;
+
+            mQCamera3HdrPlusListenerThread = new QCamera3HdrPlusListenerThread(this);
+            rc = mQCamera3HdrPlusListenerThread->run("QCamera3HdrPlusListenerThread");
+            if (rc != OK) {
+                ALOGE("%s: Starting HDR+ client listener thread failed: %s (%d)", __FUNCTION__,
+                        strerror(-rc), rc);
+                return rc;
+            }
         }
     }
 
@@ -934,6 +942,10 @@
                             strerror(-suspendErr), suspendErr);
                 }
             }
+
+            mQCamera3HdrPlusListenerThread->requestExit();
+            mQCamera3HdrPlusListenerThread->join();
+            mQCamera3HdrPlusListenerThread = nullptr;
         }
     }
 
@@ -1129,6 +1141,10 @@
                 ALOGE("%s: Suspending Easel failed: %s (%d)", __FUNCTION__, strerror(-rc), rc);
             }
         }
+
+        mQCamera3HdrPlusListenerThread->requestExit();
+        mQCamera3HdrPlusListenerThread->join();
+        mQCamera3HdrPlusListenerThread = nullptr;
     }
 
     return rc;
@@ -6430,6 +6446,7 @@
                 return rc;
             }
         }
+        mFirstPreviewIntentSeen = false;
     }
     pthread_mutex_unlock(&mMutex);
 
@@ -15189,7 +15206,7 @@
         return OK;
     }
 
-    status_t res = gEaselManagerClient->openHdrPlusClientAsync(this);
+    status_t res = gEaselManagerClient->openHdrPlusClientAsync(mQCamera3HdrPlusListenerThread.get());
     if (res != OK) {
         ALOGE("%s: Opening HDR+ client asynchronously failed: %s (%d)", __FUNCTION__,
                 strerror(-res), res);
@@ -15772,25 +15789,20 @@
             streamBuffer.acquire_fence = -1;
             streamBuffer.release_fence = -1;
 
-            streamBuffers.push_back(streamBuffer);
-
             // Send out error buffer event.
             camera3_notify_msg_t notify_msg = {};
             notify_msg.type = CAMERA3_MSG_ERROR;
             notify_msg.message.error.frame_number = pendingBuffers->frame_number;
-            notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_BUFFER;
+            notify_msg.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
             notify_msg.message.error.error_stream = buffer.stream;
 
             orchestrateNotify(&notify_msg);
+            mOutputBufferDispatcher.markBufferReady(pendingBuffers->frame_number, streamBuffer);
         }
 
-        camera3_capture_result_t result = {};
-        result.frame_number = pendingBuffers->frame_number;
-        result.num_output_buffers = streamBuffers.size();
-        result.output_buffers = &streamBuffers[0];
+        mShutterDispatcher.clear(pendingBuffers->frame_number);
 
-        // Send out result with buffer errors.
-        orchestrateResult(&result);
+
 
         // Remove pending buffers.
         mPendingBuffersMap.mPendingBuffersInRequest.erase(pendingBuffers);
@@ -15809,7 +15821,6 @@
     pthread_mutex_unlock(&mMutex);
 }
 
-
 ShutterDispatcher::ShutterDispatcher(QCamera3HardwareInterface *parent) :
         mParent(parent) {}
 
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.h b/msm8998/QCamera2/HAL3/QCamera3HWI.h
index 4eaf8a8..c10c724 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.h
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.h
@@ -47,6 +47,7 @@
 #include "QCameraCommon.h"
 #include "QCamera3VendorTags.h"
 #include "QCameraDualCamSettings.h"
+#include "QCamera3HdrPlusListenerThread.h"
 
 #include "EaselManagerClient.h"
 #include "HdrPlusClient.h"
@@ -894,6 +895,9 @@
     int32_t mSceneDistance;
 
     std::future<void> mEaselErrorFuture;
+
+    // Thread to handle callbacks from HDR+ client. Protected by gHdrPlusClientLock.
+    sp<QCamera3HdrPlusListenerThread> mQCamera3HdrPlusListenerThread;
 };
 
 }; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
new file mode 100644
index 0000000..355d970
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QCamera3HdrPlusListenerThread.h"
+
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+QCamera3HdrPlusListenerThread::QCamera3HdrPlusListenerThread(
+        HdrPlusClientListener *listener) : mListener(listener), mExitRequested(false),
+        mFatalError(false)
+{
+}
+
+QCamera3HdrPlusListenerThread::~QCamera3HdrPlusListenerThread()
+{
+    requestExit();
+}
+
+void QCamera3HdrPlusListenerThread::onOpened(std::unique_ptr<HdrPlusClient> client)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mClient != nullptr) {
+        ALOGW("%s: An old client exists and will be destroyed.", __FUNCTION__);
+    }
+    mClient = std::move(client);
+    mPendingCallbacks.push(CALLBACK_TYPE_OPENED);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onOpenFailed(status_t err)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mOpenError != OK) {
+        ALOGW("%s: An old open failure exists and will be ignored: %s (%d)", __FUNCTION__,
+                strerror(-mOpenError), mOpenError);
+    }
+    mOpenError = err;
+    mPendingCallbacks.push(CALLBACK_TYPE_OPENFAILED);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFatalError()
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    if (mFatalError) {
+        ALOGW("%s: An old fatal failure exists.", __FUNCTION__);
+    }
+    mFatalError = true;
+    mPendingCallbacks.push(CALLBACK_TYPE_FATAL_ERROR);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onCaptureResult(pbcamera::CaptureResult *result,
+            const camera_metadata_t &resultMetadata)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingResult pendingResult = {};
+    pendingResult.result = *result;
+    pendingResult.metadata = clone_camera_metadata(&resultMetadata);
+    pendingResult.isFailed = false;
+    mResults.push(pendingResult);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onFailedCaptureResult(pbcamera::CaptureResult *failedResult)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingResult result = {};
+    result.result = *failedResult;
+    result.metadata = nullptr;
+    result.isFailed = true;
+    mResults.push(result);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_CAPTURE_RESULT);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onShutter(uint32_t requestId, int64_t apSensorTimestampNs)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    std::pair<uint32_t, int64_t> shutter(requestId, apSensorTimestampNs);
+    mShutters.push(shutter);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_SHUTTER);
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::onNextCaptureReady(uint32_t requestId)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    mNextCaptureReadyIds.push(requestId);
+
+    mPendingCallbacks.push(CALLBACK_TYPE_NEXT_CAPTURE_READY);
+    mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::onPostview(uint32_t requestId,
+        std::unique_ptr<std::vector<uint8_t>> postview, uint32_t width, uint32_t height,
+        uint32_t stride, int32_t format)
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+
+    PendingPostview pendingPostview = {};
+    pendingPostview.requestId = requestId;
+    pendingPostview.postview = std::move(postview);
+    pendingPostview.width = width;
+    pendingPostview.height = height;
+    pendingPostview.stride = stride;
+    pendingPostview.format = format;
+    mPostviews.push(std::move(pendingPostview));
+
+    mPendingCallbacks.push(CALLBACK_TYPE_POSTVIEW);
+    mCallbackCond.notify_one();
+
+}
+
+void QCamera3HdrPlusListenerThread::requestExit()
+{
+    std::unique_lock<std::mutex> l(mCallbackLock);
+    mExitRequested = true;
+    mCallbackCond.notify_one();
+}
+
+void QCamera3HdrPlusListenerThread::handleFatalError()
+{
+    bool fatalError;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (!mFatalError) {
+            ALOGW("%s: There is no fatal error.", __FUNCTION__);
+            return;
+        }
+
+        fatalError = mFatalError;
+    }
+
+    mListener->onFatalError();
+}
+
+void QCamera3HdrPlusListenerThread::handlePendingClient()
+{
+    std::unique_ptr<HdrPlusClient> client;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (mClient == nullptr) {
+            ALOGW("%s: There is no pending client.", __FUNCTION__);
+            return;
+        }
+
+        client = std::move(mClient);
+    }
+
+    mListener->onOpened(std::move(client));
+}
+
+void QCamera3HdrPlusListenerThread::handleOpenError()
+{
+    status_t err = OK;
+    {
+        std::unique_lock<std::mutex> lock(mCallbackLock);
+        if (mOpenError == OK) {
+            ALOGW("%s: There is no pending open failure.", __FUNCTION__);
+            return;
+        }
+
+        err = mOpenError;
+        mOpenError = OK;
+    }
+
+    mListener->onOpenFailed(err);
+}
+
+void QCamera3HdrPlusListenerThread::handleNextCaptureReady()
+{
+    uint32_t requestId = 0;
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mNextCaptureReadyIds.size() == 0) {
+            ALOGW("%s: There is no NextCaptureReady.", __FUNCTION__);
+            return;
+        }
+        requestId = mNextCaptureReadyIds.front();
+        mNextCaptureReadyIds.pop();
+    }
+    mListener->onNextCaptureReady(requestId);
+}
+
+void QCamera3HdrPlusListenerThread::handleCaptureResult()
+{
+    PendingResult result = {};
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mResults.size() == 0) {
+            ALOGW("%s: There is no capture result.", __FUNCTION__);
+            return;
+        }
+        result = mResults.front();
+        mResults.pop();
+    }
+
+    if (result.isFailed) {
+        mListener->onFailedCaptureResult(&result.result);
+    } else {
+        mListener->onCaptureResult(&result.result, *result.metadata);
+    }
+}
+
+void QCamera3HdrPlusListenerThread::handleShutter()
+{
+    uint32_t requestId;
+    int64_t apSensorTimestampNs;
+
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mShutters.size() == 0) {
+            ALOGW("%s: There is no shutter.", __FUNCTION__);
+            return;;
+        }
+
+        auto shutter = mShutters.front();
+        requestId = shutter.first;
+        apSensorTimestampNs = shutter.second;
+        mShutters.pop();
+    }
+
+    mListener->onShutter(requestId, apSensorTimestampNs);
+}
+
+void QCamera3HdrPlusListenerThread::handlePostview()
+{
+    PendingPostview postview = {};
+
+    {
+        std::unique_lock<std::mutex> l(mCallbackLock);
+        if (mPostviews.size() == 0) {
+            ALOGW("%s: There is no postview.", __FUNCTION__);
+            return;;
+        }
+
+        postview = std::move(mPostviews.front());
+        mPostviews.pop();
+    }
+
+    mListener->onPostview(postview.requestId, std::move(postview.postview), postview.width,
+            postview.height, postview.stride, postview.format);
+}
+
+bool QCamera3HdrPlusListenerThread::threadLoop()
+{
+    if (mListener == nullptr) {
+        ALOGE("%s: mListener is nullptr.", __FUNCTION__);
+        return false;
+    }
+
+    while (1) {
+        CallbackType nextCallback;
+
+        {
+            std::unique_lock<std::mutex> lock(mCallbackLock);
+            if (!mExitRequested && mPendingCallbacks.size() == 0) {
+                mCallbackCond.wait(lock,
+                        [&] { return mExitRequested || mPendingCallbacks.size() > 0; });
+            }
+
+            if (mExitRequested) {
+                return false;
+            } else {
+                nextCallback = mPendingCallbacks.front();
+                mPendingCallbacks.pop();
+            }
+        }
+
+        switch (nextCallback) {
+            case CALLBACK_TYPE_OPENED:
+                handlePendingClient();
+                break;
+            case CALLBACK_TYPE_OPENFAILED:
+                handleOpenError();
+                break;
+            case CALLBACK_TYPE_FATAL_ERROR:
+                handleFatalError();
+                break;
+            case CALLBACK_TYPE_CAPTURE_RESULT:
+                handleCaptureResult();
+                break;
+            case CALLBACK_TYPE_SHUTTER:
+                handleShutter();
+                break;
+            case CALLBACK_TYPE_NEXT_CAPTURE_READY:
+                handleNextCaptureReady();
+                break;
+            case CALLBACK_TYPE_POSTVIEW:
+                handlePostview();
+                break;
+            default:
+                ALOGE("%s: Unknown callback type %d", __FUNCTION__, nextCallback);
+                break;
+        }
+    }
+
+    return false;
+}
+
+}; // namespace qcamera
diff --git a/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
new file mode 100644
index 0000000..e64de36
--- /dev/null
+++ b/msm8998/QCamera2/HAL3/QCamera3HdrPlusListenerThread.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+#define __HDRPLUSCLIENTLISTENERHANDLERTHREAD__
+
+// System dependencies
+#include <utils/Thread.h>
+#include <queue>
+
+#include "EaselManagerClient.h"
+#include "HdrPlusClient.h"
+
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using namespace android;
+
+namespace qcamera {
+
+/*
+ * A thread to handle callbacks from HDR+ client. When a callback from HDR+ client is invoked,
+ * HDR+ client callback thread will return and the threadloop of QCamera3HdrPlusListenerThread
+ * will call the callback handlers in QCamera3HWI, to avoid deadlock in HDR+ client callback thread.
+ */
+class QCamera3HdrPlusListenerThread : public HdrPlusClientListener, public Thread
+{
+public:
+    // listener is an HdrPlusClientListener to forward the callbacks in the thread loop.
+    QCamera3HdrPlusListenerThread(HdrPlusClientListener *listener);
+    virtual ~QCamera3HdrPlusListenerThread();
+
+    // Request the thread to exit.
+    void requestExit() override;
+
+private:
+    // HDR+ client callbacks.
+    void onOpened(std::unique_ptr<HdrPlusClient> client) override;
+    void onOpenFailed(status_t err) override;
+    void onFatalError() override;
+    void onCaptureResult(pbcamera::CaptureResult *result,
+            const camera_metadata_t &resultMetadata) override;
+    void onFailedCaptureResult(pbcamera::CaptureResult *failedResult) override;
+    void onShutter(uint32_t requestId, int64_t apSensorTimestampNs) override;
+    void onNextCaptureReady(uint32_t requestId) override;
+    void onPostview(uint32_t requestId, std::unique_ptr<std::vector<uint8_t>> postview,
+            uint32_t width, uint32_t height, uint32_t stride, int32_t format) override;
+
+    bool threadLoop() override;
+
+    // The following functions handle the pending callbacks by calling the callback handlers
+    // in QCamera3HWI.
+    bool hasPendingEventsLocked();
+    void handlePendingClient();
+    void handleNextCaptureReady();
+    void handleCaptureResult();
+    void handleFatalError();
+    void handleOpenError();
+    void handleShutter();
+    void handlePostview();
+
+    struct PendingResult {
+        pbcamera::CaptureResult result;
+        camera_metadata_t *metadata;
+        bool isFailed;
+    };
+
+    struct PendingPostview {
+        uint32_t requestId;
+        std::unique_ptr<std::vector<uint8_t>> postview;
+        uint32_t width;
+        uint32_t height;
+        uint32_t stride;
+        int32_t format;
+    };
+
+    enum CallbackType {
+        CALLBACK_TYPE_OPENED = 0,
+        CALLBACK_TYPE_OPENFAILED,
+        CALLBACK_TYPE_FATAL_ERROR,
+        CALLBACK_TYPE_CAPTURE_RESULT,
+        CALLBACK_TYPE_SHUTTER,
+        CALLBACK_TYPE_NEXT_CAPTURE_READY,
+        CALLBACK_TYPE_POSTVIEW,
+    };
+
+    HdrPlusClientListener *mListener;
+
+    std::mutex mCallbackLock;
+
+    // Condition for a new callback. Protected by mCallbackLock.
+    std::condition_variable mCallbackCond;
+    // If exit has been requested. Protected by mCallbackLock.
+    bool mExitRequested;
+
+    // The following variables store pending callbacks. Protected by mCallbackLock.
+    std::unique_ptr<HdrPlusClient> mClient;
+    std::queue<uint32_t> mNextCaptureReadyIds;
+    std::queue<PendingResult> mResults;
+    bool mFatalError;
+    status_t mOpenError;
+    std::queue<std::pair<uint32_t, int64_t>> mShutters;
+    std::queue<PendingPostview> mPostviews;
+
+    // A queue of pending callback types, in the same order as invoked by HDR+ client.
+    // Protected by mCallbackLock.
+    std::queue<CallbackType> mPendingCallbacks;
+};
+
+}; // namespace qcamera
+
+#endif /* __HDRPLUSCLIENTLISTENERHANDLERTHREAD__ */
\ No newline at end of file