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

Commit f0df72a9 authored by Kevin Han's avatar Kevin Han
Browse files

Add API to get hibernating packages

Add API to AppHibernationService to get hibernating packages so
Settings can access this information.

Bug: 175829330
Test: atest AppHibernationServiceTest
Change-Id: Icd186807c19ece55a21fc4d240d2f0132951af82
parent 152e389b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1422,6 +1422,7 @@ package android.app.usage {
package android.apphibernation {
  public final class AppHibernationManager {
    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public java.util.List<java.lang.String> getHibernatingPackagesForUser();
    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingForUser(@NonNull String);
    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public boolean isHibernatingGlobally(@NonNull String);
    method @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void setHibernatingForUser(@NonNull String, boolean);
+18 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;

import java.util.List;

/**
 * This class provides an API surface for system apps to manipulate the app hibernation
 * state of a package for the user provided in the context.
@@ -111,4 +113,20 @@ public final class AppHibernationManager {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Get the hibernating packages for the user. This is equivalent to the list of packages for
     * the user that return true for {@link #isHibernatingForUser}.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(value = android.Manifest.permission.MANAGE_APP_HIBERNATION)
    public @NonNull List<String> getHibernatingPackagesForUser() {
        try {
            return mIAppHibernationService.getHibernatingPackagesForUser(mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -25,4 +25,5 @@ interface IAppHibernationService {
    void setHibernatingForUser(String packageName, int userId, boolean isHibernating);
    boolean isHibernatingGlobally(String packageName);
    void setHibernatingGlobally(String packageName, boolean isHibernating);
    List<String> getHibernatingPackagesForUser(int userId);
}
 No newline at end of file
+34 −0
Original line number Diff line number Diff line
@@ -292,6 +292,35 @@ public final class AppHibernationService extends SystemService {
        }
    }

    /**
     * Get the hibernating packages for the given user. This is equivalent to the list of
     * packages for the user that return true for {@link #isHibernatingForUser}.
     */
    @NonNull List<String> getHibernatingPackagesForUser(int userId) {
        ArrayList<String> hibernatingPackages = new ArrayList<>();
        if (!checkHibernationEnabled("getHibernatingPackagesForUser")) {
            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);
            return hibernatingPackages;
        }
        synchronized (mLock) {
            Map<String, UserLevelState> userStates = mUserStates.get(userId);
            for (UserLevelState state : userStates.values()) {
                if (state.hibernated) {
                    hibernatingPackages.add(state.packageName);
                }
            }
            return hibernatingPackages;
        }
    }

    /**
     * Put an app into hibernation for a given user, allowing user-level optimizations to occur.
     *
@@ -618,6 +647,11 @@ public final class AppHibernationService extends SystemService {
            return mService.isHibernatingGlobally(packageName);
        }

        @Override
        public List<String> getHibernatingPackagesForUser(int userId) {
            return mService.getHibernatingPackagesForUser(userId);
        }

        @Override
        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                @Nullable FileDescriptor err, @NonNull String[] args,
+24 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.apphibernation;

import static android.content.pm.PackageManager.MATCH_ANY_USER;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalAnswers.returnsArgAt;
import static org.mockito.ArgumentMatchers.any;
@@ -67,6 +68,7 @@ public final class AppHibernationServiceTest {
    private static final String PACKAGE_SCHEME = "package";
    private static final String PACKAGE_NAME_1 = "package1";
    private static final String PACKAGE_NAME_2 = "package2";
    private static final String PACKAGE_NAME_3 = "package3";
    private static final int USER_ID_1 = 1;
    private static final int USER_ID_2 = 2;

@@ -107,6 +109,8 @@ public final class AppHibernationServiceTest {

        List<PackageInfo> packages = new ArrayList<>();
        packages.add(makePackageInfo(PACKAGE_NAME_1));
        packages.add(makePackageInfo(PACKAGE_NAME_2));
        packages.add(makePackageInfo(PACKAGE_NAME_3));
        doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
                intThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
        mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
@@ -179,6 +183,26 @@ public final class AppHibernationServiceTest {
        assertTrue(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
    }

    @Test
    public void testGetHibernatingPackagesForUser_returnsCorrectPackages() throws RemoteException {
        // 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);

        // WHEN packages are hibernated for the user
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);

        // THEN the hibernating packages returned matches
        List<String> hibernatingPackages =
                mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
        assertEquals(2, hibernatingPackages.size());
        assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
        assertTrue(hibernatingPackages.contains(PACKAGE_NAME_2));
    }

    /**
     * Add a mock user with one package.
     */