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

Commit 7a00f665 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

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

parents 8a233938 c3e906d1
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 =