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
This commit is contained in:
Kevin Han
2022-02-01 15:15:48 -08:00
parent da6dafc0bb
commit 392c84af2c
2 changed files with 45 additions and 7 deletions

View File

@@ -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);
}

View File

@@ -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