Added new API to support UX for external device permission
The new API retrieves external device permissions and flags for a given package and persistentDeviceId
Bug: 322876542
Test: atest CtsPermissionMultiDeviceTestCases
Change-Id: I3527adab302c271ec42ce926b3e7c076ce2073d8
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f30c8cf..2d46e85 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11306,6 +11306,7 @@
method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource);
method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForStartDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
method public void finishDataDelivery(@NonNull String, @NonNull android.content.AttributionSource);
+ method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public java.util.Map<java.lang.String,android.permission.PermissionManager.PermissionState> getAllPermissionStates(@NonNull String, @NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public int getPermissionFlags(@NonNull String, @NonNull String, @NonNull String);
@@ -11325,6 +11326,14 @@
field public static final int PERMISSION_SOFT_DENIED = 1; // 0x1
}
+ @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public static final class PermissionManager.PermissionState implements android.os.Parcelable {
+ method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public int describeContents();
+ method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public int getFlags();
+ method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public boolean isGranted();
+ method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") @NonNull public static final android.os.Parcelable.Creator<android.permission.PermissionManager.PermissionState> CREATOR;
+ }
+
public static final class PermissionManager.SplitPermissionInfo {
method @NonNull public java.util.List<java.lang.String> getNewPermissions();
method @NonNull public String getSplitPermission();
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 380962c..4ae0a57 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -23,6 +23,7 @@
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.UserHandle;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager.PermissionState;
/**
* Interface to communicate directly with the permission manager service.
@@ -103,4 +104,12 @@
int userId);
int checkUidPermission(int uid, String permissionName, int deviceId);
+
+ Map<String, PermissionState> getAllPermissionStates(String packageName, String persistentDeviceId, int userId);
}
+
+/**
+ * Data class for the state of a permission requested by a package
+ * @hide
+ */
+parcelable PermissionManager.PermissionState;
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index d6e8ce7..e6b8102 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -66,6 +66,8 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -89,6 +91,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -1785,6 +1788,29 @@
}
/**
+ * Gets the permission states for requested package and persistent device.
+ *
+ * @param packageName name of the package you are checking against
+ * @param persistentDeviceId id of the persistent device you are checking against
+ * @return mapping of all permission states keyed by their permission names
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS)
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId) {
+ try {
+ return mPermissionManager.getAllPermissionStates(packageName, persistentDeviceId,
+ mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Make checkPermission() above bypass the permission cache in this process.
*
* @hide
@@ -1979,4 +2005,68 @@
}
}
}
+
+ /**
+ * Data class for the state of a permission requested by a package
+ *
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public static final class PermissionState implements Parcelable {
+ private final boolean mGranted;
+ private final int mFlags;
+
+ /** @hide */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public PermissionState(boolean granted, int flags) {
+ mGranted = granted;
+ mFlags = flags;
+ }
+
+ /**
+ * Returns whether this permission is granted
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public boolean isGranted() {
+ return mGranted;
+ }
+
+ /**
+ * Returns the flags associated with this permission state
+ * @see PackageManager#getPermissionFlags
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public int getFlags() {
+ return mFlags;
+ }
+
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeBoolean(mGranted);
+ parcel.writeInt(mFlags);
+ }
+
+ private PermissionState(Parcel parcel) {
+ this(parcel.readBoolean(), parcel.readInt());
+ }
+
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+ public static final @NonNull Creator<PermissionState> CREATOR = new Creator<>() {
+ public PermissionState createFromParcel(Parcel source) {
+ return new PermissionState(source);
+ }
+
+ public PermissionState[] newArray(int size) {
+ return new PermissionState[size];
+ }
+ };
+ }
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f1dca77..f44fcf0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -65,6 +65,7 @@
import android.permission.IPermissionManager;
import android.permission.PermissionCheckerManager;
import android.permission.PermissionManager;
+import android.permission.PermissionManager.PermissionState;
import android.permission.PermissionManagerInternal;
import android.service.voice.VoiceInteractionManagerInternal;
import android.util.ArrayMap;
@@ -258,6 +259,13 @@
}
@Override
+ public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId, int userId) {
+ return mPermissionManagerServiceImpl.getAllPermissionStates(packageName,
+ persistentDeviceId, userId);
+ }
+
+ @Override
public boolean setAutoRevokeExempted(
@NonNull String packageName, boolean exempted, int userId) {
Objects.requireNonNull(packageName);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 9afd36f..c5b637d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -999,6 +999,13 @@
return checkUidPermissionInternal(pkg, uid, permName);
}
+ @Override
+ public Map<String, PermissionManager.PermissionState> getAllPermissionStates(
+ @NonNull String packageName, @NonNull String persistentDeviceId, int userId) {
+ throw new UnsupportedOperationException(
+ "This method is supported in newer implementation only");
+ }
+
/**
* Checks whether or not the given package has been granted the specified
* permission. If the given package is {@code null}, we instead check the
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index b12d8ac..7c10425 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,6 +25,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager.PermissionState;
import android.permission.PermissionManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
@@ -406,6 +407,19 @@
int checkUidPermission(int uid, String permName, int deviceId);
/**
+ * Gets the permission states for requested package, persistent device and user.
+ *
+ * @param packageName name of the package you are checking against
+ * @param persistentDeviceId id of the persistent device you are checking against
+ * @param userId id of the user for which to get permission flags
+ * @return mapping of all permission states keyed by their permission names
+ *
+ * @hide
+ */
+ Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId, @UserIdInt int userId);
+
+ /**
* Get all the package names requesting app op permissions.
*
* @return a map of app op permission names to package names requesting them
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index 835ddcb..91a778d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -22,6 +22,7 @@
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager.PermissionState;
import android.util.Log;
import com.android.server.pm.pkg.AndroidPackage;
@@ -243,12 +244,20 @@
@Override
public int checkUidPermission(int uid, String permName, int deviceId) {
- Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
- + ", deviceId = " + deviceId + ")");
+ Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = "
+ + permName + ", deviceId = " + deviceId + ")");
return mService.checkUidPermission(uid, permName, deviceId);
}
@Override
+ public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId, int userId) {
+ Log.i(LOG_TAG, "getAllPermissionStates(packageName = " + packageName
+ + ", persistentDeviceId = " + persistentDeviceId + ", userId = " + userId + ")");
+ return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ }
+
+ @Override
public Map<String, Set<String>> getAllAppOpPermissionPackages() {
Log.i(LOG_TAG, "getAllAppOpPermissionPackages()");
return mService.getAllAppOpPermissionPackages();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 66a6f3c..0a4ff07 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -24,6 +24,7 @@
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.Build;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager.PermissionState;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
@@ -327,6 +328,12 @@
}
@Override
+ public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId, int userId) {
+ return mNewImplementation.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ }
+
+ @Override
public Map<String, Set<String>> getAllAppOpPermissionPackages() {
Map<String, Set<String>> oldVal = mOldImplementation.getAllAppOpPermissionPackages();
Map<String, Set<String>> newVal = mNewImplementation.getAllAppOpPermissionPackages();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index f21993c..bc29e67 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -23,6 +23,7 @@
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.Trace;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager.PermissionState;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
@@ -348,6 +349,18 @@
}
@Override
+ public Map<String, PermissionState> getAllPermissionStates(@NonNull String packageName,
+ @NonNull String persistentDeviceId, int userId) {
+ Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl"
+ + "#getAllPermissionStates");
+ try {
+ return mService.getAllPermissionStates(packageName, persistentDeviceId, userId);
+ } finally {
+ Trace.traceEnd(TRACE_TAG);
+ }
+ }
+
+ @Override
public Map<String, Set<String>> getAllAppOpPermissionPackages() {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#getAllAppOpPermissionPackages");
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 4c74878..5588276 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -1662,6 +1662,9 @@
): Int =
state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
+ fun GetStateScope.getAllPermissionFlags(appId: Int, userId: Int): IndexedMap<String, Int>? =
+ state.userStates[userId]?.appIdPermissionFlags?.get(appId)
+
fun MutateStateScope.setPermissionFlags(
appId: Int,
userId: Int,
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
index 3284cf1..3e3047c 100644
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
@@ -95,8 +95,8 @@
) {
packageNames.forEachIndexed { _, packageName ->
// The package may still be removed even if it was once notified as installed.
- val packageState = newState.externalState.packageStates[packageName]
- ?: return@forEachIndexed
+ val packageState =
+ newState.externalState.packageStates[packageName] ?: return@forEachIndexed
trimPermissionStates(packageState.appId)
}
}
@@ -226,6 +226,16 @@
return flags
}
+ fun GetStateScope.getAllPermissionFlags(
+ appId: Int,
+ persistentDeviceId: String,
+ userId: Int
+ ): IndexedMap<String, Int>? =
+ state.userStates[userId]
+ ?.appIdDevicePermissionFlags
+ ?.get(appId)
+ ?.get(persistentDeviceId)
+
fun MutateStateScope.setPermissionFlags(
appId: Int,
deviceId: String,
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 1241ce6..2f5c109 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -45,6 +45,7 @@
import android.permission.IOnPermissionsChangeListener
import android.permission.PermissionControllerManager
import android.permission.PermissionManager
+import android.permission.PermissionManager.PermissionState
import android.permission.flags.Flags
import android.provider.Settings
import android.util.ArrayMap
@@ -1135,6 +1136,53 @@
}
}
+ override fun getAllPermissionStates(
+ packageName: String,
+ persistentDeviceId: String,
+ userId: Int
+ ): Map<String, PermissionState> {
+ if (!userManagerInternal.exists(userId)) {
+ Slog.w(LOG_TAG, "getAllPermissionStates: Unknown user $userId")
+ return emptyMap()
+ }
+ enforceCallingOrSelfCrossUserPermission(
+ userId,
+ enforceFullPermission = true,
+ enforceShellRestriction = false,
+ "getAllPermissionStates"
+ )
+ enforceCallingOrSelfAnyPermission(
+ "getAllPermissionStates",
+ Manifest.permission.GET_RUNTIME_PERMISSIONS
+ )
+
+ val packageState =
+ packageManagerLocal.withFilteredSnapshot().use { it.getPackageState(packageName) }
+ if (packageState == null) {
+ Slog.w(LOG_TAG, "getAllPermissionStates: Unknown package $packageName")
+ return emptyMap()
+ }
+
+ val permissionFlagsMap =
+ service.getState {
+ if (persistentDeviceId == VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) {
+ with(policy) { getAllPermissionFlags(packageState.appId, userId) }
+ } else {
+ with(devicePolicy) {
+ getAllPermissionFlags(packageState.appId, persistentDeviceId, userId)
+ }
+ }
+ } ?: return emptyMap()
+
+ val permissionStates = ArrayMap<String, PermissionState>()
+ permissionFlagsMap.forEachIndexed { _, permissionName, flags ->
+ val granted = PermissionFlags.isPermissionGranted(flags)
+ val apiFlags = PermissionFlags.toApiFlags(flags)
+ permissionStates[permissionName] = PermissionState(granted, apiFlags)
+ }
+ return permissionStates
+ }
+
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,