From d2b132fac44c38aea685db9170f24cf93a25ca99 Mon Sep 17 00:00:00 2001 From: Michael Wachenschwanz Date: Wed, 1 Apr 2020 16:28:46 -0700 Subject: [PATCH] Add permission check to UsageStatsManager#isAppInactive UsageStatsManager#isAppInactive provides usage information that is usually gated by the PACKAGE_USAGE_STATS permission in similar API. This updates isAppInactive to also check for the PACKAGE_USAGE_STATS permission. Test: atest android.app.usage.cts android.app.usage.cts.UsageStatsTest#testIsAppInactive Fixes: 148991455 Change-Id: I8ff8eb5d2e887bc164095f38d374e3992808fe79 --- .../android/app/usage/IUsageStatsManager.aidl | 2 +- .../android/app/usage/UsageStatsManager.java | 9 +++++++-- .../server/am/ActivityManagerShellCommand.java | 2 +- .../server/usage/UsageStatsService.java | 18 +++++++++++++++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 1211c731e2e1d..ed6ba0c5efa47 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -43,7 +43,7 @@ interface IUsageStatsManager { @UnsupportedAppUsage void setAppInactive(String packageName, boolean inactive, int userId); @UnsupportedAppUsage - boolean isAppInactive(String packageName, int userId); + boolean isAppInactive(String packageName, int userId, String callingPackage); 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 2c701b48455cf..5c6f07fd5100c 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -601,12 +601,17 @@ public final class UsageStatsManager { * app hasn't been used directly or indirectly for a period of time defined by the system. This * could be of the order of several hours or days. Apps are not considered inactive when the * device is charging. + *

The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} to query the + * inactive state of other apps

+ * * @param packageName The package name of the app to query - * @return whether the app is currently considered inactive + * @return whether the app is currently considered inactive or false if querying another app + * without {@link android.Manifest.permission#PACKAGE_USAGE_STATS} */ public boolean isAppInactive(String packageName) { try { - return mService.isAppInactive(packageName, mContext.getUserId()); + return mService.isAppInactive(packageName, mContext.getUserId(), + mContext.getOpPackageName()); } catch (RemoteException e) { // fall through and return default } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index bf797291380a2..19b084b74a8f8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2493,7 +2493,7 @@ final class ActivityManagerShellCommand extends ShellCommand { IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService( Context.USAGE_STATS_SERVICE)); - boolean isIdle = usm.isAppInactive(packageName, userId); + boolean isIdle = usm.isAppInactive(packageName, userId, SHELL_PACKAGE_NAME); pw.println("Idle=" + isIdle); return 0; } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 0d1b3523bf9b2..a2b15f323e180 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1578,15 +1578,27 @@ public class UsageStatsService extends SystemService implements } @Override - public boolean isAppInactive(String packageName, int userId) { + public boolean isAppInactive(String packageName, int userId, String callingPackage) { + final int callingUid = Binder.getCallingUid(); try { userId = ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(), - Binder.getCallingUid(), userId, false, false, "isAppInactive", null); + callingUid, userId, false, false, "isAppInactive", null); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } + + // If the calling app is asking about itself, continue, else check for permission. + if (packageName.equals(callingPackage)) { + final int actualCallingUid = mPackageManagerInternal.getPackageUidInternal( + callingPackage, 0, userId); + if (actualCallingUid != callingUid) { + return false; + } + } else if (!hasPermission(callingPackage)) { + return false; + } final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller( - Binder.getCallingUid(), userId); + callingUid, userId); final long token = Binder.clearCallingIdentity(); try { return mAppStandby.isAppIdleFiltered(