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

Commit ff0f38e6 authored by Dave Sparks's avatar Dave Sparks
Browse files

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.
parent 3bde289d
Loading
Loading
Loading
Loading
+43 −28
Original line number Diff line number Diff line
@@ -683,6 +683,8 @@ void CameraService::Client::stopPreview()
{
    LOGD("stopPreview (pid %d)", getCallingPid());

    // hold main lock during state transition
    {
        Mutex::Autolock lock(mLock);
        if (checkPid() != NO_ERROR) return;

@@ -698,14 +700,22 @@ void CameraService::Client::stopPreview()
        if (mSurface != 0 && !mUseOverlay) {
            mSurface->unregisterBuffers();
        }
    }

    // hold preview buffer lock
    {
        Mutex::Autolock lock(mPreviewLock);
        mPreviewBuffer.clear();
    }
}

// stop recording mode
void CameraService::Client::stopRecording()
{
    LOGD("stopRecording (pid %d)", getCallingPid());

    // hold main lock during state transition
    {
        Mutex::Autolock lock(mLock);
        if (checkPid() != NO_ERROR) return;

@@ -722,9 +732,14 @@ void CameraService::Client::stopRecording()
        mHardware->stopRecording();
        mHardware->disableMsgType(CAMERA_MSG_VIDEO_FRAME);
        LOGD("stopRecording(), hardware stopped OK");
    }

    // hold preview buffer lock
    {
        Mutex::Autolock lock(mPreviewLock);
        mPreviewBuffer.clear();
    }
}

// release a recording frame
void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
@@ -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()) {
+3 −1
Original line number Diff line number Diff line
@@ -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;
    };

// ----------------------------------------------------------------------------