Skip to content

Commit 248ba23

Browse files
author
James Dong
committed
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
1 parent 427db9b commit 248ba23

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

core/java/android/hardware/Camera.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.HashMap;
3636
import java.util.List;
3737
import java.util.StringTokenizer;
38+
import java.util.concurrent.locks.ReentrantLock;
3839

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

158160
/**
159161
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -746,8 +748,14 @@ public void handleMessage(Message msg) {
746748
return;
747749

748750
case CAMERA_MSG_FOCUS:
749-
if (mAutoFocusCallback != null) {
750-
mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
751+
mFocusLock.lock();
752+
try {
753+
if (mAutoFocusCallback != null) {
754+
boolean success = msg.arg1 == 0 ? false : true;
755+
mAutoFocusCallback.onAutoFocus(success, mCamera);
756+
}
757+
} finally {
758+
mFocusLock.unlock();
751759
}
752760
return;
753761

@@ -872,8 +880,13 @@ public interface AutoFocusCallback
872880
*/
873881
public final void autoFocus(AutoFocusCallback cb)
874882
{
875-
mAutoFocusCallback = cb;
876-
native_autoFocus();
883+
mFocusLock.lock();
884+
try {
885+
mAutoFocusCallback = cb;
886+
native_autoFocus();
887+
} finally {
888+
mFocusLock.unlock();
889+
}
877890
}
878891
private native final void native_autoFocus();
879892

@@ -887,8 +900,14 @@ public final void autoFocus(AutoFocusCallback cb)
887900
*/
888901
public final void cancelAutoFocus()
889902
{
890-
mAutoFocusCallback = null;
891-
native_cancelAutoFocus();
903+
mFocusLock.lock();
904+
try {
905+
mAutoFocusCallback = null;
906+
native_cancelAutoFocus();
907+
removePendingAFCompletionMessages();
908+
} finally {
909+
mFocusLock.unlock();
910+
}
892911
}
893912
private native final void native_cancelAutoFocus();
894913

@@ -3577,4 +3596,13 @@ private boolean same(String s1, String s2) {
35773596
return false;
35783597
}
35793598
};
3599+
3600+
/*
3601+
* At any time, there should be at most one pending auto focus completion
3602+
* message, but we simply remove all pending AF completion messages in
3603+
* the looper's queue.
3604+
*/
3605+
private void removePendingAFCompletionMessages() {
3606+
mEventHandler.removeMessages(CAMERA_MSG_FOCUS);
3607+
}
35803608
}

0 commit comments

Comments
 (0)