Merge "Move disk reads to background" am: 6d7c90717a am: f60e5d331e am: 44b72882b0

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1626341

Change-Id: Id00efc69e73e0376f3508b89cad86f60c77efab0
This commit is contained in:
Rajeev Kumar
2021-03-23 14:01:47 +00:00
committed by Automerger Merge Worker
3 changed files with 63 additions and 27 deletions

View File

@@ -69,6 +69,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -101,6 +102,7 @@ public final class AppHibernationService extends SystemService {
private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>();
private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore;
private final Injector mInjector;
private final Executor mBackgroundExecutor;
@VisibleForTesting
boolean mIsServiceEnabled;
@@ -126,6 +128,7 @@ public final class AppHibernationService extends SystemService {
mIActivityManager = injector.getActivityManager();
mUserManager = injector.getUserManager();
mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
mBackgroundExecutor = injector.getBackgroundExecutor();
mInjector = injector;
final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
@@ -147,11 +150,13 @@ public final class AppHibernationService extends SystemService {
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
List<GlobalLevelState> states =
mGlobalLevelHibernationDiskStore.readHibernationStates();
synchronized (mLock) {
initializeGlobalHibernationStates(states);
}
mBackgroundExecutor.execute(() -> {
List<GlobalLevelState> states =
mGlobalLevelHibernationDiskStore.readHibernationStates();
synchronized (mLock) {
initializeGlobalHibernationStates(states);
}
});
}
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mIsServiceEnabled = isAppHibernationEnabled();
@@ -170,16 +175,15 @@ public final class AppHibernationService extends SystemService {
* @return true if package is hibernating for the user
*/
boolean isHibernatingForUser(String packageName, int userId) {
if (!checkHibernationEnabled("isHibernatingForUser")) {
String methodName = "isHibernatingForUser";
if (!checkHibernationEnabled(methodName)) {
return false;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
userId = handleIncomingUser(userId, "isHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
+ userId);
userId = handleIncomingUser(userId, methodName);
if (!checkUserStatesExist(userId, methodName)) {
return false;
}
synchronized (mLock) {
@@ -225,16 +229,15 @@ public final class AppHibernationService extends SystemService {
* @param isHibernating new hibernation state
*/
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
if (!checkHibernationEnabled("setHibernatingForUser")) {
String methodName = "setHibernatingForUser";
if (!checkHibernationEnabled(methodName)) {
return;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
userId = handleIncomingUser(userId, "setHibernating");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
+ userId);
userId = handleIncomingUser(userId, methodName);
if (!checkUserStatesExist(userId, methodName)) {
return;
}
synchronized (mLock) {
@@ -298,16 +301,15 @@ public final class AppHibernationService extends SystemService {
*/
@NonNull List<String> getHibernatingPackagesForUser(int userId) {
ArrayList<String> hibernatingPackages = new ArrayList<>();
if (!checkHibernationEnabled("getHibernatingPackagesForUser")) {
String methodName = "getHibernatingPackagesForUser";
if (!checkHibernationEnabled(methodName)) {
return hibernatingPackages;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
userId = handleIncomingUser(userId, "getHibernatingPackagesForUser");
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.w(TAG, "Attempt to get hibernating packages for a stopped or nonexistent user "
+ userId);
userId = handleIncomingUser(userId, methodName);
if (!checkUserStatesExist(userId, methodName)) {
return hibernatingPackages;
}
synchronized (mLock) {
@@ -468,10 +470,15 @@ public final class AppHibernationService extends SystemService {
HibernationStateDiskStore<UserLevelState> diskStore =
mInjector.getUserLevelDiskStore(userId);
mUserDiskStores.put(userId, diskStore);
List<UserLevelState> storedStates = diskStore.readHibernationStates();
synchronized (mLock) {
initializeUserHibernationStates(userId, storedStates);
}
mBackgroundExecutor.execute(() -> {
List<UserLevelState> storedStates = diskStore.readHibernationStates();
synchronized (mLock) {
// Ensure user hasn't stopped in the time to execute.
if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
initializeUserHibernationStates(userId, storedStates);
}
}
});
}
@Override
@@ -541,6 +548,20 @@ public final class AppHibernationService extends SystemService {
}
}
private boolean checkUserStatesExist(int userId, String methodName) {
if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
Slog.e(TAG, String.format(
"Attempt to call %s on stopped or nonexistent user %d", methodName, userId));
return false;
}
if (!mUserStates.contains(userId)) {
Slog.w(TAG, String.format(
"Attempt to call %s before states have been read from disk", methodName));
return false;
}
return true;
}
private boolean checkHibernationEnabled(String methodName) {
if (!mIsServiceEnabled) {
Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
@@ -711,6 +732,8 @@ public final class AppHibernationService extends SystemService {
UserManager getUserManager();
Executor getBackgroundExecutor();
HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();
HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
@@ -748,6 +771,11 @@ public final class AppHibernationService extends SystemService {
return mContext.getSystemService(UserManager.class);
}
@Override
public Executor getBackgroundExecutor() {
return mScheduledExecutorService;
}
@Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME);

View File

@@ -109,6 +109,7 @@ class HibernationStateDiskStore<T> {
* @return the parsed list of hibernation states, null if file does not exist
*/
@Nullable
@WorkerThread
List<T> readHibernationStates() {
synchronized (this) {
if (!mHibernationFile.exists()) {

View File

@@ -58,6 +58,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Tests for {@link com.android.server.apphibernation.AppHibernationService}
@@ -116,8 +117,8 @@ public final class AppHibernationServiceTest {
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);
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
mAppHibernationService.mIsServiceEnabled = true;
}
@@ -150,8 +151,8 @@ public final class AppHibernationServiceTest {
throws RemoteException {
// WHEN a new user is added and a package from the user is hibernated
UserInfo user2 = addUser(USER_ID_2);
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated
@@ -188,8 +189,8 @@ public final class AppHibernationServiceTest {
// GIVEN an unlocked user with all packages installed
UserInfo userInfo =
addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
// WHEN packages are hibernated for the user
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
@@ -258,6 +259,12 @@ public final class AppHibernationServiceTest {
return mUserManager;
}
@Override
public Executor getBackgroundExecutor() {
// Just execute immediately in tests.
return r -> r.run();
}
@Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
return Mockito.mock(HibernationStateDiskStore.class);