From 91d9ac36e3d32f14c5f82433d257616614f639da Mon Sep 17 00:00:00 2001 From: Ahaan Ugale Date: Thu, 17 Jun 2021 22:41:07 -0700 Subject: [PATCH] Allow only HotwordDetectionService to note OP_RECORD_AUDIO_HOTWORD These ops do not incur the mic privacy indicator. The HotwordDetectionService runs in a sandbox, so it's fine to allow it to access the mic without notifying the user. Other clients that use the hotword audio source will have their ops downgraded to OP_RECORD_AUDIO (particularly the non-sandboxed partner to this service in the assistant app - the VoiceInteractionService). Bug: 186164881 Bug: 189967066 Test: manual - privacy indicator works as expected Change-Id: Id55a4fdcd0b8edfda3b969302542fc6009da3395 --- .../android/server/policy/AppOpsPolicy.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 563acf7692a06..a5b1327b68ec0 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -85,6 +85,12 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat @NonNull private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal; + /** + * Whether this device allows only the HotwordDetectionService to use OP_RECORD_AUDIO_HOTWORD + * which doesn't incur the privacy indicator. + */ + private final boolean mIsHotwordDetectionServiceRequired; + /** * The locking policy around the location tags is a bit special. Since we want to * avoid grabbing the lock on every op note we are taking the approach where the @@ -119,6 +125,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat mRoleManager = mContext.getSystemService(RoleManager.class); mVoiceInteractionManagerInternal = LocalServices.getService( VoiceInteractionManagerInternal.class); + mIsHotwordDetectionServiceRequired = isHotwordDetectionServiceRequired( + mContext.getPackageManager()); final LocationManagerInternal locationManagerInternal = LocalServices.getService( LocationManagerInternal.class); @@ -179,6 +187,12 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat initializeActivityRecognizersTags(); } + private static boolean isHotwordDetectionServiceRequired(PackageManager pm) { + // The HotwordDetectionService APIs aren't ready yet for Auto or TV. + return !(pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) + || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)); + } + @Override public int checkOperation(int code, int uid, String packageName, @Nullable String attributionTag, boolean raw, @@ -262,6 +276,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat private int resolveDatasourceOp(int code, int uid, @NonNull String packageName, @Nullable String attributionTag) { + code = resolveRecordAudioOp(code, uid); if (attributionTag == null) { return code; } @@ -382,6 +397,24 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat return code; } + private int resolveRecordAudioOp(int code, int uid) { + if (code == AppOpsManager.OP_RECORD_AUDIO_HOTWORD) { + if (!mIsHotwordDetectionServiceRequired) { + return code; + } + // Only the HotwordDetectionService can use the HOTWORD op which doesn't incur the + // privacy indicator. Downgrade to standard RECORD_AUDIO for other processes. + final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity = + mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity(); + if (hotwordDetectionServiceIdentity != null + && uid == hotwordDetectionServiceIdentity.getIsolatedUid()) { + return code; + } + return AppOpsManager.OP_RECORD_AUDIO; + } + return code; + } + private int resolveUid(int code, int uid) { // The HotwordDetectionService is an isolated service, which ordinarily cannot hold // permissions. So we allow it to assume the owning package identity for certain