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

Commit cda7de51 authored by Ajay Gopi's avatar Ajay Gopi
Browse files

Shutdown hotword detection service when voice activation op is disabled.

Test: atest -c --no-bazel-mode
CtsVoiceInteractionTestCases: HotwordDetectionServiceBasicTest
Bug: 305099192
Change-Id: I865561d9c3a31d8bade1357d3826a4315f29283f
parent ac4089a9
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -12789,6 +12789,7 @@ package android.service.voice {
    field @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") public static final int ERROR_CODE_ON_TRAINING_DATA_EGRESS_LIMIT_EXCEEDED = 8; // 0x8
    field @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") public static final int ERROR_CODE_ON_TRAINING_DATA_EGRESS_LIMIT_EXCEEDED = 8; // 0x8
    field @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") public static final int ERROR_CODE_ON_TRAINING_DATA_SECURITY_EXCEPTION = 9; // 0x9
    field @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") public static final int ERROR_CODE_ON_TRAINING_DATA_SECURITY_EXCEPTION = 9; // 0x9
    field public static final int ERROR_CODE_REMOTE_EXCEPTION = 7; // 0x7
    field public static final int ERROR_CODE_REMOTE_EXCEPTION = 7; // 0x7
    field @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") public static final int ERROR_CODE_SHUTDOWN_HDS_ON_VOICE_ACTIVATION_OP_DISABLED = 10; // 0xa
    field public static final int ERROR_CODE_UNKNOWN = 0; // 0x0
    field public static final int ERROR_CODE_UNKNOWN = 0; // 0x0
  }
  }
+9 −1
Original line number Original line Diff line number Diff line
@@ -89,6 +89,11 @@ public final class HotwordDetectionServiceFailure implements Parcelable {
    @FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
    @FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
    public static final int ERROR_CODE_ON_TRAINING_DATA_SECURITY_EXCEPTION = 9;
    public static final int ERROR_CODE_ON_TRAINING_DATA_SECURITY_EXCEPTION = 9;


    /** Indicates shutdown of {@link HotwordDetectionService} due to voice activation op being
     * disabled. */
    @FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
    public static final int ERROR_CODE_SHUTDOWN_HDS_ON_VOICE_ACTIVATION_OP_DISABLED = 10;

    /**
    /**
     * @hide
     * @hide
     */
     */
@@ -100,7 +105,10 @@ public final class HotwordDetectionServiceFailure implements Parcelable {
            ERROR_CODE_DETECT_TIMEOUT,
            ERROR_CODE_DETECT_TIMEOUT,
            ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION,
            ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION,
            ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE,
            ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE,
            ERROR_CODE_REMOTE_EXCEPTION
            ERROR_CODE_REMOTE_EXCEPTION,
            ERROR_CODE_ON_TRAINING_DATA_EGRESS_LIMIT_EXCEEDED,
            ERROR_CODE_ON_TRAINING_DATA_SECURITY_EXCEPTION,
            ERROR_CODE_SHUTDOWN_HDS_ON_VOICE_ACTIVATION_OP_DISABLED,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface HotwordDetectionServiceErrorCode {}
    public @interface HotwordDetectionServiceErrorCode {}
+78 −0
Original line number Original line Diff line number Diff line
@@ -179,6 +179,31 @@ final class HotwordDetectionConnection {
    private final SparseArray<DetectorSession> mDetectorSessions =
    private final SparseArray<DetectorSession> mDetectorSessions =
            new SparseArray<>();
            new SparseArray<>();


    /** Listens to changes to voice activation op. */
    private final AppOpsManager.OnOpChangedListener mOnOpChangedListener =
            new AppOpsManager.OnOpChangedListener() {
                @Override
                public void onOpChanged(String op, String packageName) {
                    if (op.equals(AppOpsManager.OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO)) {
                        AppOpsManager appOpsManager =
                                mContext.getSystemService(AppOpsManager.class);
                        synchronized (mLock) {
                            int checkOp = appOpsManager.unsafeCheckOpNoThrow(
                                    AppOpsManager.OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                                    mVoiceInteractorIdentity.uid,
                                    mVoiceInteractorIdentity.packageName);
                            // Voice activation app op disabled, safely shutdown hotword detection.
                            if (checkOp == AppOpsManager.MODE_ERRORED) {
                                Slog.i(TAG, "Shutdown hotword detection service on voice "
                                        + "activation op disabled.");
                                safelyShutdownHotwordDetectionOnVoiceActivationDisabledLocked();
                            }
                        }
                    }
                }
            };


    HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
    HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
            Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName,
            Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName,
            ComponentName visualQueryDetectionServiceName, int userId,
            ComponentName visualQueryDetectionServiceName, int userId,
@@ -216,6 +241,10 @@ final class HotwordDetectionConnection {


        mLastRestartInstant = Instant.now();
        mLastRestartInstant = Instant.now();


        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
        appOpsManager.startWatchingMode(AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                mVoiceInteractorIdentity.packageName, mOnOpChangedListener);

        if (mReStartPeriodSeconds <= 0) {
        if (mReStartPeriodSeconds <= 0) {
            mCancellationTaskFuture = null;
            mCancellationTaskFuture = null;
        } else {
        } else {
@@ -299,7 +328,11 @@ final class HotwordDetectionConnection {
        }
        }
        if (mAudioFlinger != null) {
        if (mAudioFlinger != null) {
            mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
            mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
            mAudioFlinger = null;
        }
        }
        // Unregister the on op mode changed listener.
        AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
        appOpsManager.stopWatchingMode(mOnOpChangedListener);
    }
    }


    @SuppressWarnings("GuardedBy")
    @SuppressWarnings("GuardedBy")
@@ -553,6 +586,51 @@ final class HotwordDetectionConnection {
        }
        }
    }
    }


    /**
     * Shutdowns down hotword detection service, swallowing exceptions.
     *
     * Called when voice activation app-op has been disabled.
     */
    @SuppressWarnings("GuardedBy")
    void safelyShutdownHotwordDetectionOnVoiceActivationDisabledLocked() {
        Slog.v(TAG, "safelyShutdownHotwordDetectionOnVoiceActivationDisabled");
        try {
            clearDebugHotwordLoggingTimeoutLocked();
            mRemoteExceptionListener = null;
            runForEachDetectorSessionLocked((session) -> {
                if (!(session instanceof VisualQueryDetectorSession)) {
                    // Inform all detector sessions that they got destroyed due to voice activation
                    // op being disabled.
                    session.reportErrorLocked(
                            new HotwordDetectionServiceFailure(
                                    HotwordDetectionServiceFailure
                                            .ERROR_CODE_SHUTDOWN_HDS_ON_VOICE_ACTIVATION_OP_DISABLED,
                                    "Shutdown hotword detection service on voice "
                                            + "activation op disabled!"));
                    session.destroyLocked();
                }
            });

            // Remove hotword detection sessions.
            mDetectorSessions.delete(HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP);
            mDetectorSessions.delete(HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE);

            mDebugHotwordLogging = false;
            unbindHotwordDetectionService();
            if (mCancellationTaskFuture != null) {
                mCancellationTaskFuture.cancel(/* mayInterruptIfRunning= */ true);
            }
            if (mAudioFlinger != null) {
                mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
                mAudioFlinger = null;
            }
        } catch (Exception e) {
            Slog.e(TAG, "Swallowing error while shutting down hotword detection."
                    + "Error message: " + e.getMessage());
        }
    }


    static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
    static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
        private final HotwordDetectionConnection mHotwordDetectionConnection;
        private final HotwordDetectionConnection mHotwordDetectionConnection;
        private final IHotwordRecognitionStatusCallback mExternalCallback;
        private final IHotwordRecognitionStatusCallback mExternalCallback;