diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java index b8536f9045692..afee94000edc8 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java @@ -17,6 +17,8 @@ package com.android.server.voiceinteraction; import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; +import static android.Manifest.permission.LOG_COMPAT_CHANGE; +import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG; import static android.Manifest.permission.RECORD_AUDIO; import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL; @@ -43,11 +45,14 @@ import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENT import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_SECURITY_EXCEPTION; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_UNEXPECTED_CALLBACK; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECT_UNEXPECTED_CALLBACK; +import static com.android.server.voiceinteraction.HotwordDetectionConnection.ENFORCE_HOTWORD_PHRASE_ID; import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.AppOpsManager; +import android.app.compat.CompatChanges; import android.attention.AttentionManagerInternal; import android.content.Context; import android.content.PermissionChecker; @@ -692,8 +697,13 @@ abstract class DetectorSession { } } - static void enforceExtraKeyphraseIdNotLeaked(HotwordDetectedResult result, + @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE}) + void enforceExtraKeyphraseIdNotLeaked(HotwordDetectedResult result, SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) { + if (!CompatChanges.isChangeEnabled(ENFORCE_HOTWORD_PHRASE_ID, + mVoiceInteractionServiceUid)) { + return; + } // verify the phrase ID in HotwordDetectedResult is not exposing extra phrases // the DSP did not detect for (SoundTrigger.KeyphraseRecognitionExtra keyphrase : recognitionEvent.keyphraseExtras) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 591e35a49be6a..220ef21413db9 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -29,6 +29,8 @@ import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPH import android.annotation.NonNull; import android.annotation.Nullable; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.ContentCaptureOptions; import android.content.Context; @@ -39,6 +41,7 @@ import android.media.AudioFormat; import android.media.AudioManagerInternal; import android.media.permission.Identity; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; @@ -48,6 +51,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SharedMemory; import android.provider.DeviceConfig; +import android.service.voice.HotwordDetectedResult; import android.service.voice.HotwordDetectionService; import android.service.voice.HotwordDetector; import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback; @@ -83,6 +87,26 @@ final class HotwordDetectionConnection { private static final String TAG = "HotwordDetectionConnection"; static final boolean DEBUG = false; + /** + * For apps targeting Android API {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, + * implementors of the {@link HotwordDetectionService} must not augment the phrase IDs which are + * supplied via {@link HotwordDetectionService + * #onDetect(AlwaysOnHotwordDetector.EventPayload, long, HotwordDetectionService.Callback)}. + * + *

The {@link HotwordDetectedResult#getHotwordPhraseId()} must match one of the phrase IDs + * from the {@link android.service.voice.AlwaysOnHotwordDetector + * .EventPayload#getKeyphraseRecognitionExtras()} list. + *

+ * + *

This behavior change is made to ensure the {@link HotwordDetectionService} honors what + * it receives from the {@link android.hardware.soundtrigger.SoundTriggerModule}, and it + * cannot signal to the client application a phrase which was not origially detected. + *

+ */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public static final long ENFORCE_HOTWORD_PHRASE_ID = 215066299L; + private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds"; private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;