Merge "Camera3: Fix the deadlock during recording pinch zooming" into jb-mr2-dev
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 6f4f4c8..1d38993 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -1329,6 +1329,10 @@
 
     // Finally, dispatch any 3A change events to listeners if we got metadata
 
+    if (result->result != NULL) {
+        mResultSignal.signal();
+    }
+
     if (result->result != NULL && listener != NULL) {
         if (new3aState.aeState != cur3aState.aeState) {
             ALOGVV("%s: AE state changed from 0x%x to 0x%x",
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp
index 49fc3d8..a248b76 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/camera2/Parameters.cpp
@@ -795,13 +795,21 @@
     previewCallbackFlags = 0;
     previewCallbackOneShot = false;
 
-    char value[PROPERTY_VALUE_MAX];
-    property_get("camera.disable_zsl_mode", value, "0");
-    if (!strcmp(value,"1")) {
-        ALOGI("Camera %d: Disabling ZSL mode", cameraId);
+    camera_metadata_ro_entry_t supportedHardwareLevel =
+        staticInfo(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+    if (!supportedHardwareLevel.count || (supportedHardwareLevel.data.u8[0] ==
+            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)) {
+        ALOGI("Camera %d: ZSL mode disabled for limited mode HALs", cameraId);
         zslMode = false;
     } else {
-        zslMode = true;
+        char value[PROPERTY_VALUE_MAX];
+        property_get("camera.disable_zsl_mode", value, "0");
+        if (!strcmp(value,"1")) {
+            ALOGI("Camera %d: Disabling ZSL mode", cameraId);
+            zslMode = false;
+        } else {
+            zslMode = true;
+        }
     }
 
     lightFx = LIGHTFX_NONE;
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
index 257a45f..4012fc5 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
@@ -93,6 +93,9 @@
     status_t res;
     ATRACE_CALL();
     CameraMetadata frame;
+
+    ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId());
+
     while ( (res = device->getNextFrame(&frame)) == OK) {
 
         camera_metadata_entry_t entry;
@@ -124,6 +127,8 @@
 
 bool ProFrameProcessor::processSingleFrame(CameraMetadata &frame,
                                            const sp<CameraDeviceBase> &device) {
+    ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
+          __FUNCTION__, device->getId(), frame.isEmpty());
     return processListeners(frame, device) == OK;
 }
 
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
index e2c120c..2e06691 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
@@ -373,9 +373,15 @@
 
     size_t idx = 0;
     nsecs_t minTimestamp = -1;
+
+    size_t emptyCount = mFrameList.size();
+
     for (size_t j = 0; j < mFrameList.size(); j++) {
         const CameraMetadata &frame = mFrameList[j];
         if (!frame.isEmpty()) {
+
+            emptyCount--;
+
             camera_metadata_ro_entry_t entry;
             entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
             if (entry.count == 0) {
@@ -387,7 +393,12 @@
             if (minTimestamp > frameTimestamp || minTimestamp == -1) {
 
                 entry = frame.find(ANDROID_CONTROL_AE_STATE);
+
                 if (entry.count == 0) {
+                    /**
+                     * This is most likely a HAL bug. The aeState field is
+                     * mandatory, so it should always be in a metadata packet.
+                     */
                     ALOGW("%s: ZSL queue frame has no AE state field!",
                             __FUNCTION__);
                     continue;
@@ -402,9 +413,30 @@
                 minTimestamp = frameTimestamp;
                 idx = j;
             }
+
+            ALOGVV("%s: Saw timestamp %lld", __FUNCTION__, frameTimestamp);
         }
     }
 
+    if (emptyCount == mFrameList.size()) {
+        /**
+         * This could be mildly bad and means our ZSL was triggered before
+         * there were any frames yet received by the camera framework.
+         *
+         * This is a fairly corner case which can happen under:
+         * + a user presses the shutter button real fast when the camera starts
+         *     (startPreview followed immediately by takePicture).
+         * + burst capture case (hitting shutter button as fast possible)
+         *
+         * If this happens in steady case (preview running for a while, call
+         *     a single takePicture) then this might be a fwk bug.
+         */
+        ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
+    }
+
+    ALOGV("%s: Candidate timestamp %lld (idx %d), empty frames: %d",
+          __FUNCTION__, minTimestamp, idx, emptyCount);
+
     if (metadataIdx) {
         *metadataIdx = idx;
     }
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 2fa78a4..cd39bad 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -101,12 +101,6 @@
 
     } // end scope of mMutex autolock
 
-    if (pinnedBuffer != 0) {
-        BI_LOGV("Pinned buffer frame %lld, timestamp %lld",
-                pinnedBuffer->getBufferItem().mFrameNumber,
-                pinnedBuffer->getBufferItem().mTimestamp);
-    }
-
     if (waitForFence) {
         status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
                 "RingBufferConsumer::pinSelectedBuffer");
@@ -172,6 +166,9 @@
     if (it == end) {
         BI_LOGE("Failed to pin buffer (timestamp %lld, framenumber %lld)",
                  item.mTimestamp, item.mFrameNumber);
+    } else {
+        BI_LOGV("Pinned buffer (frame %lld, timestamp %lld)",
+                item.mFrameNumber, item.mTimestamp);
     }
 }
 
@@ -182,7 +179,7 @@
 
     it = mBufferItemList.begin();
     end = mBufferItemList.end();
-    accIt = it;
+    accIt = end;
 
     if (it == end) {
         /**
@@ -197,12 +194,17 @@
 
     for (; it != end; ++it) {
         RingBufferItem& find = *it;
-        if (find.mTimestamp < accIt->mTimestamp && find.mPinCount <= 0) {
-            accIt = it;
+
+        if (find.mPinCount > 0) {
+            if (pinnedFrames != NULL) {
+                ++(*pinnedFrames);
+            }
+            // Filter out pinned frame when searching for buffer to release
+            continue;
         }
 
-        if (find.mPinCount > 0 && pinnedFrames != NULL) {
-            ++(*pinnedFrames);
+        if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
+            accIt = it;
         }
     }
 
@@ -323,7 +325,11 @@
     }
 
     if (it == end) {
-        BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld",
+        // This should never happen. If it happens, we have a bug.
+        BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld)",
+                 item.mTimestamp, item.mFrameNumber);
+    } else {
+        BI_LOGV("Unpinned buffer (timestamp %lld, framenumber %lld)",
                  item.mTimestamp, item.mFrameNumber);
     }
 }