Merge "Always check device policy for device aware permission check and AppOp mode checking" into main
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1a6e9b0..dc5974f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -22,14 +22,12 @@
import static android.permission.flags.Flags.shouldRegisterAttributionSource;
import static android.view.WindowManager.LayoutParams.WindowType;
-import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UiContext;
-import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
@@ -2367,47 +2365,11 @@
Log.v(TAG, "Treating renounced permission " + permission + " as denied");
return PERMISSION_DENIED;
}
- int deviceId = resolveDeviceIdForPermissionCheck(permission);
+ int deviceId = PermissionManager.resolveDeviceIdForPermissionCheck(this, getDeviceId(),
+ permission);
return PermissionManager.checkPermission(permission, pid, uid, deviceId);
}
- private int resolveDeviceIdForPermissionCheck(String permission) {
- // When checking a device-aware permission on a remote device, if the permission is CAMERA
- // or RECORD_AUDIO we need to check remote device's corresponding capability. If the remote
- // device doesn't have capability fall back to checking permission on the default device.
- // Note: we only perform permission check redirection when the device id is not explicitly
- // set in the context.
- int deviceId = getDeviceId();
- if (deviceId != Context.DEVICE_ID_DEFAULT
- && !mIsExplicitDeviceId
- && PermissionManager.DEVICE_AWARE_PERMISSIONS.contains(permission)) {
- VirtualDeviceManager virtualDeviceManager =
- getSystemService(VirtualDeviceManager.class);
- if (virtualDeviceManager == null) {
- Slog.e(
- TAG,
- "VDM is not enabled when device id is not default. deviceId = "
- + deviceId);
- } else {
- VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId);
- if (virtualDevice != null) {
- if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO)
- && !virtualDevice.hasCustomAudioInputSupport())
- || (Objects.equals(permission, Manifest.permission.CAMERA)
- && !virtualDevice.hasCustomCameraSupport())) {
- deviceId = Context.DEVICE_ID_DEFAULT;
- }
- } else {
- Slog.e(
- TAG,
- "virtualDevice is not found when device id is not default. deviceId = "
- + deviceId);
- }
- }
- }
- return deviceId;
- }
-
/** @hide */
@Override
public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
@@ -2511,7 +2473,8 @@
@Override
public int getPermissionRequestState(String permission) {
Objects.requireNonNull(permission, "Permission name can't be null");
- int deviceId = resolveDeviceIdForPermissionCheck(permission);
+ int deviceId = PermissionManager.resolveDeviceIdForPermissionCheck(this, getDeviceId(),
+ permission);
PermissionManager permissionManager = getSystemService(PermissionManager.class);
return permissionManager.getPermissionRequestState(getOpPackageName(), permission,
deviceId);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 5188204..561a2c9 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -16,6 +16,7 @@
package android.permission;
+import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -2039,12 +2040,49 @@
new PackageNamePermissionQuery(permName, pkgName, persistentDeviceId, userId));
}
+ /**
+ * When checking a device-aware permission on a remote device, if the permission is CAMERA
+ * or RECORD_AUDIO we need to check remote device's corresponding capability. If the remote
+ * device doesn't have capability fall back to checking permission on the default device.
+ *
+ * @hide
+ */
+ public static int resolveDeviceIdForPermissionCheck(@NonNull Context context, int deviceId,
+ @Nullable String permission) {
+ if (deviceId == Context.DEVICE_ID_DEFAULT || !DEVICE_AWARE_PERMISSIONS.contains(
+ permission)) {
+ return Context.DEVICE_ID_DEFAULT;
+ }
+
+ VirtualDeviceManager virtualDeviceManager =
+ context.getSystemService(VirtualDeviceManager.class);
+ if (virtualDeviceManager == null) {
+ Slog.e(LOG_TAG, "VDM is not enabled when device id is not default. deviceId = "
+ + deviceId);
+ } else {
+ VirtualDevice virtualDevice = virtualDeviceManager.getVirtualDevice(deviceId);
+ if (virtualDevice != null) {
+ if ((Objects.equals(permission, Manifest.permission.RECORD_AUDIO)
+ && !virtualDevice.hasCustomAudioInputSupport())
+ || (Objects.equals(permission, Manifest.permission.CAMERA)
+ && !virtualDevice.hasCustomCameraSupport())) {
+ deviceId = Context.DEVICE_ID_DEFAULT;
+ }
+ } else {
+ Slog.e(LOG_TAG,
+ "virtualDevice is not found when device id is not default. deviceId = "
+ + deviceId);
+ }
+ }
+ return deviceId;
+ }
+
@Nullable
private String getPersistentDeviceId(int deviceId) {
String persistentDeviceId = null;
if (deviceId == Context.DEVICE_ID_DEFAULT) {
- persistentDeviceId = VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
+ persistentDeviceId = PERSISTENT_DEVICE_ID_DEFAULT;
} else {
VirtualDeviceManager virtualDeviceManager = mContext.getSystemService(
VirtualDeviceManager.class);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index c8b8909..f7d7ed5 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3006,7 +3006,7 @@
UidState uidState = getUidStateLocked(uid, false);
if (uidState != null) {
int rawUidMode = mAppOpsCheckingService.getUidMode(
- uidState.uid, getPersistentId(virtualDeviceId), code);
+ uidState.uid, getPersistentDeviceIdForOp(virtualDeviceId, code), code);
if (rawUidMode != AppOpsManager.opToDefaultMode(code)) {
return raw ? rawUidMode :
@@ -3069,7 +3069,7 @@
int switchCode = AppOpsManager.opToSwitch(code);
int rawUidMode = mAppOpsCheckingService.getUidMode(uid,
- getPersistentId(virtualDeviceId), switchCode);
+ getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode);
if (rawUidMode != AppOpsManager.opToDefaultMode(switchCode)) {
return raw ? rawUidMode : evaluateForegroundMode(uid, switchCode, rawUidMode);
@@ -3396,7 +3396,7 @@
}
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag,
- getPersistentId(virtualDeviceId));
+ getPersistentDeviceIdForOp(virtualDeviceId, code));
if (attributedOp.isRunning()) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+ code + " startTime of in progress event="
@@ -3418,15 +3418,15 @@
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
- } else if (mAppOpsCheckingService.getUidMode(
- uidState.uid, getPersistentId(virtualDeviceId), switchCode)
+ } else if (mAppOpsCheckingService.getUidMode(uidState.uid,
+ getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode)
!= AppOpsManager.opToDefaultMode(switchCode)) {
final int uidMode =
uidState.evalMode(
code,
mAppOpsCheckingService.getUidMode(
uidState.uid,
- getPersistentId(virtualDeviceId),
+ getPersistentDeviceIdForOp(virtualDeviceId, switchCode),
switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
@@ -3478,7 +3478,8 @@
virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);
attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
- getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount);
+ getPersistentDeviceIdForOp(proxyVirtualDeviceId, code), uidState.getState(),
+ flags, notedCount);
if (shouldCollectAsyncNotedOp) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
@@ -4045,7 +4046,7 @@
}
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag,
- getPersistentId(virtualDeviceId));
+ getPersistentDeviceIdForOp(virtualDeviceId, code));
final UidState uidState = ops.uidState;
isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag,
virtualDeviceId, pvr.bypass, false);
@@ -4058,8 +4059,9 @@
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
} else if ((rawUidMode =
- mAppOpsCheckingService.getUidMode(
- uidState.uid, getPersistentId(virtualDeviceId), switchCode))
+ mAppOpsCheckingService.getUidMode(
+ uidState.uid, getPersistentDeviceIdForOp(virtualDeviceId, switchCode),
+ switchCode))
!= AppOpsManager.opToDefaultMode(switchCode)) {
final int uidMode = uidState.evalMode(code, rawUidMode);
if (!shouldStartForMode(uidMode, startIfModeDefault)) {
@@ -4107,11 +4109,13 @@
try {
if (isRestricted) {
attributedOp.createPaused(clientId, virtualDeviceId, proxyUid, proxyPackageName,
- proxyAttributionTag, getPersistentId(proxyVirtualDeviceId),
+ proxyAttributionTag,
+ getPersistentDeviceIdForOp(proxyVirtualDeviceId, code),
uidState.getState(), flags, attributionFlags, attributionChainId);
} else {
attributedOp.started(clientId, virtualDeviceId, proxyUid, proxyPackageName,
- proxyAttributionTag, getPersistentId(proxyVirtualDeviceId),
+ proxyAttributionTag,
+ getPersistentDeviceIdForOp(proxyVirtualDeviceId, code),
uidState.getState(), flags, attributionFlags, attributionChainId);
startType = START_TYPE_STARTED;
}
@@ -4179,15 +4183,15 @@
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default mode per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
- if (mAppOpsCheckingService.getUidMode(
- uidState.uid, getPersistentId(virtualDeviceId), switchCode)
+ if (mAppOpsCheckingService.getUidMode(uidState.uid,
+ getPersistentDeviceIdForOp(virtualDeviceId, switchCode), switchCode)
!= AppOpsManager.opToDefaultMode(switchCode)) {
final int uidMode =
uidState.evalMode(
code,
mAppOpsCheckingService.getUidMode(
uidState.uid,
- getPersistentId(virtualDeviceId),
+ getPersistentDeviceIdForOp(virtualDeviceId, switchCode),
switchCode));
if (!shouldStartForMode(uidMode, startIfModeDefault)) {
if (DEBUG) {
@@ -4350,7 +4354,8 @@
return;
}
final AttributedOp attributedOp =
- op.mDeviceAttributedOps.getOrDefault(getPersistentId(virtualDeviceId),
+ op.mDeviceAttributedOps.getOrDefault(
+ getPersistentDeviceIdForOp(virtualDeviceId, code),
new ArrayMap<>()).get(attributionTag);
if (attributedOp == null) {
Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
@@ -4641,7 +4646,8 @@
return true;
}
if (mVirtualDeviceManagerInternal == null) {
- return true;
+ Slog.w(TAG, "VirtualDeviceManagerInternal is null when device Id is non-default");
+ return false;
}
if (mVirtualDeviceManagerInternal.isValidVirtualDeviceId(virtualDeviceId)) {
mKnownDeviceIds.put(virtualDeviceId,
@@ -7310,7 +7316,13 @@
return packageNames;
}
- @NonNull private String getPersistentId(int virtualDeviceId) {
+ // For ops associated with device aware permissions, if virtual device id is non-default, we
+ // will return string version of that id provided the virtual device has corresponding camera or
+ // audio policy.
+ @NonNull private String getPersistentDeviceIdForOp(int virtualDeviceId, int op) {
+ virtualDeviceId = PermissionManager.resolveDeviceIdForPermissionCheck(mContext,
+ virtualDeviceId, AppOpsManager.opToPermission(op));
+
if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
return PERSISTENT_DEVICE_ID_DEFAULT;
}
@@ -7319,6 +7331,7 @@
}
String persistentId =
mVirtualDeviceManagerInternal.getPersistentIdForDevice(virtualDeviceId);
+
if (persistentId == null) {
persistentId = mKnownDeviceIds.get(virtualDeviceId);
}