Improve error handling for Trusted Hotword
Add a new callback with an DetectorFailure parameter to let the
assistant know what went wrong during using the hotword detector.
Bug: 256780491
Bug: 261012843
Test: atest CtsVoiceInteractionTestCases
Change-Id: I0b7d9625abfa10f93ad8564e85faedd1db4fa51d
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6581c42..5f83313 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -13141,7 +13141,8 @@
public static interface HotwordDetector.Callback {
method public void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload);
- method public void onError();
+ method @Deprecated public void onError();
+ method public default void onFailure(@NonNull android.service.voice.DetectorFailure);
method public void onHotwordDetectionServiceInitialized(int);
method public void onHotwordDetectionServiceRestarted();
method public void onRecognitionPaused();
@@ -13202,7 +13203,7 @@
}
public static interface VisualQueryDetector.Callback {
- method public void onError();
+ method public void onFailure(@NonNull android.service.voice.DetectorFailure);
method public void onQueryDetected(@NonNull String);
method public void onQueryFinished();
method public void onQueryRejected();
diff --git a/core/java/android/service/voice/AbstractDetector.java b/core/java/android/service/voice/AbstractDetector.java
index 39c2b98..466bc05 100644
--- a/core/java/android/service/voice/AbstractDetector.java
+++ b/core/java/android/service/voice/AbstractDetector.java
@@ -231,9 +231,12 @@
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> mCallback.onError()));
+ public void onError(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 48b7a59..bb3f03d 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -732,7 +732,13 @@
*/
public abstract void onDetected(@NonNull EventPayload eventPayload);
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * @deprecated Use {@link HotwordDetector.Callback#onError(DetectorFailure)} instead.
+ */
+ @Deprecated
+ @Override
public abstract void onError();
/** {@inheritDoc} */
@@ -1658,10 +1664,19 @@
@Override
public void onError(int status) {
Slog.i(TAG, "onError: " + status);
- mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
+ // This is a workaround before the sound trigger uses the onDetectionFailure method.
+ Message.obtain(mHandler, MSG_DETECTION_ERROR,
+ new SoundTriggerFailure(status, "Sound trigger error")).sendToTarget();
}
@Override
+ public void onDetectionFailure(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "onDetectionFailure detectorFailure: " + detectorFailure);
+ Message.obtain(mHandler, MSG_DETECTION_ERROR,
+ detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null")).sendToTarget();
+ }
+ @Override
public void onRecognitionPaused() {
Slog.i(TAG, "onRecognitionPaused");
mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE);
@@ -1716,7 +1731,7 @@
mExternalCallback.onDetected((EventPayload) message.obj);
break;
case MSG_DETECTION_ERROR:
- mExternalCallback.onError();
+ mExternalCallback.onFailure((DetectorFailure) msg.obj);
break;
case MSG_DETECTION_PAUSE:
mExternalCallback.onRecognitionPaused();
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index 562277e..22d97b7 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -231,10 +231,29 @@
/**
* Called when the detection fails due to an error.
+ *
+ * @deprecated On Android 14 and above, implement {@link #onFailure(DetectorFailure)}
+ * instead.
*/
+ @Deprecated
void onError();
/**
+ * Called when the detection fails due to an error, the subclasses of
+ * {@link DetectorFailure} will be reported to the detector.
+ *
+ * @see android.service.voice.HotwordDetectionServiceFailure
+ * @see android.service.voice.SoundTriggerFailure
+ * @see android.service.voice.UnknownFailure
+ * @see android.service.voice.VisualQueryDetectionServiceFailure
+ *
+ * @param detectorFailure It provides the error code, error message and suggested action.
+ */
+ default void onFailure(@NonNull DetectorFailure detectorFailure) {
+ onError();
+ }
+
+ /**
* Called when the recognition is paused temporarily for some reason.
* This is an informational callback, and the clients shouldn't be doing anything here
* except showing an indication on their UI if they have to.
diff --git a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
index 61ac68b..f800c1e 100644
--- a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
+++ b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
@@ -17,6 +17,7 @@
package android.service.voice;
import android.media.AudioFormat;
+import android.service.voice.DetectorFailure;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordRejectedResult;
@@ -38,7 +39,7 @@
/**
* Called when the detection fails due to an error.
*/
- void onError();
+ void onError(in DetectorFailure detectorFailure);
/**
* Called when the detected result was not detected.
diff --git a/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl
index 2eb2470..1a935c0 100644
--- a/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl
+++ b/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl
@@ -16,7 +16,7 @@
package android.service.voice;
-import android.media.AudioFormat;
+import android.service.voice.DetectorFailure;
/**
* Callback for returning the detected result from the VisualQueryDetectionService.
@@ -43,6 +43,5 @@
/**
* Called when the detection fails due to an error.
*/
- void onError();
-
+ void onDetectionFailure(in DetectorFailure detectorFailure);
}
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 6e17bd0..d4b6f3b 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -169,9 +169,12 @@
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> mCallback.onError()));
+ public void onError(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
@@ -222,6 +225,16 @@
if (DEBUG) {
Slog.i(TAG, "Ignored #onError (" + status + ") event");
}
+ // TODO: Check if we still need to implement this method with DetectorFailure mechanism.
+ }
+
+ @Override
+ public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException {
+ Slog.v(TAG, "onDetectionFailure detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index e4c47ef..0be3253 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -216,8 +216,7 @@
/**
* Called when the detection fails due to an error.
*/
- //TODO(b/265390855): Replace this callback with the new onError(DetectorError) design.
- void onError();
+ void onFailure(@NonNull DetectorFailure detectorFailure);
}
private class VisualQueryDetectorInitializationDelegate extends AbstractDetector {
@@ -294,12 +293,11 @@
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
+ public void onDetectionFailure(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onDetectionFailure");
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
- () -> mCallback.onError()));
+ () -> mCallback.onFailure(detectorFailure)));
}
-
}
@@ -373,5 +371,9 @@
Slog.v(TAG, "Initialization Error: (" + status + ")");
// Do nothing
}
+
+ @Override
+ public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException {
+ }
}
}
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index d0214e6..813febf 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.hardware.soundtrigger.SoundTrigger;
+import android.service.voice.DetectorFailure;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordRejectedResult;
@@ -62,6 +63,13 @@
void onError(int status);
/**
+ * Called when the detection fails due to an error.
+ *
+ * @param detectorFailure It provides the error code, error message and suggested action.
+ */
+ void onDetectionFailure(in DetectorFailure detectorFailure);
+
+ /**
* Called when the recognition is paused temporarily for some reason.
*/
void onRecognitionPaused();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index afee940..ec9bd2f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -70,6 +70,7 @@
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -122,10 +123,16 @@
"Providing hotword detection result to VoiceInteractionService";
// The error codes are used for onError callback
- static final int HOTWORD_DETECTION_SERVICE_DIED = -1;
- static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2;
- static final int CALLBACK_DETECT_TIMEOUT = -3;
- static final int CALLBACK_ONDETECTED_STREAM_COPY_ERROR = -4;
+ static final int HOTWORD_DETECTION_SERVICE_DIED =
+ HotwordDetectionServiceFailure.ERROR_CODE_BINDING_DIED;
+ static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION =
+ HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION;
+ static final int CALLBACK_DETECT_TIMEOUT =
+ HotwordDetectionServiceFailure.ERROR_CODE_DETECT_TIMEOUT;
+ static final int CALLBACK_ONDETECTED_STREAM_COPY_ERROR =
+ HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE;
+ static final int CALLBACK_COPY_AUDIO_DATA_FAILURE =
+ HotwordDetectionServiceFailure.ERROR_CODE_COPY_AUDIO_DATA_FAILURE;
// TODO: These constants need to be refined.
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 30000;
@@ -426,7 +433,9 @@
Slog.w(TAG, "Failed supplying audio data to validator", e);
try {
- callback.onError();
+ callback.onError(
+ new HotwordDetectionServiceFailure(CALLBACK_COPY_AUDIO_DATA_FAILURE,
+ "Copy audio data failure for external source detection."));
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to report onError status: " + ex);
if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
@@ -505,7 +514,10 @@
getDetectorType(),
EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- callback.onError();
+ callback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected"
+ + " method."));
return;
}
HotwordDetectedResult newResult;
@@ -514,7 +526,9 @@
.startCopyingAudioStreams(triggerResult);
} catch (IOException e) {
// TODO: Write event
- callback.onError();
+ callback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
callback.onDetected(newResult, /* audioFormat= */ null,
@@ -569,9 +583,11 @@
mRemoteDetectionService = remoteDetectionService;
}
- void reportErrorLocked(int status) {
+ void reportErrorLocked(int errorCode, @NonNull String errorMessage) {
try {
- mCallback.onError(status);
+ // TODO: Use instanceof(this) to get different detector to set the right error source.
+ mCallback.onDetectionFailure(
+ new HotwordDetectionServiceFailure(errorCode, errorMessage));
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: " + e);
if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
index cb5b930..63e0f46 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
@@ -34,6 +34,7 @@
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -130,7 +131,9 @@
HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP,
METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
+ externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected method."));
return;
}
saveProximityValueToBundle(result);
@@ -138,7 +141,9 @@
try {
newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
} catch (IOException e) {
- externalCallback.onError(CALLBACK_ONDETECTED_STREAM_COPY_ERROR);
+ externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
externalCallback.onKeyphraseDetected(recognitionEvent, newResult);
@@ -201,7 +206,9 @@
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT,
mVoiceInteractionServiceUid);
try {
- externalCallback.onError(CALLBACK_DETECT_TIMEOUT);
+ externalCallback.onDetectionFailure(
+ new HotwordDetectionServiceFailure(CALLBACK_DETECT_TIMEOUT,
+ "Timeout to response to the detection result."));
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: ", e);
HotwordMetricsLogger.writeDetectorEvent(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index b672b00..1ba3975 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -690,8 +690,8 @@
//TODO(b265535257): report error to either service only.
synchronized (HotwordDetectionConnection.this.mLock) {
runForEachDetectorSessionLocked((session) -> {
- session.reportErrorLocked(
- DetectorSession.HOTWORD_DETECTION_SERVICE_DIED);
+ session.reportErrorLocked(DetectorSession.HOTWORD_DETECTION_SERVICE_DIED,
+ "Detection service is dead.");
});
}
// Can improve to log exit reason if needed
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
index 3ad963d..522d832 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
@@ -33,6 +33,7 @@
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -121,7 +122,9 @@
HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE,
METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- mSoftwareCallback.onError();
+ mSoftwareCallback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected method."));
return;
}
saveProximityValueToBundle(result);
@@ -130,7 +133,9 @@
newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
} catch (IOException e) {
// TODO: Write event
- mSoftwareCallback.onError();
+ mSoftwareCallback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
mSoftwareCallback.onDetected(newResult, null, null);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
index 33150d8..c397812 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
@@ -16,6 +16,9 @@
package com.android.server.voiceinteraction;
+import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_ATTENTION_STATE;
+import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_STREAMING_STATE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -30,6 +33,7 @@
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.ISandboxedDetectionService;
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
+import android.service.voice.VisualQueryDetectionServiceFailure;
import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
@@ -102,6 +106,13 @@
mAttentionListener.onAttentionGained();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention gained event.", e);
+ try {
+ callback.onDetectionFailure(new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_ATTENTION_STATE,
+ "Attention listener failed to switch to GAINED state."));
+ } catch (RemoteException ex) {
+ Slog.v(TAG, "Fail to call onDetectionFailure");
+ }
return;
}
}
@@ -117,6 +128,13 @@
mAttentionListener.onAttentionLost();
} catch (RemoteException e) {
Slog.e(TAG, "Error delivering attention lost event.", e);
+ try {
+ callback.onDetectionFailure(new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_ATTENTION_STATE,
+ "Attention listener failed to switch to LOST state."));
+ } catch (RemoteException ex) {
+ Slog.v(TAG, "Fail to call onDetectionFailure");
+ }
return;
}
}
@@ -127,6 +145,9 @@
Slog.v(TAG, "BinderCallback#onQueryDetected");
if (!mEgressingData) {
Slog.v(TAG, "Query should not be egressed within the unattention state.");
+ callback.onDetectionFailure(new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot stream queries without attention signals."));
return;
}
mQueryStreaming = true;
@@ -140,6 +161,9 @@
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal FINISHED is block since there is"
+ " no active query being streamed.");
+ callback.onDetectionFailure(new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot send FINISHED signal with no query streamed."));
return;
}
callback.onQueryFinished();
@@ -152,6 +176,9 @@
if (!mQueryStreaming) {
Slog.v(TAG, "Query streaming state signal REJECTED is block since there is"
+ " no active query being streamed.");
+ callback.onDetectionFailure(new VisualQueryDetectionServiceFailure(
+ ERROR_CODE_ILLEGAL_STREAMING_STATE,
+ "Cannot send REJECTED signal with no query streamed."));
return;
}
callback.onQueryRejected();