summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kevin Han <kevhan@google.com> 2021-01-30 00:37:19 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2021-01-30 00:37:19 +0000
commit6857f6ed91b99b2f6c38cec9afb4f7f1d962acd3 (patch)
treeb212313f3a7afcdaf97471d85e7de53abdf6cb7d
parent1528efe4b11906a2cd1dd3ba07edeade6899a719 (diff)
parentf4261d72154a3c5c6db49ba87e26707cef1e35c5 (diff)
Merge "Introduce global package hibernation"
-rw-r--r--core/api/system-current.txt6
-rw-r--r--core/java/android/apphibernation/AppHibernationManager.java42
-rw-r--r--core/java/android/apphibernation/IAppHibernationService.aidl6
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java153
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java61
-rw-r--r--services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java71
6 files changed, 266 insertions, 73 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a7c5b7480334..602621185872 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1415,8 +1415,10 @@ package android.app.usage {
package android.apphibernation {
public final class AppHibernationManager {
- method public boolean isHibernating(@NonNull String);
- method public void setHibernating(@NonNull String, boolean);
+ method public boolean isHibernatingForUser(@NonNull String);
+ method public boolean isHibernatingGlobally(@NonNull String);
+ method public void setHibernatingForUser(@NonNull String, boolean);
+ method public void setHibernatingGlobally(@NonNull String, boolean);
}
}
diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java
index 8f1934c7b77a..7281d50a33a5 100644
--- a/core/java/android/apphibernation/AppHibernationManager.java
+++ b/core/java/android/apphibernation/AppHibernationManager.java
@@ -49,31 +49,61 @@ public final class AppHibernationManager {
}
/**
- * Returns true if the package is hibernating, false otherwise.
+ * Returns true if the package is hibernating for this context's user, false otherwise.
*
* @hide
*/
@SystemApi
- public boolean isHibernating(@NonNull String packageName) {
+ public boolean isHibernatingForUser(@NonNull String packageName) {
try {
- return mIAppHibernationService.isHibernating(packageName, mContext.getUserId());
+ return mIAppHibernationService.isHibernatingForUser(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Set whether the package is hibernating.
+ * Set whether the package is hibernating for this context's user.
*
* @hide
*/
@SystemApi
- public void setHibernating(@NonNull String packageName, boolean isHibernating) {
+ public void setHibernatingForUser(@NonNull String packageName, boolean isHibernating) {
try {
- mIAppHibernationService.setHibernating(packageName, mContext.getUserId(),
+ mIAppHibernationService.setHibernatingForUser(packageName, mContext.getUserId(),
isHibernating);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns true if app is hibernating globally / at the package level.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isHibernatingGlobally(@NonNull String packageName) {
+ try {
+ return mIAppHibernationService.isHibernatingGlobally(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether a package should be globally hibernating. This hibernates the package at a
+ * package level. User-level hibernation (e.g.. {@link #isHibernatingForUser} is independent
+ * from global hibernation.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setHibernatingGlobally(@NonNull String packageName, boolean isHibernating) {
+ try {
+ mIAppHibernationService.setHibernatingGlobally(packageName, isHibernating);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl
index db57ecb73051..6a068ee2b147 100644
--- a/core/java/android/apphibernation/IAppHibernationService.aidl
+++ b/core/java/android/apphibernation/IAppHibernationService.aidl
@@ -21,6 +21,8 @@ package android.apphibernation;
* @hide
*/
interface IAppHibernationService {
- boolean isHibernating(String packageName, int userId);
- void setHibernating(String packageName, int userId, boolean isHibernating);
+ boolean isHibernatingForUser(String packageName, int userId);
+ void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
+ boolean isHibernatingGlobally(String packageName);
+ void setHibernatingGlobally(String packageName, boolean isHibernating);
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 508bb01e50a8..fded85cd9126 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -20,6 +20,7 @@ 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;
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
@@ -46,6 +47,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -55,6 +57,7 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* System service that manages app hibernation state, a state apps can enter that means they are
@@ -74,6 +77,8 @@ public final class AppHibernationService extends SystemService {
private final UserManager mUserManager;
@GuardedBy("mLock")
private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final Set<String> mGloballyHibernatedPackages = new ArraySet<>();
/**
* Initializes the system service.
@@ -138,7 +143,7 @@ public final class AppHibernationService extends SystemService {
* @param userId the user to check
* @return true if package is hibernating for the user
*/
- public boolean isHibernating(String packageName, int userId) {
+ boolean isHibernatingForUser(String packageName, int userId) {
userId = handleIncomingUser(userId, "isHibernating");
synchronized (mLock) {
final Map<String, UserPackageState> packageStates = mUserStates.get(userId);
@@ -151,7 +156,19 @@ public final class AppHibernationService extends SystemService {
String.format("Package %s is not installed for user %s",
packageName, userId));
}
- return pkgState != null ? pkgState.hibernated : null;
+ return pkgState.hibernated;
+ }
+ }
+
+ /**
+ * Whether a package is hibernated globally. This only occurs when a package is hibernating for
+ * all users and allows us to make optimizations at the package or APK level.
+ *
+ * @param packageName package to check
+ */
+ boolean isHibernatingGlobally(String packageName) {
+ synchronized (mLock) {
+ return mGloballyHibernatedPackages.contains(packageName);
}
}
@@ -162,7 +179,7 @@ public final class AppHibernationService extends SystemService {
* @param userId user
* @param isHibernating new hibernation state
*/
- public void setHibernating(String packageName, int userId, boolean isHibernating) {
+ void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
userId = handleIncomingUser(userId, "setHibernating");
synchronized (mLock) {
if (!mUserStates.contains(userId)) {
@@ -180,32 +197,99 @@ public final class AppHibernationService extends SystemService {
return;
}
+ if (isHibernating) {
+ hibernatePackageForUserL(packageName, userId, pkgState);
+ } else {
+ unhibernatePackageForUserL(packageName, userId, pkgState);
+ }
+ }
+ }
- final long caller = Binder.clearCallingIdentity();
- try {
+ /**
+ * Set whether the package should be hibernated globally at a package level, allowing the
+ * the system to make optimizations at the package or APK level.
+ *
+ * @param packageName package to hibernate globally
+ * @param isHibernating new hibernation state
+ */
+ void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ if (isHibernating != mGloballyHibernatedPackages.contains(packageName)) {
+ synchronized (mLock) {
if (isHibernating) {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
- mIActivityManager.forceStopPackage(packageName, userId);
- mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
- null /* observer */);
+ hibernatePackageGloballyL(packageName);
} else {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
- mIPackageManager.setPackageStoppedState(packageName, false, userId);
+ unhibernatePackageGloballyL(packageName);
}
- pkgState.hibernated = isHibernating;
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Failed to hibernate due to manager not being available", e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- Binder.restoreCallingIdentity(caller);
}
+ }
+ }
- // TODO: Support package level hibernation when package is hibernating for all users
+ /**
+ * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
+ * The caller should hold {@link #mLock}
+ *
+ * @param pkgState package hibernation state
+ */
+ private void hibernatePackageForUserL(@NonNull String packageName, int userId,
+ @NonNull UserPackageState pkgState) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mIActivityManager.forceStopPackage(packageName, userId);
+ mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
+ null /* observer */);
+ pkgState.hibernated = true;
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to hibernate due to manager not being available", e);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
/**
+ * Remove a package from hibernation for a given user. The caller should hold {@link #mLock}.
+ *
+ * @param pkgState package hibernation state
+ */
+ private void unhibernatePackageForUserL(@NonNull String packageName, int userId,
+ UserPackageState pkgState) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage");
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mIPackageManager.setPackageStoppedState(packageName, false, userId);
+ pkgState.hibernated = false;
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to unhibernate due to manager not being available", e);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+
+ /**
+ * Put a package into global hibernation, optimizing its storage at a package / APK level.
+ * The caller should hold {@link #mLock}.
+ */
+ private void hibernatePackageGloballyL(@NonNull String packageName) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
+ // TODO(175830194): Delete vdex/odex when DexManager API is built out
+ mGloballyHibernatedPackages.add(packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ /**
+ * Unhibernate a package from global hibernation. The caller should hold {@link #mLock}.
+ */
+ private void unhibernatePackageGloballyL(@NonNull String packageName) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
+ mGloballyHibernatedPackages.remove(packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ /**
* Populates {@link #mUserStates} with the users installed packages. The caller should hold
* {@link #mLock}.
*
@@ -220,8 +304,8 @@ public final class AppHibernationService extends SystemService {
throw new IllegalStateException("Package manager not available.", e);
}
- for (PackageInfo pkg : packageList) {
- packages.put(pkg.packageName, new UserPackageState());
+ for (int i = 0, size = packageList.size(); i < size; i++) {
+ packages.put(packageList.get(i).packageName, new UserPackageState());
}
mUserStates.put(userId, packages);
}
@@ -250,6 +334,12 @@ public final class AppHibernationService extends SystemService {
}
}
+ private void onPackageRemovedForAllUsers(@NonNull String packageName) {
+ synchronized (mLock) {
+ mGloballyHibernatedPackages.remove(packageName);
+ }
+ }
+
/**
* Private helper method to get the real user id and enforce permission checks.
*
@@ -277,13 +367,23 @@ public final class AppHibernationService extends SystemService {
}
@Override
- public boolean isHibernating(String packageName, int userId) {
- return mService.isHibernating(packageName, userId);
+ public boolean isHibernatingForUser(String packageName, int userId) {
+ return mService.isHibernatingForUser(packageName, userId);
+ }
+
+ @Override
+ public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+ mService.setHibernatingForUser(packageName, userId, isHibernating);
+ }
+
+ @Override
+ public void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ mService.setHibernatingGlobally(packageName, isHibernating);
}
@Override
- public void setHibernating(String packageName, int userId, boolean isHibernating) {
- mService.setHibernating(packageName, userId, isHibernating);
+ public boolean isHibernatingGlobally(String packageName) {
+ return mService.isHibernatingGlobally(packageName);
}
@Override
@@ -322,6 +422,9 @@ public final class AppHibernationService extends SystemService {
onPackageAdded(packageName, userId);
} else if (ACTION_PACKAGE_REMOVED.equals(action)) {
onPackageRemoved(packageName, userId);
+ if (intent.getBooleanExtra(EXTRA_REMOVED_FOR_ALL_USERS, false)) {
+ onPackageRemovedForAllUsers(packageName);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
index 869885e28958..7d6eea25541a 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java
@@ -18,7 +18,6 @@ package com.android.server.apphibernation;
import android.os.ShellCommand;
import android.os.UserHandle;
-import android.text.TextUtils;
import java.io.PrintWriter;
@@ -27,6 +26,7 @@ import java.io.PrintWriter;
*/
final class AppHibernationShellCommand extends ShellCommand {
private static final String USER_OPT = "--user";
+ private static final String GLOBAL_OPT = "--global";
private static final int SUCCESS = 0;
private static final int ERROR = -1;
private final AppHibernationService mService;
@@ -51,7 +51,21 @@ final class AppHibernationShellCommand extends ShellCommand {
}
private int runSetState() {
- int userId = parseUserOption();
+ String opt;
+ boolean setsGlobal = false;
+ int userId = UserHandle.USER_CURRENT;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case USER_OPT:
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case GLOBAL_OPT:
+ setsGlobal = true;
+ break;
+ default:
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ }
+ }
String pkg = getNextArgRequired();
if (pkg == null) {
@@ -66,32 +80,43 @@ final class AppHibernationShellCommand extends ShellCommand {
}
boolean newState = Boolean.parseBoolean(newStateRaw);
- mService.setHibernating(pkg, userId, newState);
+ if (setsGlobal) {
+ mService.setHibernatingGlobally(pkg, newState);
+ } else {
+ mService.setHibernatingForUser(pkg, userId, newState);
+ }
return SUCCESS;
}
private int runGetState() {
- int userId = parseUserOption();
+ String opt;
+ boolean requestsGlobal = false;
+ int userId = UserHandle.USER_CURRENT;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case USER_OPT:
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case GLOBAL_OPT:
+ requestsGlobal = true;
+ break;
+ default:
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ }
+ }
String pkg = getNextArgRequired();
if (pkg == null) {
getErrPrintWriter().println("Error: No package specified");
return ERROR;
}
- boolean isHibernating = mService.isHibernating(pkg, userId);
+ boolean isHibernating = requestsGlobal
+ ? mService.isHibernatingGlobally(pkg) : mService.isHibernatingForUser(pkg, userId);
final PrintWriter pw = getOutPrintWriter();
pw.println(isHibernating);
return SUCCESS;
}
- private int parseUserOption() {
- String option = getNextOption();
- if (TextUtils.equals(option, USER_OPT)) {
- return UserHandle.parseUserArg(getNextArgRequired());
- }
- return UserHandle.USER_CURRENT;
- }
-
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -99,11 +124,13 @@ final class AppHibernationShellCommand extends ShellCommand {
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
- pw.println(" set-state [--user USER_ID] PACKAGE true|false");
- pw.println(" Sets the hibernation state of the package to value specified");
+ pw.println(" set-state [--user USER_ID] [--global] PACKAGE true|false");
+ pw.println(" Sets the hibernation state of the package to value specified. Optionally");
+ pw.println(" may specify a user id or set global hibernation state.");
pw.println("");
- pw.println(" get-state [--user USER_ID] PACKAGE");
- pw.println(" Gets the hibernation state of the package");
+ pw.println(" get-state [--user USER_ID] [--global] PACKAGE");
+ pw.println(" Gets the hibernation state of the package. Optionally may specify a user");
+ pw.println(" id or request global hibernation state.");
pw.println("");
}
}
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index d0370b6c25e9..45bca6829553 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -64,6 +64,8 @@ public final class AppHibernationServiceTest {
private static final int USER_ID_1 = 1;
private static final int USER_ID_2 = 2;
+ private final List<UserInfo> mUserInfos = new ArrayList<>();
+
private AppHibernationService mAppHibernationService;
private BroadcastReceiver mBroadcastReceiver;
@Mock
@@ -88,47 +90,42 @@ public final class AppHibernationServiceTest {
verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any());
mBroadcastReceiver = mReceiverCaptor.getValue();
- List<UserInfo> userList = new ArrayList<>();
- userList.add(new UserInfo(USER_ID_1, "user 1", 0 /* flags */));
- doReturn(userList).when(mUserManager).getUsers();
-
- List<PackageInfo> userPackages = new ArrayList<>();
- userPackages.add(makePackageInfo(PACKAGE_NAME_1));
-
- doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
- .getInstalledPackages(anyInt(), eq(USER_ID_1));
+ doReturn(mUserInfos).when(mUserManager).getUsers();
doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), any(), any());
+ addUser(USER_ID_1);
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
@Test
- public void testSetHibernating_packageIsHibernating() {
+ public void testSetHibernatingForUser_packageIsHibernating() throws RemoteException {
// WHEN we hibernate a package for a user
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
// THEN the package is marked hibernating for the user
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
}
@Test
- public void testSetHibernating_newPackageAdded_packageIsHibernating() {
+ public void testSetHibernatingForUser_newPackageAdded_packageIsHibernating()
+ throws RemoteException {
// 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 */));
intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1);
mBroadcastReceiver.onReceive(mContext, intent);
- mAppHibernationService.setHibernating(PACKAGE_NAME_2, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_1, true);
// THEN the new package is hibernated
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_2, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_2, USER_ID_1));
}
@Test
- public void testSetHibernating_newUserAdded_packageIsHibernating() throws RemoteException {
+ public void testSetHibernatingForUser_newUserAdded_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));
@@ -138,16 +135,17 @@ public final class AppHibernationServiceTest {
intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2);
mBroadcastReceiver.onReceive(mContext, intent);
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_2, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_2));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_2));
}
@Test
- public void testIsHibernating_packageReplaced_stillReturnsHibernating() {
+ public void testIsHibernatingForUser_packageReplaced_stillReturnsHibernating()
+ throws RemoteException {
// GIVEN a package is currently hibernated
- mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true);
+ mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
// WHEN the package is removed but marked as replacing
Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
@@ -157,7 +155,38 @@ public final class AppHibernationServiceTest {
mBroadcastReceiver.onReceive(mContext, intent);
// THEN the package is still hibernating
- assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1));
+ assertTrue(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
+ }
+
+ @Test
+ public void testSetHibernatingGlobally_packageIsHibernatingGlobally() throws RemoteException {
+ // WHEN we hibernate a package
+ mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
+
+ // THEN the package is marked hibernating for the user
+ assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
+ }
+
+ /**
+ * Add a mock user with one package. Must be called before
+ * {@link AppHibernationService#onBootPhase(int)} to work properly.
+ */
+ private void addUser(int userId) throws RemoteException {
+ 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
+ */
+ private void addUser(int userId, String[] packageNames) throws RemoteException {
+ mUserInfos.add(new UserInfo(userId, "user_" + userId, 0 /* flags */));
+ List<PackageInfo> userPackages = new ArrayList<>();
+ for (String pkgName : packageNames) {
+ userPackages.add(makePackageInfo(pkgName));
+ }
+ doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager)
+ .getInstalledPackages(anyInt(), eq(userId));
}
private static PackageInfo makePackageInfo(String packageName) {