From 835283f000a0077d5df746cc89905b3365e49b55 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 20 Nov 2019 14:41:22 -0800 Subject: [PATCH] Adding temp whitelist methods to PowerWhitelistManager interface. Migrating temp whitelist APIs to PowerWhitelistManager to allow telephony to add apps to the temp whitelist. Bug: 138239060 Bug: 140141678 Bug: 141155196 Bug: 142420609 Bug: 144864180 Test: atest PowerWhitelistTest Change-Id: Iefd6ecf89aad46de042ef3a1ec0c20d6c35da5a6 --- .../java/android/os/DeviceIdleManager.java | 4 + .../android/os/IDeviceIdleController.aidl | 1 + .../android/os/PowerWhitelistManager.java | 85 +++++++++++++++++++ .../android/server/DeviceIdleController.java | 12 ++- api/system-current.txt | 8 +- api/test-current.txt | 5 ++ .../android/app/usage/IUsageStatsManager.aidl | 1 - .../android/app/usage/UsageStatsManager.java | 12 +-- core/java/android/os/UserHandle.java | 21 +++-- .../server/usage/UsageStatsService.java | 16 ---- 10 files changed, 133 insertions(+), 32 deletions(-) diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java index 0568beb34e084..8019d4fdb8704 100644 --- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java +++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java @@ -44,6 +44,10 @@ public class DeviceIdleManager { mService = service; } + IDeviceIdleController getService() { + return mService; + } + /** * @return package names the system has white-listed to opt out of power save restrictions, * except for device idle mode. diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl index 21ce5ccd3ccc5..643d47ca5c6a6 100644 --- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl +++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl @@ -45,6 +45,7 @@ interface IDeviceIdleController { void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason); + long whitelistAppTemporarily(String name, int userId, String reason); void exitIdle(String reason); int setPreIdleTimeoutMode(int Mode); void resetPreIdleTimeoutMode(); diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java index 06ed52d7f5869..7a3ed92c15564 100644 --- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java +++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java @@ -16,12 +16,17 @@ package android.os; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Interface to access and modify the power save whitelist. * @@ -32,11 +37,91 @@ import android.content.Context; @SystemService(Context.POWER_WHITELIST_MANAGER) public class PowerWhitelistManager { private final Context mContext; + // Proxy to DeviceIdleController for now + // TODO: migrate to PowerWhitelistController + private final IDeviceIdleController mService; + + /** + * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle + * it. + */ + public static final int EVENT_UNSPECIFIED = 0; + + /** + * Indicates that an SMS event has occurred and the app should be whitelisted to handle it. + */ + public static final int EVENT_SMS = 1; + + /** + * Indicates that an MMS event has occurred and the app should be whitelisted to handle it. + */ + public static final int EVENT_MMS = 2; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"EVENT_"}, value = { + EVENT_UNSPECIFIED, + EVENT_SMS, + EVENT_MMS, + }) + public @interface WhitelistEvent { + } /** * @hide */ public PowerWhitelistManager(@NonNull Context context) { mContext = context; + mService = context.getSystemService(DeviceIdleManager.class).getService(); + } + + /** + * Add an app to the temporary whitelist for a short amount of time. + * + * @param packageName The package to add to the temp whitelist + * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds) + */ + @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) + public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) { + String reason = "from:" + UserHandle.formatUid(Binder.getCallingUid()); + try { + mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(), + reason); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Add an app to the temporary whitelist for a short amount of time for a specific reason. + * + * @param packageName The package to add to the temp whitelist + * @param event The reason to add the app to the temp whitelist + * @param reason A human-readable reason explaining why the app is temp whitelisted. Only used + * for logging purposes + * @return The duration (in milliseconds) that the app is whitelisted for + */ + @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) + public long whitelistAppTemporarilyForEvent(@NonNull String packageName, + @WhitelistEvent int event, @NonNull String reason) { + try { + switch (event) { + case EVENT_MMS: + return mService.addPowerSaveTempWhitelistAppForMms( + packageName, mContext.getUserId(), reason); + case EVENT_SMS: + return mService.addPowerSaveTempWhitelistAppForSms( + packageName, mContext.getUserId(), reason); + case EVENT_UNSPECIFIED: + default: + return mService.whitelistAppTemporarily( + packageName, mContext.getUserId(), reason); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return 0; + } } } diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index dfe7a90ba246d..701ea849c38f1 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -1662,7 +1662,17 @@ public class DeviceIdleController extends SystemService return isPowerSaveWhitelistAppInternal(name); } - @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration, + @Override + public long whitelistAppTemporarily(String packageName, int userId, String reason) + throws RemoteException { + // At least 10 seconds. + long duration = Math.max(10_000L, mConstants.MAX_TEMP_APP_WHITELIST_DURATION / 2); + addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason); + return duration; + } + + @Override + public void addPowerSaveTempWhitelistApp(String packageName, long duration, int userId, String reason) throws RemoteException { addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason); } diff --git a/api/system-current.txt b/api/system-current.txt index aa7d9c1dd76e8..1b5e693e81cc2 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1283,7 +1283,7 @@ package android.app.usage { method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void unregisterAppUsageLimitObserver(int); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterAppUsageObserver(int); method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterUsageSessionObserver(int); - method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle); + method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle); field public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID"; field public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT"; field public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED"; @@ -5746,6 +5746,11 @@ package android.os { } public class PowerWhitelistManager { + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long); + method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String); + field public static final int EVENT_MMS = 2; // 0x2 + field public static final int EVENT_SMS = 1; // 0x1 + field public static final int EVENT_UNSPECIFIED = 0; // 0x0 } public class RecoverySystem { @@ -5874,6 +5879,7 @@ package android.os { } public final class UserHandle implements android.os.Parcelable { + method @NonNull public static String formatUid(int); method public static int getAppId(int); method public int getIdentifier(); method @Deprecated public boolean isOwner(); diff --git a/api/test-current.txt b/api/test-current.txt index dacc5d67b7300..4d54664e40d14 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2044,6 +2044,11 @@ package android.os { } public class PowerWhitelistManager { + method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long); + method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String); + field public static final int EVENT_MMS = 2; // 0x2 + field public static final int EVENT_SMS = 1; // 0x1 + field public static final int EVENT_UNSPECIFIED = 0; // 0x0 } public class Process { diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 83c1d611226d4..1211c731e2e1d 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -44,7 +44,6 @@ interface IUsageStatsManager { void setAppInactive(String packageName, boolean inactive, int userId); @UnsupportedAppUsage boolean isAppInactive(String packageName, int userId); - void whitelistAppTemporarily(String packageName, long duration, int userId); void onCarrierPrivilegedAppsChanged(); void reportChooserSelection(String packageName, int userId, String contentType, in String[] annotations, String action); diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 1f13a1e13d13f..ab404d212730d 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -29,6 +29,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Build; +import android.os.PowerWhitelistManager; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -1044,15 +1045,16 @@ public final class UsageStatsManager { * @param user The user for whom the package should be whitelisted. Passing in a user that is * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission. * @see #isAppInactive(String) + * + * @deprecated Use + * {@link android.os.PowerWhitelistManager#whitelistAppTemporarily(String, long)} instead. */ @SystemApi @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) + @Deprecated public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) { - try { - mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier()); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + mContext.getSystemService(PowerWhitelistManager.class) + .whitelistAppTemporarily(packageName, duration); } /** diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 537cb98898059..62e83aa192aa8 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -393,8 +393,13 @@ public final class UserHandle implements Parcelable { /** * Generate a text representation of the uid, breaking out its individual * components -- user, app, isolated, etc. + * + * @param uid The uid to format + * @return A string representing the UID with its individual components broken out * @hide */ + @SystemApi + @NonNull public static String formatUid(int uid) { StringBuilder sb = new StringBuilder(); formatUid(sb, uid); @@ -520,7 +525,7 @@ public final class UserHandle implements Parcelable { public int hashCode() { return mHandle; } - + public int describeContents() { return 0; } @@ -532,10 +537,10 @@ public final class UserHandle implements Parcelable { /** * Write a UserHandle to a Parcel, handling null pointers. Must be * read with {@link #readFromParcel(Parcel)}. - * + * * @param h The UserHandle to be written. * @param out The Parcel in which the UserHandle will be placed. - * + * * @see #readFromParcel(Parcel) */ public static void writeToParcel(UserHandle h, Parcel out) { @@ -545,23 +550,23 @@ public final class UserHandle implements Parcelable { out.writeInt(USER_NULL); } } - + /** * Read a UserHandle from a Parcel that was previously written * with {@link #writeToParcel(UserHandle, Parcel)}, returning either * a null or new object as appropriate. - * + * * @param in The Parcel from which to read the UserHandle * @return Returns a new UserHandle matching the previously written * object, or null if a null had been written. - * + * * @see #writeToParcel(UserHandle, Parcel) */ public static UserHandle readFromParcel(Parcel in) { int h = in.readInt(); return h != USER_NULL ? new UserHandle(h) : null; } - + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public UserHandle createFromParcel(Parcel in) { @@ -581,7 +586,7 @@ public final class UserHandle implements Parcelable { * must not use this with data written by * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible * to handle a null UserHandle here. - * + * * @param in The Parcel containing the previously written UserHandle, * positioned at the location in the buffer where it was written. */ diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 63b062e91c986..ba4a4484f09b6 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -62,12 +62,10 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; -import android.os.IDeviceIdleController; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -150,7 +148,6 @@ public class UsageStatsService extends SystemService implements UserManager mUserManager; PackageManager mPackageManager; PackageManagerInternal mPackageManagerInternal; - IDeviceIdleController mDeviceIdleController; // Do not use directly. Call getDpmInternal() instead DevicePolicyManagerInternal mDpmInternal; @@ -265,9 +262,6 @@ public class UsageStatsService extends SystemService implements // initialize mDpmInternal getDpmInternal(); - mDeviceIdleController = IDeviceIdleController.Stub.asInterface( - ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); - if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) { try { ActivityManager.getService().registerUidObserver(mUidObserver, @@ -1625,16 +1619,6 @@ public class UsageStatsService extends SystemService implements } } - @Override - public void whitelistAppTemporarily(String packageName, long duration, int userId) - throws RemoteException { - StringBuilder reason = new StringBuilder(32); - reason.append("from:"); - UserHandle.formatUid(reason, Binder.getCallingUid()); - mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId, - reason.toString()); - } - @Override public void onCarrierPrivilegedAppsChanged() { if (DEBUG) {