diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 00d8711c7baac..971352783dcb7 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -36,6 +36,8 @@ interface IUsageStatsManager { String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage); + UsageEvents queryEventsForUser(long beginTime, long endTime, int userId, String callingPackage); + UsageEvents queryEventsForPackageForUser(long beginTime, long endTime, int userId, String pkg, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); boolean isAppInactive(String packageName, int userId); void whitelistAppTemporarily(String packageName, long duration, int userId); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 71f9bb3f81276..17272f8ca67b3 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -699,6 +699,29 @@ public class UsageStatsService extends SystemService implements == PackageManager.PERMISSION_GRANTED; } + private void checkCallerIsSystemOrSameApp(String pkg) { + if (isCallingUidSystem()) { + return; + } + checkCallerIsSameApp(pkg); + } + + private void checkCallerIsSameApp(String pkg) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + + if (mPackageManagerInternal.getPackageUid(pkg, PackageManager.MATCH_ANY_USER, + callingUserId) != callingUid) { + throw new SecurityException("Calling uid " + pkg + " cannot query events" + + "for package " + pkg); + } + } + + private boolean isCallingUidSystem() { + final int uid = Binder.getCallingUid(); + return uid == Process.SYSTEM_UID; + } + @Override public ParceledListSlice queryUsageStats(int bucketType, long beginTime, long endTime, String callingPackage) { @@ -792,11 +815,7 @@ public class UsageStatsService extends SystemService implements final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER, - callingUserId) != callingUid) { - throw new SecurityException("Calling uid " + callingPackage + " cannot query events" - + "for package " + callingPackage); - } + checkCallerIsSameApp(callingPackage); final long token = Binder.clearCallingIdentity(); try { return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime, @@ -806,6 +825,53 @@ public class UsageStatsService extends SystemService implements } } + @Override + public UsageEvents queryEventsForUser(long beginTime, long endTime, int userId, + String callingPackage) { + if (!hasPermission(callingPackage)) { + return null; + } + + if (userId != UserHandle.getCallingUserId()) { + getContext().enforceCallingPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "No permission to query usage stats for this user"); + } + + final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller( + Binder.getCallingUid(), UserHandle.getCallingUserId()); + + final long token = Binder.clearCallingIdentity(); + try { + return UsageStatsService.this.queryEvents(userId, beginTime, endTime, + obfuscateInstantApps); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public UsageEvents queryEventsForPackageForUser(long beginTime, long endTime, + int userId, String pkg, String callingPackage) { + if (!hasPermission(callingPackage)) { + return null; + } + if (userId != UserHandle.getCallingUserId()) { + getContext().enforceCallingPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "No permission to query usage stats for this user"); + } + checkCallerIsSystemOrSameApp(pkg); + + final long token = Binder.clearCallingIdentity(); + try { + return UsageStatsService.this.queryEventsForPackage(userId, beginTime, + endTime, callingPackage); + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public boolean isAppInactive(String packageName, int userId) { try {