Camera: ProClient add asynchronous locks and such

Change-Id: I551e5e5e76d9be733fab5224beaa7309268c0f38
diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp
index c2ad74f..756fba2 100644
--- a/camera/IProCameraCallbacks.cpp
+++ b/camera/IProCameraCallbacks.cpp
@@ -34,6 +34,7 @@
     NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
     DATA_CALLBACK,
     DATA_CALLBACK_TIMESTAMP,
+    LOCK_STATUS_CHANGED,
 };
 
 class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks>
@@ -86,6 +87,15 @@
         remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply,
                                                           IBinder::FLAG_ONEWAY);
     }
+
+    void onLockStatusChanged(LockStatus newLockStatus) {
+        ALOGV("onLockStatusChanged");
+        Parcel data, reply;
+        data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor());
+        data.writeInt32(newLockStatus);
+        remote()->transact(LOCK_STATUS_CHANGED, data, &reply,
+                           IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(ProCameraCallbacks,
@@ -96,6 +106,7 @@
 status_t BnProCameraCallbacks::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
+    ALOGV("onTransact - code = %d", code);
     switch(code) {
         case NOTIFY_CALLBACK: {
             ALOGV("NOTIFY_CALLBACK");
@@ -133,6 +144,14 @@
             dataCallbackTimestamp(timestamp, msgType, imageData);
             return NO_ERROR;
         } break;
+        case LOCK_STATUS_CHANGED: {
+            ALOGV("LOCK_STATUS_CHANGED");
+            CHECK_INTERFACE(IProCameraCallbacks, data, reply);
+            LockStatus newLockStatus
+                                 = static_cast<LockStatus>(data.readInt32());
+            onLockStatusChanged(newLockStatus);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 134a4a3..8164188 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -118,6 +118,12 @@
     ALOGW("Camera service died!");
 }
 
+void ProCamera::setListener(const sp<ProCameraListener>& listener)
+{
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+}
+
 
 // callback from camera service
 void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
@@ -164,6 +170,34 @@
 
 /* IProCameraUser's implementation */
 
+void ProCamera::onLockStatusChanged(
+                                 IProCameraCallbacks::LockStatus newLockStatus)
+{
+    ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus);
+
+    sp<ProCameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        switch (newLockStatus) {
+            case IProCameraCallbacks::LOCK_ACQUIRED:
+                listener->onLockAcquired();
+                break;
+            case IProCameraCallbacks::LOCK_RELEASED:
+                listener->onLockReleased();
+                break;
+            case IProCameraCallbacks::LOCK_STOLEN:
+                listener->onLockStolen();
+                break;
+            default:
+                ALOGE("%s: Unknown lock status: %d",
+                      __FUNCTION__, newLockStatus);
+        }
+    }
+}
+
 status_t ProCamera::exclusiveTryLock()
 {
     sp <IProCameraUser> c = mCamera;
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index 5d386c4..e455943 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -14,7 +14,8 @@
 	libgui \
 	libsync \
 	libui \
-	libdl
+	libdl \
+	libbinder
 
 LOCAL_STATIC_LIBRARIES := \
 	libgtest
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 4de9c10..ca9e224 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -17,8 +17,14 @@
 #include <gtest/gtest.h>
 #include <iostream>
 
+#include <binder/IPCThreadState.h>
+#include <utils/Thread.h>
+
 #include "Camera.h"
 #include "ProCamera.h"
+#include <utils/Vector.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
 
 namespace android {
 namespace camera2 {
@@ -28,17 +34,159 @@
 #define CAMERA_ID 0
 #define TEST_DEBUGGING 0
 
+#define TEST_LISTENER_TIMEOUT 2000000000 // 2 second listener timeout
+
 #if TEST_DEBUGGING
 #define dout std::cerr
 #else
 #define dout if (0) std::cerr
 #endif
 
+enum LockEvent {
+    UNKNOWN,
+    ACQUIRED,
+    RELEASED,
+    STOLEN
+};
+
+typedef Vector<LockEvent> EventList;
+
+class ProCameraTestThread : public Thread
+{
+public:
+    ProCameraTestThread() {
+    }
+
+    virtual bool threadLoop() {
+        mProc = ProcessState::self();
+        mProc->startThreadPool();
+
+        IPCThreadState *ptr = IPCThreadState::self();
+
+        dout << "will join thread pool" << std::endl;
+        ptr->joinThreadPool();
+        dout << "joined thread pool (done)" << std::endl;
+
+        return false;
+    }
+
+    sp<ProcessState> mProc;
+};
+
+class ProCameraTestListener : public ProCameraListener {
+
+public:
+    status_t WaitForEvent() {
+        Mutex::Autolock cal(mConditionMutex);
+
+        {
+            Mutex::Autolock al(mListenerMutex);
+
+            if (mLockEventList.size() > 0) {
+                return OK;
+            }
+        }
+
+        return mListenerCondition.waitRelative(mConditionMutex,
+                                               TEST_LISTENER_TIMEOUT);
+    }
+
+    /* Read events into out. Existing queue is flushed */
+    void ReadEvents(EventList& out) {
+        Mutex::Autolock al(mListenerMutex);
+
+        for (size_t i = 0; i < mLockEventList.size(); ++i) {
+            out.push(mLockEventList[i]);
+        }
+
+        mLockEventList.clear();
+    }
+
+    /**
+      * Dequeue 1 event from the event queue.
+      * Returns UNKNOWN if queue is empty
+      */
+    LockEvent ReadEvent() {
+        Mutex::Autolock al(mListenerMutex);
+
+        if (mLockEventList.size() == 0) {
+            return UNKNOWN;
+        }
+
+        LockEvent ev = mLockEventList[0];
+        mLockEventList.removeAt(0);
+
+        return ev;
+    }
+
+private:
+    void QueueEvent(LockEvent ev) {
+        {
+            Mutex::Autolock al(mListenerMutex);
+            mLockEventList.push(ev);
+        }
+
+
+        mListenerCondition.broadcast();
+    }
+
+protected:
+
+    //////////////////////////////////////////////////
+    ///////// ProCameraListener //////////////////////
+    //////////////////////////////////////////////////
+
+
+    // Lock has been acquired. Write operations now available.
+    virtual void onLockAcquired() {
+        QueueEvent(ACQUIRED);
+    }
+    // Lock has been released with exclusiveUnlock
+    virtual void onLockReleased() {
+        QueueEvent(RELEASED);
+    }
+
+    // Lock has been stolen by another client.
+    virtual void onLockStolen() {
+        QueueEvent(STOLEN);
+    }
+
+    // Lock free.
+    virtual void onTriggerNotify(int32_t ext1, int32_t ext2, int32_t ext3) {
+
+        dout << "Trigger notify: " << ext1 << " " << ext2
+             << " " << ext3 << std::endl;
+    }
+
+    // TODO: remove
+
+    virtual void notify(int32_t , int32_t , int32_t ) {}
+    virtual void postData(int32_t , const sp<IMemory>& ,
+                          camera_frame_metadata_t *) {}
+    virtual void postDataTimestamp(nsecs_t , int32_t , const sp<IMemory>& ) {}
+
+
+    Vector<LockEvent> mLockEventList;
+    Mutex             mListenerMutex;
+    Mutex             mConditionMutex;
+    Condition         mListenerCondition;
+};
+
 class ProCameraTest : public ::testing::Test {
 
+public:
+    ProCameraTest() {
+    }
+
     virtual void SetUp() {
+        mTestThread = new ProCameraTestThread();
+        mTestThread->run("ProCameraTestThread");
+
         mCamera = ProCamera::connect(CAMERA_ID);
         ASSERT_NE((void*)NULL, mCamera.get());
+
+        mListener = new ProCameraTestListener();
+        mCamera->setListener(mListener);
     }
 
     virtual void TearDown() {
@@ -48,17 +196,32 @@
 
 protected:
     sp<ProCamera> mCamera;
+    sp<ProCameraTestListener> mListener;
+
+    sp<Thread> mTestThread;
+
 };
 
-TEST_F(ProCameraTest, Locking) {
+TEST_F(ProCameraTest, LockingImmediate) {
 
     if (HasFatalFailure()) {
         return;
     }
 
-    status_t res = mCamera->exclusiveTryLock();
 
-    EXPECT_EQ(OK, res);
+    EXPECT_FALSE(mCamera->hasExclusiveLock());
+    EXPECT_EQ(OK, mCamera->exclusiveTryLock());
+
+    EXPECT_EQ(OK, mListener->WaitForEvent());
+    EXPECT_EQ(ACQUIRED, mListener->ReadEvent());
+
+    EXPECT_TRUE(mCamera->hasExclusiveLock());
+    EXPECT_EQ(OK, mCamera->exclusiveUnlock());
+
+    EXPECT_EQ(OK, mListener->WaitForEvent());
+    EXPECT_EQ(RELEASED, mListener->ReadEvent());
+
+    EXPECT_FALSE(mCamera->hasExclusiveLock());
 }
 
 }
diff --git a/include/camera/IProCameraCallbacks.h b/include/camera/IProCameraCallbacks.h
index ac1d5eb..e5be099 100644
--- a/include/camera/IProCameraCallbacks.h
+++ b/include/camera/IProCameraCallbacks.h
@@ -39,6 +39,14 @@
     virtual void            dataCallbackTimestamp(nsecs_t timestamp,
                                                   int32_t msgType,
                                                   const sp<IMemory>& data) = 0;
+
+    enum LockStatus {
+        LOCK_ACQUIRED,
+        LOCK_RELEASED,
+        LOCK_STOLEN,
+    };
+
+    virtual void            onLockStatusChanged(LockStatus newLockStatus) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h
index ba5fdc0..2dd01e3 100644
--- a/include/camera/ProCamera.h
+++ b/include/camera/ProCamera.h
@@ -34,9 +34,10 @@
 public:
     // Lock has been acquired. Write operations now available.
     virtual void onLockAcquired() = 0;
-    // Lock has been released with exclusiveUnlock, or has been stolen by
-    // another client.
+    // Lock has been released with exclusiveUnlock.
     virtual void onLockReleased() = 0;
+    // Lock has been stolen by another client.
+    virtual void onLockStolen() = 0;
 
     // Lock free.
     virtual void onTriggerNotify(int32_t msgType, int32_t ext1, int32_t ext2)
@@ -129,6 +130,8 @@
     virtual void        dataCallbackTimestamp(nsecs_t timestamp,
                                               int32_t msgType,
                                               const sp<IMemory>& dataPtr);
+    virtual void        onLockStatusChanged(
+                                IProCameraCallbacks::LockStatus newLockStatus);
 
     class DeathNotifier: public IBinder::DeathRecipient
     {