diff options
author | Dave Sparks <davidsparks@android.com> | 2009-11-10 17:08:08 -0800 |
---|---|---|
committer | Dave Sparks <davidsparks@android.com> | 2009-11-10 17:08:08 -0800 |
commit | 05fd0df0f3ec71ec6ea874439feda960ef882d0b (patch) | |
tree | 80289875489b6479d749267d5b45c8d5092ed7f7 /camera/libcameraservice | |
parent | ae0cf6dc9eb92282ef92b00ac68bfaca8aad2a1e (diff) | |
download | frameworks_base-05fd0df0f3ec71ec6ea874439feda960ef882d0b.zip frameworks_base-05fd0df0f3ec71ec6ea874439feda960ef882d0b.tar.gz frameworks_base-05fd0df0f3ec71ec6ea874439feda960ef882d0b.tar.bz2 |
Fix potential deadlock in stopPreview/stopRecord.
Some camera HALs spin up a preview thread and need to wait for
the thread to exit. This can create a potential deadlock. In
stopPreview, we take the main lock. If a preview callback occurs
while the lock is held, the preview thread will block. If the
camera HAL is waiting for the preview thread to exit, this will
cause a deadlock.
This patch breaks out the preview buffer heap into a separate
mutex. This mutex is never held when the main lock is held, thus
preventing the deadlock from occuring.
Diffstat (limited to 'camera/libcameraservice')
-rw-r--r-- | camera/libcameraservice/CameraService.cpp | 71 | ||||
-rw-r--r-- | camera/libcameraservice/CameraService.h | 4 |
2 files changed, 46 insertions, 29 deletions
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index e548524..df59dcf 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -683,22 +683,30 @@ void CameraService::Client::stopPreview() { LOGD("stopPreview (pid %d)", getCallingPid()); - Mutex::Autolock lock(mLock); - if (checkPid() != NO_ERROR) return; + // hold main lock during state transition + { + Mutex::Autolock lock(mLock); + if (checkPid() != NO_ERROR) return; - if (mHardware == 0) { - LOGE("mHardware is NULL, returning."); - return; - } + if (mHardware == 0) { + LOGE("mHardware is NULL, returning."); + return; + } - mHardware->stopPreview(); - mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); - LOGD("stopPreview(), hardware stopped OK"); + mHardware->stopPreview(); + mHardware->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); + LOGD("stopPreview(), hardware stopped OK"); - if (mSurface != 0 && !mUseOverlay) { - mSurface->unregisterBuffers(); + if (mSurface != 0 && !mUseOverlay) { + mSurface->unregisterBuffers(); + } + } + + // hold preview buffer lock + { + Mutex::Autolock lock(mPreviewLock); + mPreviewBuffer.clear(); } - mPreviewBuffer.clear(); } // stop recording mode @@ -706,24 +714,31 @@ void CameraService::Client::stopRecording() { LOGD("stopRecording (pid %d)", getCallingPid()); - Mutex::Autolock lock(mLock); - if (checkPid() != NO_ERROR) return; + // hold main lock during state transition + { + Mutex::Autolock lock(mLock); + if (checkPid() != NO_ERROR) return; - if (mHardware == 0) { - LOGE("mHardware is NULL, returning."); - return; - } + if (mHardware == 0) { + LOGE("mHardware is NULL, returning."); + return; + } - if (mMediaPlayerBeep.get() != NULL) { - mMediaPlayerBeep->seekTo(0); - mMediaPlayerBeep->start(); - } + if (mMediaPlayerBeep.get() != NULL) { + mMediaPlayerBeep->seekTo(0); + mMediaPlayerBeep->start(); + } - mHardware->stopRecording(); - mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME); - LOGD("stopRecording(), hardware stopped OK"); + mHardware->stopRecording(); + mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME); + LOGD("stopRecording(), hardware stopped OK"); + } - mPreviewBuffer.clear(); + // hold preview buffer lock + { + Mutex::Autolock lock(mPreviewLock); + mPreviewBuffer.clear(); + } } // release a recording frame @@ -1216,10 +1231,10 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(const sp<ICameraClient>& // provided it's big enough. Don't allocate the memory or // perform the copy if there's no callback. - // hold the lock while we grab a reference to the preview buffer + // hold the preview lock while we grab a reference to the preview buffer sp<MemoryHeapBase> previewBuffer; { - Mutex::Autolock lock(mLock); + Mutex::Autolock lock(mPreviewLock); if (mPreviewBuffer == 0) { mPreviewBuffer = new MemoryHeapBase(size, 0, NULL); } else if (size > mPreviewBuffer->virtualSize()) { diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index 41c5d99..3e3e54f 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -181,7 +181,6 @@ private: mutable Condition mReady; sp<CameraService> mCameraService; sp<ISurface> mSurface; - sp<MemoryHeapBase> mPreviewBuffer; int mPreviewCallbackFlag; sp<MediaPlayer> mMediaPlayerClick; @@ -197,6 +196,9 @@ private: sp<OverlayRef> mOverlayRef; int mOverlayW; int mOverlayH; + + mutable Mutex mPreviewLock; + sp<MemoryHeapBase> mPreviewBuffer; }; // ---------------------------------------------------------------------------- |