Merge "Add cache savings to hibernation savings stats"
This commit is contained in:
@@ -35,6 +35,8 @@ import android.app.ActivityThread;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.StatsManager;
|
||||
import android.app.StatsManager.StatsPullAtomCallback;
|
||||
import android.app.usage.StorageStats;
|
||||
import android.app.usage.StorageStatsManager;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
|
||||
@@ -78,6 +80,7 @@ import com.android.server.SystemService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -111,6 +114,7 @@ public final class AppHibernationService extends SystemService {
|
||||
private final PackageManagerInternal mPackageManagerInternal;
|
||||
private final IActivityManager mIActivityManager;
|
||||
private final UserManager mUserManager;
|
||||
private final StorageStatsManager mStorageStatsManager;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>();
|
||||
@@ -147,6 +151,7 @@ public final class AppHibernationService extends SystemService {
|
||||
mPackageManagerInternal = injector.getPackageManagerInternal();
|
||||
mIActivityManager = injector.getActivityManager();
|
||||
mUserManager = injector.getUserManager();
|
||||
mStorageStatsManager = injector.getStorageStatsManager();
|
||||
mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
|
||||
mBackgroundExecutor = injector.getBackgroundExecutor();
|
||||
mOatArtifactDeletionEnabled = injector.isOatArtifactDeletionEnabled();
|
||||
@@ -297,7 +302,8 @@ public final class AppHibernationService extends SystemService {
|
||||
|
||||
pkgState.hibernated = isHibernating;
|
||||
if (isHibernating) {
|
||||
mBackgroundExecutor.execute(() -> hibernatePackageForUser(packageName, realUserId));
|
||||
mBackgroundExecutor.execute(
|
||||
() -> hibernatePackageForUser(packageName, realUserId, pkgState));
|
||||
} else {
|
||||
mBackgroundExecutor.execute(
|
||||
() -> unhibernatePackageForUser(packageName, realUserId));
|
||||
@@ -415,8 +421,9 @@ public final class AppHibernationService extends SystemService {
|
||||
+ "the package was uninstalled? ", pkgName, userId));
|
||||
continue;
|
||||
}
|
||||
HibernationStats stats = new HibernationStats(
|
||||
mGlobalHibernationStates.get(pkgName).savedByte);
|
||||
long diskBytesSaved = mGlobalHibernationStates.get(pkgName).savedByte
|
||||
+ userPackageStates.get(pkgName).savedByte;
|
||||
HibernationStats stats = new HibernationStats(diskBytesSaved);
|
||||
statsMap.put(pkgName, stats);
|
||||
}
|
||||
}
|
||||
@@ -427,16 +434,28 @@ public final class AppHibernationService extends SystemService {
|
||||
* Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do
|
||||
* not hold {@link #mLock} while calling this to avoid deadlock scenarios.
|
||||
*/
|
||||
private void hibernatePackageForUser(@NonNull String packageName, int userId) {
|
||||
private void hibernatePackageForUser(@NonNull String packageName, int userId,
|
||||
UserLevelState state) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
|
||||
final long caller = Binder.clearCallingIdentity();
|
||||
try {
|
||||
ApplicationInfo info = mIPackageManager.getApplicationInfo(
|
||||
packageName, PACKAGE_MATCH_FLAGS, userId);
|
||||
StorageStats stats = mStorageStatsManager.queryStatsForPackage(
|
||||
info.storageUuid, packageName, new UserHandle(userId));
|
||||
mIActivityManager.forceStopPackage(packageName, userId);
|
||||
mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
|
||||
null /* observer */);
|
||||
synchronized (mLock) {
|
||||
state.savedByte = stats.getCacheBytes();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to hibernate due to manager not being available", e);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(TAG, "Package name not found when querying storage stats", e);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Storage device not found", e);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(caller);
|
||||
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
|
||||
@@ -920,6 +939,8 @@ public final class AppHibernationService extends SystemService {
|
||||
|
||||
UserManager getUserManager();
|
||||
|
||||
StorageStatsManager getStorageStatsManager();
|
||||
|
||||
Executor getBackgroundExecutor();
|
||||
|
||||
UsageStatsManagerInternal getUsageStatsManagerInternal();
|
||||
@@ -968,6 +989,11 @@ public final class AppHibernationService extends SystemService {
|
||||
return mContext.getSystemService(UserManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageStatsManager getStorageStatsManager() {
|
||||
return mContext.getSystemService(StorageStatsManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getBackgroundExecutor() {
|
||||
return mScheduledExecutorService;
|
||||
|
||||
@@ -28,6 +28,8 @@ final class UserLevelState {
|
||||
|
||||
public String packageName;
|
||||
public boolean hibernated;
|
||||
// Saved bytes from user level hibernation.
|
||||
public long savedByte;
|
||||
@CurrentTimeMillisLong
|
||||
public long lastUnhibernatedMs;
|
||||
|
||||
@@ -36,6 +38,7 @@ final class UserLevelState {
|
||||
UserLevelState(UserLevelState state) {
|
||||
packageName = state.packageName;
|
||||
hibernated = state.hibernated;
|
||||
savedByte = state.savedByte;
|
||||
lastUnhibernatedMs = state.lastUnhibernatedMs;
|
||||
}
|
||||
|
||||
@@ -44,6 +47,7 @@ final class UserLevelState {
|
||||
return "UserLevelState{"
|
||||
+ "packageName='" + packageName + '\''
|
||||
+ ", hibernated=" + hibernated + '\''
|
||||
+ ", savedByte=" + savedByte + '\''
|
||||
+ ", lastUnhibernated=" + DATE_FORMAT.format(lastUnhibernatedMs)
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import static org.mockito.AdditionalAnswers.returnsArgAt;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.longThat;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
@@ -38,6 +40,8 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
import android.app.usage.StorageStats;
|
||||
import android.app.usage.StorageStatsManager;
|
||||
import android.app.usage.UsageEvents.Event;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
|
||||
@@ -48,6 +52,7 @@ import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.UserInfo;
|
||||
@@ -68,10 +73,12 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@@ -104,6 +111,8 @@ public final class AppHibernationServiceTest {
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private StorageStatsManager mStorageStatsManager;
|
||||
@Mock
|
||||
private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore;
|
||||
@Mock
|
||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||
@@ -115,7 +124,7 @@ public final class AppHibernationServiceTest {
|
||||
private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
|
||||
|
||||
@Before
|
||||
public void setUp() throws RemoteException {
|
||||
public void setUp() throws RemoteException, PackageManager.NameNotFoundException, IOException {
|
||||
// Share class loader to allow access to package-private classes
|
||||
System.setProperty("dexmaker.share_classloader", "true");
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -140,6 +149,11 @@ public final class AppHibernationServiceTest {
|
||||
packages.add(makePackageInfo(PACKAGE_NAME_3));
|
||||
doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
|
||||
longThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
|
||||
doReturn(mock(ApplicationInfo.class)).when(mIPackageManager).getApplicationInfo(
|
||||
any(), anyLong(), anyInt());
|
||||
StorageStats storageStats = new StorageStats();
|
||||
doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
|
||||
(UUID) any(), anyString(), any());
|
||||
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
|
||||
|
||||
UserInfo userInfo = addUser(USER_ID_1);
|
||||
@@ -381,18 +395,31 @@ public final class AppHibernationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHibernationStatsForUser_getsStatsForPackage() {
|
||||
// GIVEN a package is hibernating globally and for a user
|
||||
public void testGetHibernationStatsForUser_getsStatsForPackage()
|
||||
throws PackageManager.NameNotFoundException, IOException, RemoteException {
|
||||
// GIVEN a package is hibernating globally and for a user with some storage saved
|
||||
final long cacheSavings = 1000;
|
||||
StorageStats storageStats = new StorageStats();
|
||||
storageStats.cacheBytes = cacheSavings;
|
||||
doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
|
||||
(UUID) any(), eq(PACKAGE_NAME_1), any());
|
||||
final long oatDeletionSavings = 2000;
|
||||
doReturn(oatDeletionSavings).when(mPackageManagerInternal).deleteOatArtifactsOfPackage(
|
||||
PACKAGE_NAME_1);
|
||||
|
||||
mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
|
||||
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
|
||||
|
||||
// WHEN we ask for the hibernation stats for the package
|
||||
Map<String, HibernationStats> stats =
|
||||
Map<String, HibernationStats> statsMap =
|
||||
mAppHibernationService.getHibernationStatsForUser(
|
||||
Set.of(PACKAGE_NAME_1), USER_ID_1);
|
||||
|
||||
// THEN the stats exist for the package
|
||||
assertTrue(stats.containsKey(PACKAGE_NAME_1));
|
||||
// THEN the stats exist for the package and add up to the OAT deletion and cache deletion
|
||||
// savings
|
||||
HibernationStats stats = statsMap.get(PACKAGE_NAME_1);
|
||||
assertNotNull(stats);
|
||||
assertEquals(cacheSavings + oatDeletionSavings, stats.getDiskBytesSaved());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -518,6 +545,11 @@ public final class AppHibernationServiceTest {
|
||||
return mUserManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageStatsManager getStorageStatsManager() {
|
||||
return mStorageStatsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsageStatsManagerInternal getUsageStatsManagerInternal() {
|
||||
return mUsageStatsManagerInternal;
|
||||
|
||||
Reference in New Issue
Block a user