Add/remove user state based off user unlocking
Only store user hibernation state in memory when the user is not stopped and is unlocked since we do not need the information. When a user unlocks, we get their installed packages and initialize their hibernation states in memory. When the user is stopped, we clear it. Bug: 175829330 Test: atest AppHibernationServiceTest Change-Id: Idb2dba02d53df72daedae0078405634a5db51e8d
This commit is contained in:
@@ -18,8 +18,6 @@ package com.android.server.apphibernation;
|
||||
|
||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
||||
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_REPLACING;
|
||||
import static android.content.pm.PackageManager.MATCH_ALL;
|
||||
@@ -36,7 +34,6 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
@@ -48,6 +45,7 @@ import android.os.UserManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
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 */);
|
||||
|
||||
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_REMOVED);
|
||||
intentFilter.addDataScheme("package");
|
||||
@@ -123,19 +116,6 @@ public final class AppHibernationService extends SystemService {
|
||||
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.
|
||||
*
|
||||
@@ -145,11 +125,13 @@ public final class AppHibernationService extends SystemService {
|
||||
*/
|
||||
boolean isHibernatingForUser(String packageName, int userId) {
|
||||
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) {
|
||||
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);
|
||||
if (pkgState == null) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -181,10 +163,12 @@ public final class AppHibernationService extends SystemService {
|
||||
*/
|
||||
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
|
||||
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) {
|
||||
if (!mUserStates.contains(userId)) {
|
||||
throw new IllegalArgumentException("No user associated with user id " + userId);
|
||||
}
|
||||
Map<String, UserPackageState> packageStates = mUserStates.get(userId);
|
||||
UserPackageState pkgState = packageStates.get(packageName);
|
||||
if (pkgState == null) {
|
||||
@@ -310,15 +294,19 @@ public final class AppHibernationService extends SystemService {
|
||||
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) {
|
||||
addUserPackageStatesL(userId);
|
||||
addUserPackageStatesL(user.getUserIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserRemoved(int userId) {
|
||||
@Override
|
||||
public void onUserStopping(@NonNull TargetUser user) {
|
||||
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() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@@ -405,12 +393,6 @@ public final class AppHibernationService extends SystemService {
|
||||
}
|
||||
|
||||
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)) {
|
||||
final String packageName = intent.getData().getSchemeSpecificPart();
|
||||
if (intent.getBooleanExtra(EXTRA_REPLACING, false)) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -87,7 +86,7 @@ public final class AppHibernationServiceTest {
|
||||
mAppHibernationService = new AppHibernationService(mContext, mIPackageManager,
|
||||
mIActivityManager, mUserManager);
|
||||
|
||||
verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
|
||||
verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
|
||||
mBroadcastReceiver = mReceiverCaptor.getValue();
|
||||
|
||||
doReturn(mUserInfos).when(mUserManager).getUsers();
|
||||
@@ -95,12 +94,13 @@ public final class AppHibernationServiceTest {
|
||||
doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
|
||||
anyInt(), anyBoolean(), anyBoolean(), any(), any());
|
||||
|
||||
addUser(USER_ID_1);
|
||||
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
||||
UserInfo userInfo = addUser(USER_ID_1);
|
||||
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
|
||||
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException {
|
||||
public void testSetHibernatingForUser_packageIsHibernating() {
|
||||
// WHEN we hibernate a package for a user
|
||||
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
|
||||
|
||||
@@ -109,8 +109,7 @@ public final class AppHibernationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating()
|
||||
throws RemoteException {
|
||||
public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating() {
|
||||
// WHEN a new package is added and it is hibernated
|
||||
Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED,
|
||||
Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */));
|
||||
@@ -124,17 +123,12 @@ public final class AppHibernationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHibernatingForUser_newUserAdded_packageIsHibernating()
|
||||
public void testSetHibernatingForUser_newUserUnlocked_packageIsHibernating()
|
||||
throws RemoteException {
|
||||
// WHEN a new user is added and a package from the user is hibernated
|
||||
List<PackageInfo> userPackages = new ArrayList<>();
|
||||
userPackages.add(makePackageInfo(PACKAGE_NAME_1));
|
||||
doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
|
||||
.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);
|
||||
|
||||
UserInfo user2 = addUser(USER_ID_2);
|
||||
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
|
||||
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
|
||||
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
|
||||
|
||||
// THEN the new user's package is hibernated
|
||||
@@ -142,8 +136,7 @@ public final class AppHibernationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()
|
||||
throws RemoteException {
|
||||
public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating() {
|
||||
// GIVEN a package is currently hibernated
|
||||
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
|
||||
|
||||
@@ -159,7 +152,7 @@ public final class AppHibernationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException {
|
||||
public void testSetHibernatingGlobally_packageIsHibernatingGlobally() {
|
||||
// WHEN we hibernate a package
|
||||
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
|
||||
* {@link AppHibernationService#onBootPhase(int)} to work properly.
|
||||
* Add a mock user with one package.
|
||||
*/
|
||||
private void addUser(int userId) throws RemoteException {
|
||||
addUser(userId, new String[]{PACKAGE_NAME_1});
|
||||
private UserInfo addUser(int userId) throws RemoteException {
|
||||
return addUser(userId, new String[]{PACKAGE_NAME_1});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mock user with the packages specified. Must be called before
|
||||
* {@link AppHibernationService#onBootPhase(int)} to work properly
|
||||
* Add a mock user with the packages specified.
|
||||
*/
|
||||
private void addUser(int userId, String[] packageNames) throws RemoteException {
|
||||
mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */));
|
||||
private UserInfo addUser(int userId, String[] packageNames) throws RemoteException {
|
||||
UserInfo userInfo = new UserInfo(userId, "user_" + userId, 0 /* flags */);
|
||||
mUserInfos.add(userInfo);
|
||||
List<PackageInfo> userPackages = new ArrayList<>();
|
||||
for (String pkgName : packageNames) {
|
||||
userPackages.add(makePackageInfo(pkgName));
|
||||
}
|
||||
doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
|
||||
.getInstalledPackages(anyInt(), eq(userId));
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
private static PackageInfo makePackageInfo(String packageName) {
|
||||
|
||||
Reference in New Issue
Block a user