Use a ref-counted callback interface for Camera.
This allows the camera service to hang onto the callback interface
until all callbacks have been processed. This prevents problems
where pending callbacks in binder worker threads are processed
after the Java camera object and its associated native resources
have been released.
Bug 1884362
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..bd4855c 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -86,6 +86,14 @@
class Mutex;
class String8;
+// ref-counted object for callbacks
+class CameraListener: virtual public RefBase
+{
+public:
+ virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+ virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
+
typedef void (*shutter_callback)(void *cookie);
typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
typedef void (*autofocus_callback)(bool focused, void *cookie);
@@ -152,6 +160,9 @@
void setErrorCallback(error_callback cb, void *cookie);
void setAutoFocusCallback(autofocus_callback cb, void *cookie);
+ void setListener(const sp<CameraListener>& listener);
+ void setPreviewCallbackFlags(int preview_callback_flag);
+
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
@@ -194,6 +205,8 @@
autofocus_callback mAutoFocusCallback;
void *mAutoFocusCallbackCookie;
+ sp<CameraListener> mListener;
+
friend class DeathNotifier;
static Mutex mLock;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..1aa5245 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -337,9 +337,32 @@
mErrorCallbackCookie = cookie;
}
+void Camera::setListener(const sp<CameraListener>& listener)
+{
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
+}
+
+void Camera::setPreviewCallbackFlags(int flag)
+{
+ LOGV("setPreviewCallbackFlags");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return;
+ mCamera->setPreviewCallbackFlag(flag);
+}
+
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->notify(msgType, ext1, ext2);
+ }
+
switch(msgType) {
case CAMERA_MSG_ERROR:
LOGV("errorCallback");
@@ -368,6 +391,15 @@
// callback from camera service when frame or image is ready
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
{
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->postData(msgType, dataPtr);
+ }
+
switch(msgType) {
case CAMERA_MSG_PREVIEW_FRAME:
LOGV("previewCallback");
@@ -401,6 +433,7 @@
void Camera::binderDied(const wp<IBinder>& who) {
LOGW("ICamera died");
+ notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
if (mErrorCallback) {
mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
}