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

Commit c3e906d1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "send onFailure callback for asyncronous exceptions" into udc-dev

parents bb9e856e d06ad212
Loading
Loading
Loading
Loading
+47 −11
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.service.voice;

import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
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 android.annotation.ElapsedRealtimeLong;
@@ -269,6 +270,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
    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.
     * Negative value corresponds to less sensitive model (high threshold) and
@@ -1409,12 +1419,16 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
            if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
                try {
                    stopRecognitionLocked();
                } catch (SecurityException e) {
                    Slog.w(TAG, "Failed to Stop the recognition", e);
                    if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
                        throw e;
                    }
                } catch (Exception e) {
                    Slog.w(TAG, "Failed to stop recognition after enrollment update", e);
                    if (CompatChanges.isChangeEnabled(SEND_ON_FAILURE_FOR_ASYNC_EXCEPTIONS)) {
                        sendSoundTriggerFailure(new SoundTriggerFailure(ERROR_CODE_UNKNOWN,
                                "Failed to stop recognition after enrollment update: "
                                        + Log.getStackTraceString(e),
                                FailureSuggestedAction.RECREATE_DETECTOR));
                    } else {
                        updateAndNotifyStateChangedLocked(STATE_ERROR);
                    }
                    return;
                }
            }
@@ -1538,6 +1552,12 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {

    @GuardedBy("mLock")
    private void updateAndNotifyStateChangedLocked(int availability) {
        updateAvailabilityLocked(availability);
        notifyStateChangedLocked();
    }

    @GuardedBy("mLock")
    private void updateAvailabilityLocked(int availability) {
        if (DBG) {
            Slog.d(TAG, "Hotword availability changed from " + mAvailability
                    + " -> " + availability);
@@ -1545,7 +1565,6 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
        if (!mIsAvailabilityOverriddenByTestApi) {
            mAvailability = availability;
        }
        notifyStateChangedLocked();
    }

    @GuardedBy("mLock")
@@ -1555,6 +1574,18 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
        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 */
    static final class SoundTriggerListener extends IHotwordRecognitionStatusCallback.Stub {
        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> {

        @Override
@@ -1744,15 +1776,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
                    }
                    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);
                if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
                    throw e;
                }
                synchronized (mLock) {
                    if (CompatChanges.isChangeEnabled(SEND_ON_FAILURE_FOR_ASYNC_EXCEPTIONS)) {
                        sendUnknownFailure(
                                "Failed to refresh availability: " + Log.getStackTraceString(e));
                    } else {
                        updateAndNotifyStateChangedLocked(STATE_ERROR);
                    }
                }
            }

            return null;
        }
+26 −5
Original line number Diff line number Diff line
@@ -74,14 +74,22 @@ public final class SoundTriggerFailure implements Parcelable {
    public @interface SoundTriggerErrorCode {}

    private final int mErrorCode;
    private final int mSuggestedAction;
    private final String mErrorMessage;

    /**
     * @hide
     */
    @TestApi
    public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode,
            @NonNull String errorMessage) {
    public SoundTriggerFailure(@SoundTriggerErrorCode int errorCode, @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)) {
            throw new IllegalArgumentException("errorMessage is empty or null.");
        }
@@ -95,7 +103,13 @@ public final class SoundTriggerFailure implements Parcelable {
            default:
                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;
        mSuggestedAction = suggestedAction;
    }

    /**
@@ -119,7 +133,11 @@ public final class SoundTriggerFailure implements Parcelable {
     */
    @FailureSuggestedAction.FailureSuggestedActionDef
    public int getSuggestedAction() {
        switch (mErrorCode) {
        return mSuggestedAction;
    }

    private static int getSuggestedActionBasedOnErrorCode(@SoundTriggerErrorCode int errorCode) {
        switch (errorCode) {
            case ERROR_CODE_UNKNOWN:
            case ERROR_CODE_MODULE_DIED:
            case ERROR_CODE_UNEXPECTED_PREEMPTION:
@@ -144,8 +162,11 @@ public final class SoundTriggerFailure implements Parcelable {

    @Override
    public String toString() {
        return "SoundTriggerFailure { errorCode = " + mErrorCode + ", errorMessage = "
                + mErrorMessage + " }";
        return "SoundTriggerFailure {"
                + " errorCode = " + mErrorCode
                + ", errorMessage = " + mErrorMessage
                + ", suggestedNextAction = " + mSuggestedAction
                + " }";
    }

    public static final @NonNull Parcelable.Creator<SoundTriggerFailure> CREATOR =