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

Commit c4d1d01a authored by Kevin Han's avatar Kevin Han Committed by Automerger Merge Worker
Browse files

Merge changes from topic "app_hibernation_permission" am: 4dfa5f8d

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

Change-Id: I55b8dc7dfa171b5d11098320445932ef2f91bcbf
parents 0a4f736c 4dfa5f8d
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.
     */