Merge "send onFailure callback for asyncronous exceptions" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c3e906d1cf
@@ -18,6 +18,7 @@ package android.service.voice;
|
|||||||
|
|
||||||
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
|
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
|
||||||
import static android.Manifest.permission.RECORD_AUDIO;
|
import static android.Manifest.permission.RECORD_AUDIO;
|
||||||
|
import static android.service.voice.SoundTriggerFailure.ERROR_CODE_UNKNOWN;
|
||||||
import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
|
import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS;
|
||||||
|
|
||||||
import android.annotation.ElapsedRealtimeLong;
|
import android.annotation.ElapsedRealtimeLong;
|
||||||
@@ -269,6 +270,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
static final long THROW_ON_INITIALIZE_IF_NO_DSP = 269165460L;
|
static final long THROW_ON_INITIALIZE_IF_NO_DSP = 269165460L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gates returning {@link Callback#onFailure} and {@link Callback#onUnknownFailure}
|
||||||
|
* when asynchronous exceptions are propagated to the client. If the change is not enabled,
|
||||||
|
* the existing behavior of delivering {@link #STATE_ERROR} is retained.
|
||||||
|
*/
|
||||||
|
@ChangeId
|
||||||
|
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
|
static final long SEND_ON_FAILURE_FOR_ASYNC_EXCEPTIONS = 280471513L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls the sensitivity threshold adjustment factor for a given model.
|
* Controls the sensitivity threshold adjustment factor for a given model.
|
||||||
* Negative value corresponds to less sensitive model (high threshold) and
|
* Negative value corresponds to less sensitive model (high threshold) and
|
||||||
@@ -1409,12 +1419,16 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
|
if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
|
||||||
try {
|
try {
|
||||||
stopRecognitionLocked();
|
stopRecognitionLocked();
|
||||||
} catch (SecurityException e) {
|
} catch (Exception e) {
|
||||||
Slog.w(TAG, "Failed to Stop the recognition", e);
|
Slog.w(TAG, "Failed to stop recognition after enrollment update", e);
|
||||||
if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
|
if (CompatChanges.isChangeEnabled(SEND_ON_FAILURE_FOR_ASYNC_EXCEPTIONS)) {
|
||||||
throw e;
|
sendSoundTriggerFailure(new SoundTriggerFailure(ERROR_CODE_UNKNOWN,
|
||||||
}
|
"Failed to stop recognition after enrollment update: "
|
||||||
|
+ Log.getStackTraceString(e),
|
||||||
|
FailureSuggestedAction.RECREATE_DETECTOR));
|
||||||
|
} else {
|
||||||
updateAndNotifyStateChangedLocked(STATE_ERROR);
|
updateAndNotifyStateChangedLocked(STATE_ERROR);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1538,6 +1552,12 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private void updateAndNotifyStateChangedLocked(int availability) {
|
private void updateAndNotifyStateChangedLocked(int availability) {
|
||||||
|
updateAvailabilityLocked(availability);
|
||||||
|
notifyStateChangedLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private void updateAvailabilityLocked(int availability) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Slog.d(TAG, "Hotword availability changed from " + mAvailability
|
Slog.d(TAG, "Hotword availability changed from " + mAvailability
|
||||||
+ " -> " + availability);
|
+ " -> " + availability);
|
||||||
@@ -1545,7 +1565,6 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
if (!mIsAvailabilityOverriddenByTestApi) {
|
if (!mIsAvailabilityOverriddenByTestApi) {
|
||||||
mAvailability = availability;
|
mAvailability = availability;
|
||||||
}
|
}
|
||||||
notifyStateChangedLocked();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
@@ -1555,6 +1574,18 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
message.sendToTarget();
|
message.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private void sendUnknownFailure(String failureMessage) {
|
||||||
|
// update but do not call onAvailabilityChanged callback for STATE_ERROR
|
||||||
|
updateAvailabilityLocked(STATE_ERROR);
|
||||||
|
Message.obtain(mHandler, MSG_DETECTION_UNKNOWN_FAILURE, failureMessage).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendSoundTriggerFailure(@NonNull SoundTriggerFailure soundTriggerFailure) {
|
||||||
|
Message.obtain(mHandler, MSG_DETECTION_SOUND_TRIGGER_FAILURE, soundTriggerFailure)
|
||||||
|
.sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
static final class SoundTriggerListener extends IHotwordRecognitionStatusCallback.Stub {
|
static final class SoundTriggerListener extends IHotwordRecognitionStatusCallback.Stub {
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
@@ -1726,6 +1757,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(b/267681692): remove the AsyncTask usage
|
||||||
class RefreshAvailabilityTask extends AsyncTask<Void, Void, Void> {
|
class RefreshAvailabilityTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1744,15 +1776,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
|
|||||||
}
|
}
|
||||||
updateAndNotifyStateChangedLocked(availability);
|
updateAndNotifyStateChangedLocked(availability);
|
||||||
}
|
}
|
||||||
} catch (SecurityException e) {
|
} catch (Exception e) {
|
||||||
|
// Any exception here not caught will crash the process because AsyncTask does not
|
||||||
|
// bubble up the exceptions to the client app, so we must propagate it to the app.
|
||||||
Slog.w(TAG, "Failed to refresh availability", e);
|
Slog.w(TAG, "Failed to refresh availability", e);
|
||||||
if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
if (CompatChanges.isChangeEnabled(SEND_ON_FAILURE_FOR_ASYNC_EXCEPTIONS)) {
|
||||||
|
sendUnknownFailure(
|
||||||
|
"Failed to refresh availability: " + Log.getStackTraceString(e));
|
||||||
|
} else {
|
||||||
updateAndNotifyStateChangedLocked(STATE_ERROR);
|
updateAndNotifyStateChangedLocked(STATE_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,14 +74,22 @@ public final class SoundTriggerFailure implements Parcelable {
|
|||||||
public @interface SoundTriggerErrorCode {}
|
public @interface SoundTriggerErrorCode {}
|
||||||
|
|
||||||
private final int mErrorCode;
|
private final int mErrorCode;
|
||||||
|
private final int mSuggestedAction;
|
||||||
private final String mErrorMessage;
|
private final String mErrorMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@TestApi
|
@TestApi
|
||||||
public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode,
|
public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode, @NonNull String errorMessage) {
|
||||||
@NonNull String errorMessage) {
|
this(errorCode, errorMessage, getSuggestedActionBasedOnErrorCode(errorCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode, @NonNull String errorMessage,
|
||||||
|
@FailureSuggestedAction.FailureSuggestedActionDef int suggestedAction) {
|
||||||
if (TextUtils.isEmpty(errorMessage)) {
|
if (TextUtils.isEmpty(errorMessage)) {
|
||||||
throw new IllegalArgumentException("errorMessage is empty or null.");
|
throw new IllegalArgumentException("errorMessage is empty or null.");
|
||||||
}
|
}
|
||||||
@@ -95,7 +103,13 @@ public final class SoundTriggerFailure implements Parcelable {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid ErrorCode: " + errorCode);
|
throw new IllegalArgumentException("Invalid ErrorCode: " + errorCode);
|
||||||
}
|
}
|
||||||
|
if (suggestedAction != getSuggestedActionBasedOnErrorCode(errorCode)
|
||||||
|
&& errorCode != ERROR_CODE_UNKNOWN) {
|
||||||
|
throw new IllegalArgumentException("Invalid suggested next action: "
|
||||||
|
+ "errorCode=" + errorCode + ", suggestedAction=" + suggestedAction);
|
||||||
|
}
|
||||||
mErrorMessage = errorMessage;
|
mErrorMessage = errorMessage;
|
||||||
|
mSuggestedAction = suggestedAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +133,11 @@ public final class SoundTriggerFailure implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
@FailureSuggestedAction.FailureSuggestedActionDef
|
@FailureSuggestedAction.FailureSuggestedActionDef
|
||||||
public int getSuggestedAction() {
|
public int getSuggestedAction() {
|
||||||
switch (mErrorCode) {
|
return mSuggestedAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getSuggestedActionBasedOnErrorCode(@SoundTriggerErrorCode int errorCode) {
|
||||||
|
switch (errorCode) {
|
||||||
case ERROR_CODE_UNKNOWN:
|
case ERROR_CODE_UNKNOWN:
|
||||||
case ERROR_CODE_MODULE_DIED:
|
case ERROR_CODE_MODULE_DIED:
|
||||||
case ERROR_CODE_UNEXPECTED_PREEMPTION:
|
case ERROR_CODE_UNEXPECTED_PREEMPTION:
|
||||||
@@ -144,8 +162,11 @@ public final class SoundTriggerFailure implements Parcelable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SoundTriggerFailure { errorCode = " + mErrorCode + ", errorMessage = "
|
return "SoundTriggerFailure {"
|
||||||
+ mErrorMessage + " }";
|
+ " errorCode = " + mErrorCode
|
||||||
|
+ ", errorMessage = " + mErrorMessage
|
||||||
|
+ ", suggestedNextAction = " + mSuggestedAction
|
||||||
|
+ " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @NonNull Parcelable.Creator<SoundTriggerFailure> CREATOR =
|
public static final @NonNull Parcelable.Creator<SoundTriggerFailure> CREATOR =
|
||||||
|
|||||||
Reference in New Issue
Block a user