Camera API 2, Device 2/3: Implement idle and shutter callbacks

- Update callback Binder interface
- Rename frameId to be requestId to be consistent and disambiguate
  from frameNumber.
- Implement shutter callback from HAL2/3 notify()
  - Add in-flight tracking to HAL2
  - Add requestId to in-flight tracking
  - Report requestId from shutter callback
- Implement idle callback from HAL3 process_capture_result
  - Add new idle tracker thread
  - Update all idle waiting to use the tracker
  - Add reporting from request thread, all streams to tracker
  - Remove existing idle waiting infrastructure

Bug: 10549462
Change-Id: I867bfc248e3848c50e71527e3561fe92dc037958
diff --git a/services/camera/libcameraservice/device3/StatusTracker.cpp b/services/camera/libcameraservice/device3/StatusTracker.cpp
new file mode 100644
index 0000000..ab5419f
--- /dev/null
+++ b/services/camera/libcameraservice/device3/StatusTracker.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "Camera3-Status"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+// This is needed for stdint.h to define INT64_MAX in C++
+#define __STDC_LIMIT_MACROS
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <ui/Fence.h>
+
+#include "device3/StatusTracker.h"
+#include "device3/Camera3Device.h"
+
+namespace android {
+
+namespace camera3 {
+
+StatusTracker::StatusTracker(wp<Camera3Device> parent) :
+        mComponentsChanged(false),
+        mParent(parent),
+        mNextComponentId(0),
+        mIdleFence(new Fence()),
+        mDeviceState(IDLE) {
+}
+
+StatusTracker::~StatusTracker() {
+}
+
+int StatusTracker::addComponent() {
+    int id;
+    ssize_t err;
+    {
+        Mutex::Autolock l(mLock);
+        id = mNextComponentId++;
+        ALOGV("%s: Adding new component %d", __FUNCTION__, id);
+
+        err = mStates.add(id, IDLE);
+        ALOGE_IF(err < 0, "%s: Can't add new component %d: %s (%d)",
+                __FUNCTION__, id, strerror(-err), err);
+    }
+
+    if (err >= 0) {
+        Mutex::Autolock pl(mPendingLock);
+        mComponentsChanged = true;
+        mPendingChangeSignal.signal();
+    }
+
+    return err < 0 ? err : id;
+}
+
+void StatusTracker::removeComponent(int id) {
+    ssize_t idx;
+    {
+        Mutex::Autolock l(mLock);
+        ALOGV("%s: Removing component %d", __FUNCTION__, id);
+        idx = mStates.removeItem(id);
+    }
+
+    if (idx >= 0) {
+        Mutex::Autolock pl(mPendingLock);
+        mComponentsChanged = true;
+        mPendingChangeSignal.signal();
+    }
+
+    return;
+}
+
+
+void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
+    markComponent(id, IDLE, componentFence);
+}
+
+void StatusTracker::markComponentActive(int id) {
+    markComponent(id, ACTIVE, Fence::NO_FENCE);
+}
+
+void StatusTracker::markComponent(int id, ComponentState state,
+        const sp<Fence>& componentFence) {
+    ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
+            state == IDLE ? "idle" : "active");
+    Mutex::Autolock l(mPendingLock);
+
+    StateChange newState = {
+        id,
+        state,
+        componentFence
+    };
+
+    mPendingChangeQueue.add(newState);
+    mPendingChangeSignal.signal();
+}
+
+void StatusTracker::requestExit() {
+    // First mark thread dead
+    Thread::requestExit();
+    // Then exit any waits
+    mPendingChangeSignal.signal();
+}
+
+StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
+    for (size_t i = 0; i < mStates.size(); i++) {
+        if (mStates.valueAt(i) == ACTIVE) {
+            ALOGV("%s: Component %d not idle", __FUNCTION__,
+                    mStates.keyAt(i));
+            return ACTIVE;
+        }
+    }
+    // - If not yet signaled, getSignalTime returns INT64_MAX
+    // - If invalid fence or error, returns -1
+    // - Otherwise returns time of signalling.
+    // Treat -1 as 'signalled', since HAL may not be using fences, and want
+    // to be able to idle in case of errors.
+    nsecs_t signalTime = mIdleFence->getSignalTime();
+    bool fencesDone = signalTime != INT64_MAX;
+
+    ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
+
+    return fencesDone ? IDLE : ACTIVE;
+}
+
+bool StatusTracker::threadLoop() {
+    status_t res;
+
+    // Wait for state updates
+    {
+        Mutex::Autolock pl(mPendingLock);
+        while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
+            res = mPendingChangeSignal.waitRelative(mPendingLock,
+                    kWaitDuration);
+            if (exitPending()) return false;
+            if (res != OK) {
+                if (res != TIMED_OUT) {
+                    ALOGE("%s: Error waiting on state changes: %s (%d)",
+                            __FUNCTION__, strerror(-res), res);
+                }
+                // TIMED_OUT is expected
+                break;
+            }
+        }
+    }
+
+    // After new pending states appear, or timeout, check if we're idle.  Even
+    // with timeout, need to check to account for fences that may still be
+    // clearing out
+    sp<Camera3Device> parent;
+    {
+        Mutex::Autolock pl(mPendingLock);
+        Mutex::Autolock l(mLock);
+
+        // Collect all pending state updates and see if the device
+        // collectively transitions between idle and active for each one
+
+        // First pass for changed components or fence completions
+        ComponentState prevState = getDeviceStateLocked();
+        if (prevState != mDeviceState) {
+            // Only collect changes to overall device state
+            mStateTransitions.add(prevState);
+        }
+        // For each pending component state update, check if we've transitioned
+        // to a new overall device state
+        for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
+            const StateChange &newState = mPendingChangeQueue[i];
+            ssize_t idx = mStates.indexOfKey(newState.id);
+            // Ignore notices for unknown components
+            if (idx >= 0) {
+                // Update single component state
+                mStates.replaceValueAt(idx, newState.state);
+                mIdleFence = Fence::merge(String8("idleFence"),
+                        mIdleFence, newState.fence);
+                // .. and see if overall device state has changed
+                ComponentState newState = getDeviceStateLocked();
+                if (newState != prevState) {
+                    mStateTransitions.add(newState);
+                }
+                prevState = newState;
+            }
+        }
+        mPendingChangeQueue.clear();
+        mComponentsChanged = false;
+
+        // Store final state after all pending state changes are done with
+
+        mDeviceState = prevState;
+        parent = mParent.promote();
+    }
+
+    // Notify parent for all intermediate transitions
+    if (mStateTransitions.size() > 0 && parent.get()) {
+        for (size_t i = 0; i < mStateTransitions.size(); i++) {
+            bool idle = (mStateTransitions[i] == IDLE);
+            ALOGV("Camera device is now %s", idle ? "idle" : "active");
+            parent->notifyStatus(idle);
+        }
+    }
+    mStateTransitions.clear();
+
+    return true;
+}
+
+} // namespace android
+
+} // namespace camera3