Loading camera/IProCameraCallbacks.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ enum { NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, DATA_CALLBACK, DATA_CALLBACK_TIMESTAMP, LOCK_STATUS_CHANGED, }; class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks> Loading Loading @@ -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, Loading @@ -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"); Loading Loading @@ -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); } Loading camera/ProCamera.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading camera/tests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ libgui \ libsync \ libui \ libdl libdl \ libbinder LOCAL_STATIC_LIBRARIES := \ libgtest Loading camera/tests/ProCameraTests.cpp +166 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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() { Loading @@ -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()); } } Loading include/camera/IProCameraCallbacks.h +8 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
camera/IProCameraCallbacks.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ enum { NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, DATA_CALLBACK, DATA_CALLBACK_TIMESTAMP, LOCK_STATUS_CHANGED, }; class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks> Loading Loading @@ -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, Loading @@ -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"); Loading Loading @@ -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); } Loading
camera/ProCamera.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading
camera/tests/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ libgui \ libsync \ libui \ libdl libdl \ libbinder LOCAL_STATIC_LIBRARIES := \ libgtest Loading
camera/tests/ProCameraTests.cpp +166 −3 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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() { Loading @@ -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()); } } Loading
include/camera/IProCameraCallbacks.h +8 −0 Original line number Diff line number Diff line Loading @@ -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