diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 27d78e5b6fb1e..0021ad8e3a9ef 100755 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8956,6 +8956,8 @@ package android.permission { public final class PermissionManager { method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int); + method public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String); + method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource); method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set getAutoRevokeExemptionGrantedPackages(); method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set getAutoRevokeExemptionRequestedPackages(); method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion(); @@ -8963,6 +8965,9 @@ package android.permission { method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int); method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String); + field public static final int PERMISSION_GRANTED = 0; // 0x0 + field public static final int PERMISSION_HARD_DENIED = 2; // 0x2 + field public static final int PERMISSION_SOFT_DENIED = 1; // 0x1 } public static final class PermissionManager.SplitPermissionInfo { diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 4cd9fb933c2d0..db9d4e2e05355 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -37,6 +37,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.AttributionSource; import android.content.Context; +import android.content.PermissionChecker; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -80,6 +81,26 @@ import java.util.Set; public final class PermissionManager { private static final String LOG_TAG = PermissionManager.class.getName(); + /** + * The permission is granted. + */ + public static final int PERMISSION_GRANTED = 0; + + /** + * The permission is denied. Applicable only to runtime and app op permissions. + *

+ * The app isn't expecting the permission to be denied so that a "no-op" action should be taken, + * such as returning an empty result. + */ + public static final int PERMISSION_SOFT_DENIED = 1; + + /** + * The permission is denied. + *

+ * The app should receive a {@code SecurityException}, or an error through a relevant callback. + */ + public static final int PERMISSION_HARD_DENIED = 2; + /** @hide */ public static final String LOG_TAG_TRACE_GRANTS = "PermissionGrantTrace"; @@ -163,6 +184,69 @@ public final class PermissionManager { mUsageHelper = new PermissionUsageHelper(context); } + /** + * Checks whether a given data access chain described by the given {@link AttributionSource} + * has a given permission. + * + * NOTE: Use this method only for permission checks at the + * point where you will deliver the permission protected data to clients. + * + *

For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use {@link #checkPermissionForPreflight(String, AttributionSource)} + * to determine if the app has or may have location permission (if app has only foreground + * location the grant state depends on the app's fg/gb state) and this check will not + * leave a trace that permission protected data was delivered. When you are about to + * deliver the location data to a registered listener you should use this method which + * will evaluate the permission access based on the current fg/bg state of the app and + * leave a record that the data was accessed. + * + * @param permission The permission to check. + * @param attributionSource the permission identity + * @param message A message describing the reason the permission was checked + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. + * + * @see #checkPermissionForPreflight(String, AttributionSource) + */ + @PermissionCheckerManager.PermissionResult + public int checkPermissionForDataDelivery(@NonNull String permission, + @NonNull AttributionSource attributionSource, @Nullable String message) { + return PermissionChecker.checkPermissionForDataDelivery(mContext, permission, + // FIXME(b/199526514): PID should be passed inside AttributionSource. + PermissionChecker.PID_UNKNOWN, attributionSource, message); + } + + /** + * Checks whether a given data access chain described by the given {@link AttributionSource} + * has a given permission. + * + * NOTE: Use this method only for permission checks at the + * preflight point where you will not deliver the permission protected data + * to clients but schedule permission data delivery, apps register listeners, + * etc. + * + *

For example, if an app registers a data listener it should have the required + * permission but no data is actually sent to the app at the moment of registration + * and you should use this method to determine if the app has or may have the + * permission and this check will not leave a trace that permission protected data + * was delivered. When you are about to deliver the protected data to a registered + * listener you should use {@link #checkPermissionForDataDelivery(String, + * AttributionSource, String)} which will evaluate the permission access based + * on the current fg/bg state of the app and leave a record that the data was accessed. + * + * @param permission The permission to check. + * @param attributionSource The identity for which to check the permission. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. + */ + @PermissionCheckerManager.PermissionResult + public int checkPermissionForPreflight(@NonNull String permission, + @NonNull AttributionSource attributionSource) { + return PermissionChecker.checkPermissionForPreflight(mContext, permission, + attributionSource); + } + /** * Retrieve all of the information we know about a particular permission. *