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

Commit 248ba23a authored by James Dong's avatar James Dong
Browse files

Fix a race condition in Camera API for handling focus

In the case where a previous AF completion was outstanding but before the completion
notification reached the application, the application cancelled this AF request, and
then started a new AF request. Right after the new AF request, the AF completion
notification for earlier AF request reached the application. The application
could not tell the AF completion notification was meant for the cancelled AF, but
thought the new AF was successfully completed. Subsequently, the application trid to
take a picture, which failed as a result.

The fix is to add an explicit lock in the Camera.java class to fix the race condition to
synchornize autoFocus(), cancelAutoFocus() and the callback of the pending AF
completion message.

o related-to-bug: 6026480

Change-Id: I33d244d908ac066698e792f641ba88fe228b14a9
parent 427db9b3
Loading
Loading
Loading
Loading
+34 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.locks.ReentrantLock;

/**
 * The Camera class is used to set image capture settings, start/stop preview,
@@ -154,6 +155,7 @@ public class Camera {
    private boolean mOneShot;
    private boolean mWithBuffer;
    private boolean mFaceDetectionRunning = false;
    private ReentrantLock mFocusLock = new ReentrantLock();

    /**
     * Broadcast Action:  A new picture is taken by the camera, and the entry of
@@ -746,8 +748,14 @@ public class Camera {
                return;

            case CAMERA_MSG_FOCUS:
                mFocusLock.lock();
                try {
                    if (mAutoFocusCallback != null) {
                    mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
                        boolean success = msg.arg1 == 0 ? false : true;
                        mAutoFocusCallback.onAutoFocus(success, mCamera);
                    }
                } finally {
                    mFocusLock.unlock();
                }
                return;

@@ -872,8 +880,13 @@ public class Camera {
     */
    public final void autoFocus(AutoFocusCallback cb)
    {
        mFocusLock.lock();
        try {
            mAutoFocusCallback = cb;
            native_autoFocus();
        } finally {
            mFocusLock.unlock();
        }
    }
    private native final void native_autoFocus();

@@ -887,8 +900,14 @@ public class Camera {
     */
    public final void cancelAutoFocus()
    {
        mFocusLock.lock();
        try {
            mAutoFocusCallback = null;
            native_cancelAutoFocus();
            removePendingAFCompletionMessages();
        } finally {
            mFocusLock.unlock();
        }
    }
    private native final void native_cancelAutoFocus();

@@ -3577,4 +3596,13 @@ public class Camera {
            return false;
        }
    };

    /*
     * At any time, there should be at most one pending auto focus completion
     * message, but we simply remove all pending AF completion messages in
     * the looper's queue.
     */
    private void removePendingAFCompletionMessages() {
        mEventHandler.removeMessages(CAMERA_MSG_FOCUS);
    }
}