summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/AppOpsManager.java40
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java24
-rw-r--r--services/core/java/com/android/server/policy/AppOpsPolicy.java23
3 files changed, 80 insertions, 7 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b48a8fb73832..1dddf064e82a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1461,9 +1461,25 @@ public class AppOpsManager {
*/
public static final int OP_USE_FULL_SCREEN_INTENT = AppProtoEnums.APP_OP_USE_FULL_SCREEN_INTENT;
+ /**
+ * Hides camera indicator for sandboxed detection apps that directly access the service.
+ *
+ * @hide
+ */
+ public static final int OP_CAMERA_SANDBOXED =
+ AppProtoEnums.APP_OP_CAMERA_SANDBOXED;
+
+ /**
+ * Hides microphone indicator for sandboxed detection apps that directly access the service.
+ *
+ * @hide
+ */
+ public static final int OP_RECORD_AUDIO_SANDBOXED =
+ AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 134;
+ public static final int _NUM_OP = 136;
/**
* All app ops represented as strings.
@@ -1605,6 +1621,8 @@ public class AppOpsManager {
OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
OPSTR_BODY_SENSORS_WRIST_TEMPERATURE,
OPSTR_USE_FULL_SCREEN_INTENT,
+ OPSTR_CAMERA_SANDBOXED,
+ OPSTR_RECORD_AUDIO_SANDBOXED
})
public @interface AppOpString {}
@@ -2013,6 +2031,20 @@ public class AppOpsManager {
public static final String OPSTR_COARSE_LOCATION_SOURCE = "android:coarse_location_source";
/**
+ * Camera is being recorded in sandboxed detection process.
+ *
+ * @hide
+ */
+ public static final String OPSTR_CAMERA_SANDBOXED = "android:camera_sandboxed";
+
+ /**
+ * Audio is being recorded in sandboxed detection process.
+ *
+ * @hide
+ */
+ public static final String OPSTR_RECORD_AUDIO_SANDBOXED = "android:record_audio_sandboxed";
+
+ /**
* Allow apps to create the requests to manage the media files without user confirmation.
*
* @see android.Manifest.permission#MANAGE_MEDIA
@@ -2738,7 +2770,11 @@ public class AppOpsManager {
.setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_USE_FULL_SCREEN_INTENT, OPSTR_USE_FULL_SCREEN_INTENT,
"USE_FULL_SCREEN_INTENT").setPermission(Manifest.permission.USE_FULL_SCREEN_INTENT)
- .build()
+ .build(),
+ new AppOpInfo.Builder(OP_CAMERA_SANDBOXED, OPSTR_CAMERA_SANDBOXED,
+ "CAMERA_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
+ new AppOpInfo.Builder(OP_RECORD_AUDIO_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED,
+ "RECORD_AUDIO_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
};
// The number of longs needed to form a full bitmask of app ops
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 81ba4b813de1..a110169ac8c2 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -34,6 +34,7 @@ import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_CAMERA_SANDBOXED;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
@@ -42,6 +43,7 @@ import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO_SANDBOXED;
import static android.app.AppOpsManager.OP_VIBRATE;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
@@ -3027,17 +3029,29 @@ public class AppOpsService extends IAppOpsService.Stub {
packageName);
}
- // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
- // purposes and not as a check, also make sure that the caller is allowed to access
- // the data gated by OP_RECORD_AUDIO.
+ // As a special case for OP_RECORD_AUDIO_HOTWORD, OP_RECEIVE_AMBIENT_TRIGGER_AUDIO and
+ // OP_RECORD_AUDIO_SANDBOXED which we use only for attribution purposes and not as a check,
+ // also make sure that the caller is allowed to access the data gated by OP_RECORD_AUDIO.
//
// TODO: Revert this change before Android 12.
- if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
- int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
+ int result = MODE_DEFAULT;
+ if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO
+ || code == OP_RECORD_AUDIO_SANDBOXED) {
+ result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
+ // Check result
if (result != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(result, code, attributionTag, packageName);
}
}
+ // As a special case for OP_CAMERA_SANDBOXED.
+ if (code == OP_CAMERA_SANDBOXED) {
+ result = checkOperation(OP_CAMERA, uid, packageName);
+ // Check result
+ if (result != AppOpsManager.MODE_ALLOWED) {
+ return new SyncNotedAppOp(result, code, attributionTag, packageName);
+ }
+ }
+
return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 401eac6e2d19..7a5664f8135e 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -316,6 +316,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);
+ code = resolveSandboxedServiceOp(code, uid);
if (attributionTag == null) {
return code;
}
@@ -439,6 +440,28 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
return code;
}
+ private int resolveSandboxedServiceOp(int code, int uid) {
+ if (!Process.isIsolated(uid) // simple check which fails-fast for the common case
+ || !(code == AppOpsManager.OP_RECORD_AUDIO || code == AppOpsManager.OP_CAMERA)) {
+ return code;
+ }
+ final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
+ mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
+ if (hotwordDetectionServiceIdentity != null
+ && uid == hotwordDetectionServiceIdentity.getIsolatedUid()) {
+ // Upgrade the op such that no indicators is shown for camera or audio service. This
+ // will bypass the permission checking for the original OP_RECORD_AUDIO and OP_CAMERA.
+ switch (code) {
+ case AppOpsManager.OP_RECORD_AUDIO:
+ return AppOpsManager.OP_RECORD_AUDIO_SANDBOXED;
+ case AppOpsManager.OP_CAMERA:
+ return AppOpsManager.OP_CAMERA_SANDBOXED;
+ }
+ }
+ 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