Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68c80668 authored by Igor Murashkin's avatar Igor Murashkin
Browse files

Camera: ProClient add asynchronous locks and such

Change-Id: I551e5e5e76d9be733fab5224beaa7309268c0f38
parent bfb5d5ef
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ enum {
    NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
    DATA_CALLBACK,
    DATA_CALLBACK_TIMESTAMP,
    LOCK_STATUS_CHANGED,
};

class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks>
@@ -86,6 +87,15 @@ public:
        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 @@ IMPLEMENT_META_INTERFACE(ProCameraCallbacks,
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 @@ status_t BnProCameraCallbacks::onTransact(
            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);
    }
+34 −0
Original line number Diff line number Diff line
@@ -118,6 +118,12 @@ void ProCamera::DeathNotifier::binderDied(const wp<IBinder>& who) {
    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 @@ void ProCamera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,

/* 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;
+2 −1
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \
	libgui \
	libsync \
	libui \
	libdl
	libdl \
	libbinder

LOCAL_STATIC_LIBRARIES := \
	libgtest
+166 −3
Original line number Diff line number Diff line
@@ -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 @@ namespace client {
#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 @@ class ProCameraTest : public ::testing::Test {

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());
}

}
+8 −0
Original line number Diff line number Diff line
@@ -39,6 +39,14 @@ public:
    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;
};

// ----------------------------------------------------------------------------
Loading