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

Commit 392c84af authored by Kevin Han's avatar Kevin Han
Browse files

Add pkg visibility checks to all hibernation APIs

Ensure that hibernation APIs only return packages that are visible to
the caller UI.

Bug: 216536865
Test: atest AppHibernationTest
Change-Id: I87dba5cb24bf090960680417823c335fcfd084c0
parent da6dafc0
Loading
Loading
Loading
Loading
+22 −7
Original line number Diff line number Diff line
@@ -230,8 +230,10 @@ public final class AppHibernationService extends SystemService {
            }
            final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
            final UserLevelState pkgState = packageStates.get(packageName);
            if (pkgState == null) {
                Slog.e(TAG, String.format("Package %s is not installed for user %s",
            if (pkgState == null
                    || !mPackageManagerInternal.canQueryPackage(
                            Binder.getCallingUid(), packageName)) {
                Slog.e(TAG, TextUtils.formatSimple("Package %s is not installed for user %s",
                        packageName, userId));
                return false;
            }
@@ -254,7 +256,9 @@ public final class AppHibernationService extends SystemService {
                "Caller does not have MANAGE_APP_HIBERNATION permission.");
        synchronized (mLock) {
            GlobalLevelState state = mGlobalHibernationStates.get(packageName);
            if (state == null) {
            if (state == null
                    || !mPackageManagerInternal.canQueryPackage(
                            Binder.getCallingUid(), packageName)) {
                // This API can be legitimately called before installation finishes as part of
                // dex optimization, so we just return false here.
                return false;
@@ -285,8 +289,10 @@ public final class AppHibernationService extends SystemService {
            }
            final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId);
            final UserLevelState pkgState = packageStates.get(packageName);
            if (pkgState == null) {
                Slog.e(TAG, String.format("Package %s is not installed for user %s",
            if (pkgState == null
                    || !mPackageManagerInternal.canQueryPackage(
                            Binder.getCallingUid(), packageName)) {
                Slog.e(TAG, TextUtils.formatSimple("Package %s is not installed for user %s",
                        packageName, realUserId));
                return;
            }
@@ -334,8 +340,11 @@ public final class AppHibernationService extends SystemService {
                "Caller does not have MANAGE_APP_HIBERNATION permission.");
        synchronized (mLock) {
            GlobalLevelState state = mGlobalHibernationStates.get(packageName);
            if (state == null) {
                Slog.e(TAG, String.format("Package %s is not installed for any user", packageName));
            if (state == null
                    || !mPackageManagerInternal.canQueryPackage(
                            Binder.getCallingUid(), packageName)) {
                Slog.e(TAG, TextUtils.formatSimple(
                        "Package %s is not installed for any user", packageName));
                return;
            }
            if (state.hibernated != isHibernating) {
@@ -372,6 +381,12 @@ public final class AppHibernationService extends SystemService {
            }
            Map<String, UserLevelState> userStates = mUserStates.get(userId);
            for (UserLevelState state : userStates.values()) {
                String packageName = state.packageName;
                if (!mPackageManagerInternal.canQueryPackage(
                        Binder.getCallingUid(), packageName)) {
                    // Package is not visible to caller
                    continue;
                }
                if (state.hibernated) {
                    hibernatingPackages.add(state.packageName);
                }
+23 −0
Original line number Diff line number Diff line
@@ -234,6 +234,29 @@ public final class AppHibernationServiceTest {
        assertTrue(hibernatingPackages.contains(PACKAGE_NAME_2));
    }

    @Test
    public void testGetHibernatingPackagesForUser_doesNotReturnPackagesThatArentVisible()
            throws RemoteException {
        // GIVEN an unlocked user with all packages installed but only some are visible to the
        // caller
        UserInfo userInfo =
                addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
        doReturn(false).when(mPackageManagerInternal).canQueryPackage(anyInt(), eq(PACKAGE_NAME_2));
        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
        mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));

        // WHEN packages are hibernated for the user
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);

        // THEN the hibernating packages returned does not contain the package that was not visible
        List<String> hibernatingPackages =
                mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
        assertEquals(1, hibernatingPackages.size());
        assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
        assertFalse(hibernatingPackages.contains(PACKAGE_NAME_2));
    }

    @Test
    public void testUserLevelStatesInitializedFromDisk() throws RemoteException {
        // GIVEN states stored on disk that match with package manager's force-stop states