Add API to get hibernation eligibility

Add an API to get a package's eligibility for hibernation for a given
user. A package is either eligible, exempt by the system, or exempt by
the user.

This information can be used to show more accurate UI for hibernation
controls (e.g. disabling the user-controlled exemption toggle if the app
is already exempt by the system)

Bug: 200087723
Test: CTS test in topic
Change-Id: Iea844477184fadb55ea14485dff172ed7be2b715
This commit is contained in:
Kevin Han
2022-01-05 19:21:15 -08:00
parent b5956636ff
commit 19166cb1fc
4 changed files with 119 additions and 0 deletions

View File

@@ -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<java.lang.Boolean>);
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<byte[]>);
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<java.lang.String,java.util.List<java.lang.String>>, 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<java.lang.String>, int, @NonNull java.util.function.IntConsumer);
method @BinderThread public abstract void onGetAppPermissions(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionPresentationInfo>>);
method @BinderThread public void onGetGroupOfPlatformPermission(@NonNull String, @NonNull java.util.function.Consumer<java.lang.String>);
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<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
method @BinderThread public void onGetPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);

View File

@@ -56,6 +56,9 @@ oneway interface IPermissionController {
in AndroidFuture<String> callback);
void getUnusedAppCount(
in AndroidFuture callback);
void getHibernationEligibility(
in String packageName,
in AndroidFuture callback);
void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}

View File

@@ -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<Integer> 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:

View File

@@ -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<String> permissions, @NonNull AndroidFuture callback) {