Merge "Add/remove user state based off user unlocking"
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_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)) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user