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

This commit is contained in:
Kevin Han
2021-04-28 02:41:54 +00:00
committed by Android (Google) Code Review
2 changed files with 129 additions and 1 deletions

View File

@@ -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);

View File

@@ -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.