Merge "Removed unnecessary include JNI from two drm Android.mk files"
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 22836e3..dc3f083 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -299,9 +299,14 @@
LOG1("CameraService::removeClient X (pid %d)", callingPid);
}
-sp<CameraService::Client> CameraService::getClientById(int cameraId) {
+CameraService::Client* CameraService::getClientByIdUnsafe(int cameraId) {
if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
- return mClient[cameraId].promote();
+ return mClient[cameraId].unsafe_get();
+}
+
+Mutex* CameraService::getClientLockById(int cameraId) {
+ if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
+ return &mClientLock[cameraId];
}
status_t CameraService::onTransact(
@@ -408,6 +413,7 @@
mMsgEnabled = 0;
mSurface = 0;
mPreviewWindow = 0;
+ mDestructionStarted = false;
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
@@ -428,6 +434,12 @@
// tear down the client
CameraService::Client::~Client() {
+ // this lock should never be NULL
+ Mutex* lock = mCameraService->getClientLockById(mCameraId);
+ lock->lock();
+ mDestructionStarted = true;
+ // client will not be accessed from callback. should unlock to prevent dead-lock in disconnect
+ lock->unlock();
int callingPid = getCallingPid();
LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
@@ -994,16 +1006,22 @@
// ----------------------------------------------------------------------------
-// Converts from a raw pointer to the client to a strong pointer during a
-// hardware callback. This requires the callbacks only happen when the client
-// is still alive.
-sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) {
- sp<Client> client = gCameraService->getClientById((int) user);
+Mutex* CameraService::Client::getClientLockFromCookie(void* user) {
+ return gCameraService->getClientLockById((int) user);
+}
+
+// Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should
+// be acquired for this to be safe
+CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
+ Client* client = gCameraService->getClientByIdUnsafe((int) user);
// This could happen if the Client is in the process of shutting down (the
// last strong reference is gone, but the destructor hasn't finished
// stopping the hardware).
- if (client == 0) return NULL;
+ if (client == NULL) return NULL;
+
+ // destruction already started, so should not be accessed
+ if (client->mDestructionStarted) return NULL;
// The checks below are not necessary and are for debugging only.
if (client->mCameraService.get() != gCameraService) {
@@ -1046,8 +1064,13 @@
int32_t ext2, void* user) {
LOG2("notifyCallback(%d)", msgType);
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) return;
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+
+ Client* client = getClientFromCookie(user);
+ if (client == NULL) return;
+
if (!client->lockIfMessageWanted(msgType)) return;
switch (msgType) {
@@ -1065,10 +1088,14 @@
const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
LOG2("dataCallback(%d)", msgType);
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) return;
- if (!client->lockIfMessageWanted(msgType)) return;
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+ Client* client = getClientFromCookie(user);
+ if (client == NULL) return;
+
+ if (!client->lockIfMessageWanted(msgType)) return;
if (dataPtr == 0 && metadata == NULL) {
ALOGE("Null data returned in data callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
@@ -1098,8 +1125,13 @@
int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
LOG2("dataCallbackTimestamp(%d)", msgType);
- sp<Client> client = getClientFromCookie(user);
- if (client == 0) return;
+ Mutex* lock = getClientLockFromCookie(user);
+ if (lock == NULL) return;
+ Mutex::Autolock alock(*lock);
+
+ Client* client = getClientFromCookie(user);
+ if (client == NULL) return;
+
if (!client->lockIfMessageWanted(msgType)) return;
if (dataPtr == 0) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 457c79b..7972201 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -49,7 +49,10 @@
virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
bool force, bool keep);
virtual void removeClient(const sp<ICameraClient>& cameraClient);
- virtual sp<Client> getClientById(int cameraId);
+ // returns plain pointer of client. Note that mClientLock should be acquired to
+ // prevent the client from destruction. The result can be NULL.
+ virtual Client* getClientByIdUnsafe(int cameraId);
+ virtual Mutex* getClientLockById(int cameraId);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t onTransact(uint32_t code, const Parcel& data,
@@ -69,6 +72,7 @@
private:
Mutex mServiceLock;
wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock
+ Mutex mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks
int mNumberOfCameras;
// atomics to record whether the hardware is allocated to some client.
@@ -147,8 +151,9 @@
static void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata, void* user);
static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
- // convert client from cookie
- static sp<Client> getClientFromCookie(void* user);
+ static Mutex* getClientLockFromCookie(void* user);
+ // convert client from cookie. Client lock should be acquired before getting Client.
+ static Client* getClientFromCookie(void* user);
// handlers for messages
void handleShutter(void);
void handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
@@ -204,6 +209,11 @@
// of the original one), we allocate mPreviewBuffer and reuse it if possible.
sp<MemoryHeapBase> mPreviewBuffer;
+ // the instance is in the middle of destruction. When this is set,
+ // the instance should not be accessed from callback.
+ // CameraService's mClientLock should be acquired to access this.
+ bool mDestructionStarted;
+
// We need to avoid the deadlock when the incoming command thread and
// the CameraHardwareInterface callback thread both want to grab mLock.
// An extra flag is used to tell the callback thread that it should stop