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

Commit 6e98c05c authored by James Dong's avatar James Dong Committed by The Android Automerger
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 456fe00e
Loading
Loading
Loading
Loading
+34 −6
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.StringTokenizer;
import java.util.StringTokenizer;
import java.util.concurrent.locks.ReentrantLock;


/**
/**
 * The Camera class is used to set image capture settings, start/stop preview,
 * 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 mOneShot;
    private boolean mWithBuffer;
    private boolean mWithBuffer;
    private boolean mFaceDetectionRunning = false;
    private boolean mFaceDetectionRunning = false;
    private ReentrantLock mFocusLock = new ReentrantLock();


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


            case CAMERA_MSG_FOCUS:
            case CAMERA_MSG_FOCUS:
                mFocusLock.lock();
                try {
                    if (mAutoFocusCallback != null) {
                    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;
                return;


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


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


@@ -3577,4 +3596,13 @@ public class Camera {
            return false;
            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);
    }
}
}