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:
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user