Loading services/core/java/com/android/server/apphibernation/AppHibernationService.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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. * Loading Loading @@ -817,6 +834,8 @@ public final class AppHibernationService extends SystemService { Executor getBackgroundExecutor(); UsageStatsManagerInternal getUsageStatsManagerInternal(); HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore(); HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId); Loading Loading @@ -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); Loading services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -81,6 +87,8 @@ public final class AppHibernationServiceTest { private AppHibernationService mAppHibernationService; private BroadcastReceiver mBroadcastReceiver; private UsageEventListener mUsageEventListener; @Mock private Context mContext; @Mock Loading @@ -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 { Loading @@ -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(); Loading Loading @@ -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. */ Loading Loading @@ -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. Loading Loading
services/core/java/com/android/server/apphibernation/AppHibernationService.java +25 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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. * Loading Loading @@ -817,6 +834,8 @@ public final class AppHibernationService extends SystemService { Executor getBackgroundExecutor(); UsageStatsManagerInternal getUsageStatsManagerInternal(); HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore(); HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId); Loading Loading @@ -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); Loading
services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -81,6 +87,8 @@ public final class AppHibernationServiceTest { private AppHibernationService mAppHibernationService; private BroadcastReceiver mBroadcastReceiver; private UsageEventListener mUsageEventListener; @Mock private Context mContext; @Mock Loading @@ -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 { Loading @@ -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(); Loading Loading @@ -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. */ Loading Loading @@ -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. Loading