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

Commit f3040a45 authored by Kevin Han's avatar Kevin Han Committed by Android (Google) Code Review
Browse files

Merge "Exit hibernation when usage is detected" into sc-dev

parents f3b52188 16ab148b
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
import android.apphibernation.IAppHibernationService;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -148,8 +151,8 @@ public final class AppHibernationService extends SystemService {
        intentFilter.addAction(ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);

        LocalServices.addService(AppHibernationManagerInternal.class, mLocalService);
        mInjector.getUsageStatsManagerInternal().registerListener(mUsageEventListener);
    }

    @Override
@@ -785,6 +788,20 @@ public final class AppHibernationService extends SystemService {
        }
    };

    private final UsageEventListener mUsageEventListener = (userId, event) -> {
        if (!isAppHibernationEnabled()) {
            return;
        }
        final int eventType = event.mEventType;
        if (eventType == UsageEvents.Event.USER_INTERACTION
                || eventType == UsageEvents.Event.ACTIVITY_RESUMED
                || eventType == UsageEvents.Event.APP_COMPONENT_USED) {
            final String pkgName = event.mPackage;
            setHibernatingForUser(pkgName, userId, false);
            setHibernatingGlobally(pkgName, false);
        }
    };

    /**
     * Whether app hibernation is enabled on this device.
     *
@@ -817,6 +834,8 @@ public final class AppHibernationService extends SystemService {

        Executor getBackgroundExecutor();

        UsageStatsManagerInternal getUsageStatsManagerInternal();

        HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();

        HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
@@ -866,6 +885,11 @@ public final class AppHibernationService extends SystemService {
            return mScheduledExecutorService;
        }

        @Override
        public UsageStatsManagerInternal getUsageStatsManagerInternal() {
            return LocalServices.getService(UsageStatsManagerInternal.class);
        }

        @Override
        public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
            File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME);
+104 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.apphibernation;

import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
import static android.content.pm.PackageManager.MATCH_ANY_USER;

import static org.junit.Assert.assertEquals;
@@ -34,6 +37,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.IActivityManager;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -81,6 +87,8 @@ public final class AppHibernationServiceTest {

    private AppHibernationService mAppHibernationService;
    private BroadcastReceiver mBroadcastReceiver;
    private UsageEventListener mUsageEventListener;

    @Mock
    private Context mContext;
    @Mock
@@ -93,8 +101,14 @@ public final class AppHibernationServiceTest {
    private UserManager mUserManager;
    @Mock
    private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore;
    @Mock
    private UsageStatsManagerInternal mUsageStatsManagerInternal;
    @Mock
    private HibernationStateDiskStore<UserLevelState> mHibernationStateDiskStore;
    @Captor
    private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
    @Captor
    private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;

    @Before
    public void setUp() throws RemoteException {
@@ -108,6 +122,8 @@ public final class AppHibernationServiceTest {

        verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
        mBroadcastReceiver = mReceiverCaptor.getValue();
        verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture());
        mUsageEventListener = mUsageEventListenerCaptor.getValue();

        doReturn(mUserInfos).when(mUserManager).getUsers();

@@ -284,6 +300,89 @@ public final class AppHibernationServiceTest {
        assertEquals(capturedIntents.get(1).getAction(), Intent.ACTION_BOOT_COMPLETED);
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedForUserWhenUserInteracted() {
        // GIVEN a package that is currently hibernated for a user
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);

        // WHEN the package is interacted with by user
        generateUsageEvent(USER_INTERACTION);

        // THEN the package is not hibernating anymore
        assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedForUserWhenActivityResumed() {
        // GIVEN a package that is currently hibernated for a user
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);

        // WHEN the package has activity resumed
        generateUsageEvent(ACTIVITY_RESUMED);

        // THEN the package is not hibernating anymore
        assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedForUserWhenComponentUsed() {
        // GIVEN a package that is currently hibernated for a user
        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);

        // WHEN a package component is used
        generateUsageEvent(APP_COMPONENT_USED);

        // THEN the package is not hibernating anymore
        assertFalse(mAppHibernationService.isHibernatingForUser(PACKAGE_NAME_1, USER_ID_1));
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedGloballyWhenUserInteracted() {
        // GIVEN a package that is currently hibernated globally
        mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);

        // WHEN the user interacts with the package
        generateUsageEvent(USER_INTERACTION);

        // THEN the package is not hibernating globally anymore
        assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedGloballyWhenActivityResumed() {
        // GIVEN a package that is currently hibernated globally
        mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);

        // WHEN activity in package resumed
        generateUsageEvent(ACTIVITY_RESUMED);

        // THEN the package is not hibernating globally anymore
        assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
    }

    @Test
    public void testHibernatingPackageIsUnhibernatedGloballyWhenComponentUsed() {
        // GIVEN a package that is currently hibernated globally
        mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);

        // WHEN a package component is used
        generateUsageEvent(APP_COMPONENT_USED);

        // THEN the package is not hibernating globally anymore
        assertFalse(mAppHibernationService.isHibernatingGlobally(PACKAGE_NAME_1));
    }

    /**
     * Mock a usage event occurring.
     *
     * @param usageEventId id of a usage event
     */
    private void generateUsageEvent(int usageEventId) {
        Event event = new Event(usageEventId, 0 /* timestamp */);
        event.mPackage = PACKAGE_NAME_1;
        mUsageEventListener.onUsageEvent(USER_ID_1, event);
    }

    /**
     * Add a mock user with one package.
     */
@@ -359,6 +458,11 @@ public final class AppHibernationServiceTest {
            return mUserManager;
        }

        @Override
        public UsageStatsManagerInternal getUsageStatsManagerInternal() {
            return mUsageStatsManagerInternal;
        }

        @Override
        public Executor getBackgroundExecutor() {
            // Just execute immediately in tests.