Lock before checking if user state is null
If a user is removed between the user state null check and the lock, it
is possible to run into a NPE. We fix this by putting the entire user
state check inside the lock.
Bug: 211906910
Test: builds
Change-Id: I1f5f4d05f7d21db1af08e4d8cbaa48f41470dee0
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 4d025c9..9d4d1c1 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -223,10 +223,10 @@
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
userId = handleIncomingUser(userId, methodName);
- if (!checkUserStatesExist(userId, methodName)) {
- return false;
- }
synchronized (mLock) {
+ if (!checkUserStatesExist(userId, methodName)) {
+ return false;
+ }
final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
final UserLevelState pkgState = packageStates.get(packageName);
if (pkgState == null) {
@@ -278,10 +278,10 @@
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
final int realUserId = handleIncomingUser(userId, methodName);
- if (!checkUserStatesExist(realUserId, methodName)) {
- return;
- }
synchronized (mLock) {
+ if (!checkUserStatesExist(realUserId, methodName)) {
+ return;
+ }
final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId);
final UserLevelState pkgState = packageStates.get(packageName);
if (pkgState == null) {
@@ -365,10 +365,10 @@
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
userId = handleIncomingUser(userId, methodName);
- if (!checkUserStatesExist(userId, methodName)) {
- return hibernatingPackages;
- }
synchronized (mLock) {
+ if (!checkUserStatesExist(userId, methodName)) {
+ return hibernatingPackages;
+ }
Map<String, UserLevelState> userStates = mUserStates.get(userId);
for (UserLevelState state : userStates.values()) {
if (state.hibernated) {
@@ -658,6 +658,14 @@
}
}
+ /**
+ * Check that user states exist.
+ *
+ * @param userId user to check
+ * @param methodName method name that is calling. Used for logging purposes.
+ * @return true if user states exist
+ */
+ @GuardedBy("mLock")
private boolean checkUserStatesExist(int userId, String methodName) {
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.e(TAG, String.format(