diff options
3 files changed, 56 insertions, 19 deletions
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 248cc26ce656..ccc4ac28876a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -27,6 +27,7 @@ import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPH import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__SERVICE_CRASH; +import android.app.AppOpsManager; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.ChangeId; @@ -548,13 +549,15 @@ final class HotwordDetectionConnection { static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub { private final HotwordDetectionConnection mHotwordDetectionConnection; private final IHotwordRecognitionStatusCallback mExternalCallback; - private final int mVoiceInteractionServiceUid; + private final Identity mVoiceInteractorIdentity; + private final Context mContext; - SoundTriggerCallback(IHotwordRecognitionStatusCallback callback, - HotwordDetectionConnection connection, int uid) { + SoundTriggerCallback(Context context, IHotwordRecognitionStatusCallback callback, + HotwordDetectionConnection connection, Identity voiceInteractorIdentity) { + mContext = context; mHotwordDetectionConnection = connection; mExternalCallback = callback; - mVoiceInteractionServiceUid = uid; + mVoiceInteractorIdentity = voiceInteractorIdentity; } @Override @@ -568,15 +571,30 @@ final class HotwordDetectionConnection { HotwordMetricsLogger.writeKeyphraseTriggerEvent( HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP, HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER, - mVoiceInteractionServiceUid); + mVoiceInteractorIdentity.uid); mHotwordDetectionConnection.detectFromDspSource( recognitionEvent, mExternalCallback); } else { - HotwordMetricsLogger.writeKeyphraseTriggerEvent( - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER, - mVoiceInteractionServiceUid); - mExternalCallback.onKeyphraseDetected(recognitionEvent, null); + // We have to attribute ops here, since we configure all st clients as trusted to + // enable a partial exemption. + // TODO (b/292012931) remove once trusted uniformly required. + int result = mContext.getSystemService(AppOpsManager.class) + .noteOpNoThrow(AppOpsManager.OP_RECORD_AUDIO_HOTWORD, + mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, + mVoiceInteractorIdentity.attributionTag, + "Non-HDS keyphrase recognition to VoiceInteractionService"); + + if (result != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "onKeyphraseDetected suppressed, permission check returned: " + + result); + mExternalCallback.onRecognitionPaused(); + } else { + HotwordMetricsLogger.writeKeyphraseTriggerEvent( + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR, + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER, + mVoiceInteractorIdentity.uid); + mExternalCallback.onKeyphraseDetected(recognitionEvent, null); + } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 423a81ac0523..3574ef8e91fb 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -104,6 +104,7 @@ import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.LegacyPermissionManagerInternal; +import com.android.server.policy.AppOpsPolicy; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wm.ActivityTaskManagerInternal; @@ -336,6 +337,9 @@ public class VoiceInteractionManagerService extends SystemService { /** The start value of showSessionId */ private static final int SHOW_SESSION_START_ID = 0; + private final boolean IS_HDS_REQUIRED = AppOpsPolicy.isHotwordDetectionServiceRequired( + mContext.getPackageManager()); + @GuardedBy("this") private int mShowSessionId = SHOW_SESSION_START_ID; @@ -393,8 +397,14 @@ public class VoiceInteractionManagerService extends SystemService { } try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect( originatorIdentity)) { + if (!IS_HDS_REQUIRED) { + // For devices which still have hotword exemption, any client (not just HDS + // clients) are trusted. + // TODO (b/292012931) remove once trusted uniformly required. + forHotwordDetectionService = true; + } return new SoundTriggerSession(mSoundTriggerInternal.attach(client, - moduleProperties, forHotwordDetectionService)); + moduleProperties, forHotwordDetectionService), originatorIdentity); } } @@ -1674,10 +1684,13 @@ public class VoiceInteractionManagerService extends SystemService { final SoundTriggerInternal.Session mSession; private IHotwordRecognitionStatusCallback mSessionExternalCallback; private IRecognitionStatusCallback mSessionInternalCallback; + private final Identity mVoiceInteractorIdentity; SoundTriggerSession( - SoundTriggerInternal.Session session) { + SoundTriggerInternal.Session session, + Identity voiceInteractorIdentity) { mSession = session; + mVoiceInteractorIdentity = voiceInteractorIdentity; } @Override @@ -1731,7 +1744,8 @@ public class VoiceInteractionManagerService extends SystemService { if (mSessionExternalCallback == null || mSessionInternalCallback == null || callback.asBinder() != mSessionExternalCallback.asBinder()) { - mSessionInternalCallback = createSoundTriggerCallbackLocked(callback); + mSessionInternalCallback = createSoundTriggerCallbackLocked(callback, + mVoiceInteractorIdentity); mSessionExternalCallback = callback; } } @@ -1752,7 +1766,8 @@ public class VoiceInteractionManagerService extends SystemService { if (mSessionExternalCallback == null || mSessionInternalCallback == null || callback.asBinder() != mSessionExternalCallback.asBinder()) { - soundTriggerCallback = createSoundTriggerCallbackLocked(callback); + soundTriggerCallback = createSoundTriggerCallbackLocked(callback, + mVoiceInteractorIdentity); Slog.w(TAG, "stopRecognition() called with a different callback than" + "startRecognition()"); } else { @@ -2090,6 +2105,7 @@ public class VoiceInteractionManagerService extends SystemService { pw.println(" mTemporarilyDisabled: " + mTemporarilyDisabled); pw.println(" mCurUser: " + mCurUser); pw.println(" mCurUserSupported: " + mCurUserSupported); + pw.println(" mIsHdsRequired: " + IS_HDS_REQUIRED); dumpSupportedUsers(pw, " "); mDbHelper.dump(pw); if (mImpl == null) { @@ -2165,11 +2181,13 @@ public class VoiceInteractionManagerService extends SystemService { } private IRecognitionStatusCallback createSoundTriggerCallbackLocked( - IHotwordRecognitionStatusCallback callback) { + IHotwordRecognitionStatusCallback callback, + Identity voiceInteractorIdentity) { if (mImpl == null) { return null; } - return mImpl.createSoundTriggerCallbackLocked(callback); + return mImpl.createSoundTriggerCallbackLocked(mContext, callback, + voiceInteractorIdentity); } class RoleObserver implements OnRoleHoldersChangedListener { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 0ad86c11d29a..5d88a65ce29e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -877,12 +877,13 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } public IRecognitionStatusCallback createSoundTriggerCallbackLocked( - IHotwordRecognitionStatusCallback callback) { + Context context, IHotwordRecognitionStatusCallback callback, + Identity voiceInteractorIdentity) { if (DEBUG) { Slog.d(TAG, "createSoundTriggerCallbackLocked"); } - return new HotwordDetectionConnection.SoundTriggerCallback(callback, - mHotwordDetectionConnection, mInfo.getServiceInfo().applicationInfo.uid); + return new HotwordDetectionConnection.SoundTriggerCallback(context, callback, + mHotwordDetectionConnection, voiceInteractorIdentity); } private static ServiceInfo getServiceInfoLocked(@NonNull ComponentName componentName, |