Merge "Fix race condition for VQDS functionalities" into main

This commit is contained in:
Charles Chen 2023-12-19 04:06:00 +00:00 committed by Android (Google) Code Review
commit 737a7b71d9
2 changed files with 133 additions and 91 deletions

View File

@ -94,7 +94,9 @@ public class VisualQueryDetector {
*/
public void updateState(@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory) {
mInitializationDelegate.updateState(options, sharedMemory);
synchronized (mInitializationDelegate.getLock()) {
mInitializationDelegate.updateState(options, sharedMemory);
}
}
@ -116,18 +118,21 @@ public class VisualQueryDetector {
if (DEBUG) {
Slog.i(TAG, "#startRecognition");
}
// check if the detector is active with the initialization delegate
mInitializationDelegate.startRecognition();
synchronized (mInitializationDelegate.getLock()) {
// check if the detector is active with the initialization delegate
mInitializationDelegate.startRecognition();
try {
mManagerService.startPerceiving(new BinderCallback(mExecutor, mCallback));
} catch (SecurityException e) {
Slog.e(TAG, "startRecognition failed: " + e);
return false;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
try {
mManagerService.startPerceiving(new BinderCallback(
mExecutor, mCallback, mInitializationDelegate.getLock()));
} catch (SecurityException e) {
Slog.e(TAG, "startRecognition failed: " + e);
return false;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return true;
}
return true;
}
/**
@ -140,15 +145,17 @@ public class VisualQueryDetector {
if (DEBUG) {
Slog.i(TAG, "#stopRecognition");
}
// check if the detector is active with the initialization delegate
mInitializationDelegate.startRecognition();
synchronized (mInitializationDelegate.getLock()) {
// check if the detector is active with the initialization delegate
mInitializationDelegate.stopRecognition();
try {
mManagerService.stopPerceiving();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
try {
mManagerService.stopPerceiving();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return true;
}
return true;
}
/**
@ -160,12 +167,16 @@ public class VisualQueryDetector {
if (DEBUG) {
Slog.i(TAG, "#destroy");
}
mInitializationDelegate.destroy();
synchronized (mInitializationDelegate.getLock()) {
mInitializationDelegate.destroy();
}
}
/** @hide */
public void dump(String prefix, PrintWriter pw) {
// TODO: implement this
synchronized (mInitializationDelegate.getLock()) {
mInitializationDelegate.dump(prefix, pw);
}
}
/** @hide */
@ -175,7 +186,9 @@ public class VisualQueryDetector {
/** @hide */
void registerOnDestroyListener(Consumer<AbstractDetector> onDestroyListener) {
mInitializationDelegate.registerOnDestroyListener(onDestroyListener);
synchronized (mInitializationDelegate.getLock()) {
mInitializationDelegate.registerOnDestroyListener(onDestroyListener);
}
}
/**
@ -282,6 +295,15 @@ public class VisualQueryDetector {
public boolean isUsingSandboxedDetectionService() {
return true;
}
@Override
public void dump(String prefix, PrintWriter pw) {
// No-op
}
private Object getLock() {
return mLock;
}
}
private static class BinderCallback
@ -289,31 +311,43 @@ public class VisualQueryDetector {
private final Executor mExecutor;
private final VisualQueryDetector.Callback mCallback;
BinderCallback(Executor executor, VisualQueryDetector.Callback callback) {
private final Object mLock;
BinderCallback(Executor executor, VisualQueryDetector.Callback callback, Object lock) {
this.mExecutor = executor;
this.mCallback = callback;
this.mLock = lock;
}
/** Called when the detected result is valid. */
@Override
public void onQueryDetected(@NonNull String partialQuery) {
Slog.v(TAG, "BinderCallback#onQueryDetected");
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
() -> mCallback.onQueryDetected(partialQuery)));
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
mCallback.onQueryDetected(partialQuery);
}
});
}
@Override
public void onQueryFinished() {
Slog.v(TAG, "BinderCallback#onQueryFinished");
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
() -> mCallback.onQueryFinished()));
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
mCallback.onQueryFinished();
}
});
}
@Override
public void onQueryRejected() {
Slog.v(TAG, "BinderCallback#onQueryRejected");
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
() -> mCallback.onQueryRejected()));
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
mCallback.onQueryRejected();
}
});
}
/** Called when the detection fails due to an error. */

View File

@ -106,96 +106,104 @@ final class VisualQueryDetectorSession extends DetectorSession {
@Override
public void onAttentionGained() {
Slog.v(TAG, "BinderCallback#onAttentionGained");
mEgressingData = true;
if (mAttentionListener == null) {
return;
}
try {
mAttentionListener.onAttentionGained();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention gained event.", e);
try {
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_ATTENTION_STATE,
"Attention listener failed to switch to GAINED state."));
} catch (RemoteException ex) {
Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure");
synchronized (mLock) {
mEgressingData = true;
if (mAttentionListener == null) {
return;
}
try {
mAttentionListener.onAttentionGained();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention gained event.", e);
try {
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_ATTENTION_STATE,
"Attention listener fails to switch to GAINED state."));
} catch (RemoteException ex) {
Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure");
}
}
return;
}
}
@Override
public void onAttentionLost() {
Slog.v(TAG, "BinderCallback#onAttentionLost");
mEgressingData = false;
if (mAttentionListener == null) {
return;
}
try {
mAttentionListener.onAttentionLost();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention lost event.", e);
try {
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_ATTENTION_STATE,
"Attention listener failed to switch to LOST state."));
} catch (RemoteException ex) {
Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure");
synchronized (mLock) {
mEgressingData = false;
if (mAttentionListener == null) {
return;
}
try {
mAttentionListener.onAttentionLost();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention lost event.", e);
try {
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_ATTENTION_STATE,
"Attention listener fails to switch to LOST state."));
} catch (RemoteException ex) {
Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure");
}
}
return;
}
}
@Override
public void onQueryDetected(@NonNull String partialQuery) throws RemoteException {
Objects.requireNonNull(partialQuery);
Slog.v(TAG, "BinderCallback#onQueryDetected");
if (!mEgressingData) {
Slog.v(TAG, "Query should not be egressed within the unattention state.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot stream queries without attention signals."));
return;
synchronized (mLock) {
Objects.requireNonNull(partialQuery);
if (!mEgressingData) {
Slog.v(TAG, "Query should not be egressed within the unattention state.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot stream queries without attention signals."));
return;
}
mQueryStreaming = true;
callback.onQueryDetected(partialQuery);
Slog.i(TAG, "Egressed from visual query detection process.");
}
mQueryStreaming = true;
callback.onQueryDetected(partialQuery);
Slog.i(TAG, "Egressed from visual query detection process.");
}
@Override
public void onQueryFinished() throws RemoteException {
Slog.v(TAG, "BinderCallback#onQueryFinished");
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal FINISHED is block since there is"
+ " no active query being streamed.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot send FINISHED signal with no query streamed."));
return;
synchronized (mLock) {
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal FINISHED is block since there is"
+ " no active query being streamed.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot send FINISHED signal with no query streamed."));
return;
}
callback.onQueryFinished();
mQueryStreaming = false;
}
callback.onQueryFinished();
mQueryStreaming = false;
}
@Override
public void onQueryRejected() throws RemoteException {
Slog.v(TAG, "BinderCallback#onQueryRejected");
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal REJECTED is block since there is"
+ " no active query being streamed.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot send REJECTED signal with no query streamed."));
return;
synchronized (mLock) {
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal REJECTED is block since there is"
+ " no active query being streamed.");
callback.onVisualQueryDetectionServiceFailure(
new VisualQueryDetectionServiceFailure(
ERROR_CODE_ILLEGAL_STREAMING_STATE,
"Cannot send REJECTED signal with no query streamed."));
return;
}
callback.onQueryRejected();
mQueryStreaming = false;
}
callback.onQueryRejected();
mQueryStreaming = false;
}
};
return mRemoteDetectionService.run(