diff --git a/core/api/system-current.txt b/core/api/system-current.txt index f554e1f83cbd4..dab43525cb2ba 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -9699,12 +9699,17 @@ package android.permission { public final class PermissionControllerManager { method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void getHibernationEligibility(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer); method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); method public void getUnusedAppCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer); method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback); method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle); field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1 field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2 + field public static final int HIBERNATION_ELIGIBILITY_ELIGIBLE = 0; // 0x0 + field public static final int HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM = 1; // 0x1 + field public static final int HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER = 2; // 0x2 + field public static final int HIBERNATION_ELIGIBILITY_UNKNOWN = -1; // 0xffffffff field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2 field public static final int REASON_MALWARE = 1; // 0x1 } @@ -9722,6 +9727,7 @@ package android.permission { method @BinderThread public abstract void onCountPermissionApps(@NonNull java.util.List, int, @NonNull java.util.function.IntConsumer); method @BinderThread public abstract void onGetAppPermissions(@NonNull String, @NonNull java.util.function.Consumer>); method @BinderThread public void onGetGroupOfPlatformPermission(@NonNull String, @NonNull java.util.function.Consumer); + method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void onGetHibernationEligibility(@NonNull String, @NonNull java.util.function.IntConsumer); method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer>); method @BinderThread public void onGetPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer>); method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable); diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl index 0894e372efc2e..c9dd06cfaa434 100644 --- a/core/java/android/permission/IPermissionController.aidl +++ b/core/java/android/permission/IPermissionController.aidl @@ -56,6 +56,9 @@ oneway interface IPermissionController { in AndroidFuture callback); void getUnusedAppCount( in AndroidFuture callback); + void getHibernationEligibility( + in String packageName, + in AndroidFuture callback); void revokeOwnPermissionsOnKill(in String packageName, in List permissions, in AndroidFuture callback); } diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index a0115a94e7fe9..0cf06aa364ecd 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -128,6 +128,51 @@ public final class PermissionControllerManager { /** Count and app even if it is a system app. */ public static final int COUNT_WHEN_SYSTEM = 2; + /** @hide */ + @IntDef(prefix = { "HIBERNATION_ELIGIBILITY_"}, value = { + HIBERNATION_ELIGIBILITY_UNKNOWN, + HIBERNATION_ELIGIBILITY_ELIGIBLE, + HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM, + HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface HibernationEligibilityFlag {} + + /** + * Unknown whether package is eligible for hibernation. + * + * @hide + */ + @SystemApi + public static final int HIBERNATION_ELIGIBILITY_UNKNOWN = -1; + + /** + * Package is eligible for app hibernation and may be hibernated when the job runs. + * + * @hide + */ + @SystemApi + public static final int HIBERNATION_ELIGIBILITY_ELIGIBLE = 0; + + /** + * Package is not eligible for app hibernation because it is categorically exempt via the + * system. + * + * @hide + */ + @SystemApi + public static final int HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM = 1; + + /** + * Package is not eligible for app hibernation because it has been exempt by the user's + * preferences. Note that this should not be set if the package is exempt from hibernation by + * the system as the user preference would have no effect. + * + * @hide + */ + @SystemApi + public static final int HIBERNATION_ELIGIBILITY_EXEMPT_BY_USER = 2; + /** * Callback for delivering the result of {@link #revokeRuntimePermissions}. */ @@ -818,6 +863,39 @@ public final class PermissionControllerManager { }); } + /** + * Get the hibernation eligibility of a package. See {@link HibernationEligibilityFlag}. + * + * @param packageName package name to check eligibility + * @param executor executor to run callback on + * @param callback callback for when result is generated + */ + @RequiresPermission(Manifest.permission.MANAGE_APP_HIBERNATION) + public void getHibernationEligibility(@NonNull String packageName, + @NonNull @CallbackExecutor Executor executor, + @NonNull IntConsumer callback) { + checkNotNull(executor); + checkNotNull(callback); + + mRemoteService.postAsync(service -> { + AndroidFuture eligibilityResult = new AndroidFuture<>(); + service.getHibernationEligibility(packageName, eligibilityResult); + return eligibilityResult; + }).whenCompleteAsync((eligibility, err) -> { + if (err != null) { + Log.e(TAG, "Error getting hibernation eligibility", err); + callback.accept(HIBERNATION_ELIGIBILITY_UNKNOWN); + } else { + final long token = Binder.clearCallingIdentity(); + try { + callback.accept(eligibility); + } finally { + Binder.restoreCallingIdentity(token); + } + } + }, executor); + } + /** * Triggers the revocation of one or more permissions for a package, under the following * conditions: diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index b1e3cfc161dea..8d9f82b04b545 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -375,6 +375,22 @@ public abstract class PermissionControllerService extends Service { throw new AbstractMethodError("Must be overridden in implementing class"); } + /** + * Get the hibernation eligibility of the app. See + * {@link android.permission.PermissionControllerManager.HibernationEligibilityFlag}. + * + * @param packageName package to check eligibility + * @param callback callback after eligibility is returned + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MANAGE_APP_HIBERNATION) + public void onGetHibernationEligibility(@NonNull String packageName, + @NonNull IntConsumer callback) { + throw new AbstractMethodError("Must be overridden in implementing class"); + } + @Override public final @NonNull IBinder onBind(Intent intent) { return new IPermissionController.Stub() { @@ -668,6 +684,22 @@ public abstract class PermissionControllerService extends Service { } } + @Override + public void getHibernationEligibility(@NonNull String packageName, + @NonNull AndroidFuture callback) { + try { + Objects.requireNonNull(callback); + + enforceSomePermissionsGrantedToCaller( + Manifest.permission.MANAGE_APP_HIBERNATION); + + PermissionControllerService.this.onGetHibernationEligibility(packageName, + callback::complete); + } catch (Throwable t) { + callback.completeExceptionally(t); + } + } + @Override public void revokeOwnPermissionsOnKill(@NonNull String packageName, @NonNull List permissions, @NonNull AndroidFuture callback) {