Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4cc9e777 authored by Rajeev Kumar's avatar Rajeev Kumar Committed by Automerger Merge Worker
Browse files

Merge "Move disk reads to background" am: 6d7c9071 am: f60e5d33 am: 44b72882 am: 24c97c9f

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

Change-Id: I6df667b316fe41f5439f4060857a4bc0abd21aa7
parents 7c82c55b 24c97c9f
Loading
Loading
Loading
Loading
+52 −24
Original line number Diff line number Diff line
@@ -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) {
            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,11 +470,16 @@ public final class AppHibernationService extends SystemService {
        HibernationStateDiskStore<UserLevelState> diskStore =
                mInjector.getUserLevelDiskStore(userId);
        mUserDiskStores.put(userId, diskStore);
        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
    public void onUserStopping(@NonNull TargetUser user) {
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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()) {
+10 −3
Original line number Diff line number Diff line
@@ -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);