Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b61d018 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Allow cross user usage event queries

For multipackage requests, caller must be system uid or hold
interact_across_users if not requesting fate for the same user.

For single package requests, caller must be system uid or the
same package and hold interact_across_users if not requesting data
for the current user.

In both cases the caller must have the usagestats permission.

Test: couldn't find automated tests for this file; manual
Bug: 79142791
Change-Id: I8d650f8e875e0e4578cb48c9ba42e821342852a0
parent f90662fe
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+71 −5
Original line number Diff line number Diff line
@@ -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, /*flags=*/ 0,
                    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<UsageStats> 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 {