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

Commit aa186ef5 authored by Ajay Gopi's avatar Ajay Gopi Committed by Android (Google) Code Review
Browse files

Merge "Shutdown hotword detection service when voice activation op is disabled." into main

parents 4d43529d cda7de51
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12788,6 +12788,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_SECURITY_EXCEPTION = 9; // 0x9
    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
  }
+9 −1
Original line number Diff line number Diff line
@@ -89,6 +89,11 @@ public final class HotwordDetectionServiceFailure implements Parcelable {
    @FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
    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
     */
@@ -100,7 +105,10 @@ public final class HotwordDetectionServiceFailure implements Parcelable {
            ERROR_CODE_DETECT_TIMEOUT,
            ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION,
            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)
    public @interface HotwordDetectionServiceErrorCode {}
+78 −0
Original line number Diff line number Diff line
@@ -179,6 +179,31 @@ final class HotwordDetectionConnection {
    private final SparseArray<DetectorSession> mDetectorSessions =
            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,
            Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName,
            ComponentName visualQueryDetectionServiceName, int userId,
@@ -216,6 +241,10 @@ final class HotwordDetectionConnection {

        mLastRestartInstant = Instant.now();

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

        if (mReStartPeriodSeconds <= 0) {
            mCancellationTaskFuture = null;
        } else {
@@ -299,7 +328,11 @@ final class HotwordDetectionConnection {
        }
        if (mAudioFlinger != null) {
            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")
@@ -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 {
        private final HotwordDetectionConnection mHotwordDetectionConnection;
        private final IHotwordRecognitionStatusCallback mExternalCallback;