Merge "Add/remove user state based off user unlocking"

This commit is contained in:
Treehugger Robot
2021-02-04 02:05:28 +00:00
committed by Gerrit Code Review
2 changed files with 40 additions and 65 deletions

View File

@@ -18,8 +18,6 @@ package com.android.server.apphibernation;
import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_REMOVED_FOR_ALL_USERS; import static android.content.Intent.EXTRA_REMOVED_FOR_ALL_USERS;
import static android.content.Intent.EXTRA_REPLACING; import static android.content.Intent.EXTRA_REPLACING;
import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_ALL;
@@ -36,7 +34,6 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.IPackageManager; import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.UserInfo;
import android.os.Binder; import android.os.Binder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ResultReceiver; import android.os.ResultReceiver;
@@ -48,6 +45,7 @@ import android.os.UserManager;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
@@ -107,11 +105,6 @@ public final class AppHibernationService extends SystemService {
final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
IntentFilter intentFilter = new IntentFilter(); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_USER_ADDED);
intentFilter.addAction(ACTION_USER_REMOVED);
userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_PACKAGE_ADDED); intentFilter.addAction(ACTION_PACKAGE_ADDED);
intentFilter.addAction(ACTION_PACKAGE_REMOVED); intentFilter.addAction(ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package"); intentFilter.addDataScheme("package");
@@ -123,19 +116,6 @@ public final class AppHibernationService extends SystemService {
publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub); publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub);
} }
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
synchronized (mLock) {
final List<UserInfo> users = mUserManager.getUsers();
// TODO: Pull from persistent disk storage. For now, just make from scratch.
for (UserInfo user : users) {
addUserPackageStatesL(user.id);
}
}
}
}
/** /**
* Whether a package is hibernating for a given user. * Whether a package is hibernating for a given user.
* *
@@ -145,11 +125,13 @@ public final class AppHibernationService extends SystemService {
*/ */
boolean isHibernatingForUser(String packageName, int userId) { boolean isHibernatingForUser(String packageName, int userId) {
userId = handleIncomingUser(userId, "isHibernating"); userId = handleIncomingUser(userId, "isHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
+ userId);
return false;
}
synchronized (mLock) { synchronized (mLock) {
final Map<String, UserPackageState> packageStates = mUserStates.get(userId); final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
if (packageStates == null) {
throw new IllegalArgumentException("No user associated with user id " + userId);
}
final UserPackageState pkgState = packageStates.get(packageName); final UserPackageState pkgState = packageStates.get(packageName);
if (pkgState == null) { if (pkgState == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -181,10 +163,12 @@ public final class AppHibernationService extends SystemService {
*/ */
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
userId = handleIncomingUser(userId, "setHibernating"); userId = handleIncomingUser(userId, "setHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
+ userId);
return;
}
synchronized (mLock) { synchronized (mLock) {
if (!mUserStates.contains(userId)) {
throw new IllegalArgumentException("No user associated with user id " + userId);
}
Map<String, UserPackageState> packageStates = mUserStates.get(userId); Map<String, UserPackageState> packageStates = mUserStates.get(userId);
UserPackageState pkgState = packageStates.get(packageName); UserPackageState pkgState = packageStates.get(packageName);
if (pkgState == null) { if (pkgState == null) {
@@ -310,15 +294,19 @@ public final class AppHibernationService extends SystemService {
mUserStates.put(userId, packages); mUserStates.put(userId, packages);
} }
private void onUserAdded(int userId) { @Override
public void onUserUnlocking(@NonNull TargetUser user) {
// TODO: Pull from persistent disk storage. For now, just make from scratch.
synchronized (mLock) { synchronized (mLock) {
addUserPackageStatesL(userId); addUserPackageStatesL(user.getUserIdentifier());
} }
} }
private void onUserRemoved(int userId) { @Override
public void onUserStopping(@NonNull TargetUser user) {
synchronized (mLock) { synchronized (mLock) {
mUserStates.remove(userId); // TODO: Flush to disk when persistence is implemented
mUserStates.remove(user.getUserIdentifier());
} }
} }
@@ -395,7 +383,7 @@ public final class AppHibernationService extends SystemService {
} }
} }
// Broadcast receiver for user and package add/removal events // Broadcast receiver for package add/removal events
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@@ -405,12 +393,6 @@ public final class AppHibernationService extends SystemService {
} }
final String action = intent.getAction(); final String action = intent.getAction();
if (ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
}
if (ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(userId);
}
if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) { if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) {
final String packageName = intent.getData().getSchemeSpecificPart(); final String packageName = intent.getData().getSchemeSpecificPart();
if (intent.getBooleanExtra(EXTRA_REPLACING, false)) { if (intent.getBooleanExtra(EXTRA_REPLACING, false)) {

View File

@@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import android.app.IActivityManager; import android.app.IActivityManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -87,7 +86,7 @@ public final class AppHibernationServiceTest {
mAppHibernationService = new AppHibernationService(mContext, mIPackageManager, mAppHibernationService = new AppHibernationService(mContext, mIPackageManager,
mIActivityManager, mUserManager); mIActivityManager, mUserManager);
verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any()); verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
mBroadcastReceiver = mReceiverCaptor.getValue(); mBroadcastReceiver = mReceiverCaptor.getValue();
doReturn(mUserInfos).when(mUserManager).getUsers(); doReturn(mUserInfos).when(mUserManager).getUsers();
@@ -95,12 +94,13 @@ public final class AppHibernationServiceTest {
doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(), doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), any(), any()); anyInt(), anyBoolean(), anyBoolean(), any(), any());
addUser(USER_ID_1); UserInfo userInfo = addUser(USER_ID_1);
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
} }
@Test @Test
public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException { public void testSetHibernatingForUser_packageIsHibernating() {
// WHEN we hibernate a package for a user // WHEN we hibernate a package for a user
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
@@ -109,8 +109,7 @@ public final class AppHibernationServiceTest {
} }
@Test @Test
public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating() public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating() {
throws RemoteException {
// WHEN a new package is added and it is hibernated // WHEN a new package is added and it is hibernated
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED, Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */)); Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
@@ -124,17 +123,12 @@ public final class AppHibernationServiceTest {
} }
@Test @Test
public void testSetHibernatingForUser_newUserAdded_packageIsHibernating() public void testSetHibernatingForUser_newUserUnlocked_packageIsHibernating()
throws RemoteException { throws RemoteException {
// WHEN a new user is added and a package from the user is hibernated // WHEN a new user is added and a package from the user is hibernated
List<PackageInfo> userPackages = new ArrayList<>(); UserInfo user2 = addUser(USER_ID_2);
userPackages.add(makePackageInfo(PACKAGE_NAME_1)); mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager) doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
.getInstalledPackages(anyInt(), eq(USER_ID_2));
Intent intent = new Intent(Intent.ACTION_USER_ADDED);
intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
mBroadcastReceiver.onReceive(mContext, intent);
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true); mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated // THEN the new user's package is hibernated
@@ -142,8 +136,7 @@ public final class AppHibernationServiceTest {
} }
@Test @Test
public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating() public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating() {
throws RemoteException {
// GIVEN a package is currently hibernated // GIVEN a package is currently hibernated
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true); mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
@@ -159,7 +152,7 @@ public final class AppHibernationServiceTest {
} }
@Test @Test
public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException { public void testSetHibernatingGlobally_packageIsHibernatingGlobally() {
// WHEN we hibernate a package // WHEN we hibernate a package
mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true); mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
@@ -168,25 +161,25 @@ public final class AppHibernationServiceTest {
} }
/** /**
* Add a mock user with one package. Must be called before * Add a mock user with one package.
* {@link AppHibernationService#onBootPhase(int)} to work properly.
*/ */
private void addUser(int userId) throws RemoteException { private UserInfo addUser(int userId) throws RemoteException {
addUser(userId, new String[]{PACKAGE_NAME_1}); return addUser(userId, new String[]{PACKAGE_NAME_1});
} }
/** /**
* Add a mock user with the packages specified. Must be called before * Add a mock user with the packages specified.
* {@link AppHibernationService#onBootPhase(int)} to work properly
*/ */
private void addUser(int userId, String[] packageNames) throws RemoteException { private UserInfo addUser(int userId, String[] packageNames) throws RemoteException {
mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */)); UserInfo userInfo = new UserInfo(userId, "user_" + userId, 0 /* flags */);
mUserInfos.add(userInfo);
List<PackageInfo> userPackages = new ArrayList<>(); List<PackageInfo> userPackages = new ArrayList<>();
for (String pkgName : packageNames) { for (String pkgName : packageNames) {
userPackages.add(makePackageInfo(pkgName)); userPackages.add(makePackageInfo(pkgName));
} }
doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager) doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
.getInstalledPackages(anyInt(), eq(userId)); .getInstalledPackages(anyInt(), eq(userId));
return userInfo;
} }
private static PackageInfo makePackageInfo(String packageName) { private static PackageInfo makePackageInfo(String packageName) {