Loading core/java/android/content/pm/PackageStats.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ package android.content.pm; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; import java.util.Objects; /** * implementation of PackageStats associated with a Loading Loading @@ -173,4 +176,31 @@ public class PackageStats implements Parcelable { dest.writeLong(externalMediaSize); dest.writeLong(externalObbSize); } @Override public boolean equals(Object obj) { if (!(obj instanceof PackageStats)) { return false; } final PackageStats otherStats = (PackageStats) obj; return ((TextUtils.equals(packageName, otherStats.packageName)) && userHandle == otherStats.userHandle && codeSize == otherStats.codeSize && dataSize == otherStats.dataSize && cacheSize == otherStats.cacheSize && externalCodeSize == otherStats.externalCodeSize && externalDataSize == otherStats.externalDataSize && externalCacheSize == otherStats.externalCacheSize && externalMediaSize == otherStats.externalMediaSize && externalObbSize == otherStats.externalObbSize); } @Override public int hashCode() { return Objects.hash(packageName, userHandle, codeSize, dataSize, cacheSize, externalCodeSize, externalDataSize, externalCacheSize, externalMediaSize, externalObbSize); } } services/core/java/com/android/server/storage/AppCollector.java +18 −28 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.storage; import android.annotation.NonNull; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageStatsObserver; Loading Loading @@ -64,7 +66,8 @@ public class AppCollector { mBackgroundHandler = new BackgroundHandler(BackgroundThread.get().getLooper(), volume, context.getPackageManager(), (UserManager) context.getSystemService(Context.USER_SERVICE)); (UserManager) context.getSystemService(Context.USER_SERVICE), (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE)); } /** Loading Loading @@ -93,39 +96,20 @@ public class AppCollector { return value; } private class StatsObserver extends IPackageStatsObserver.Stub { private AtomicInteger mCount; private final ArrayList<PackageStats> mPackageStats; public StatsObserver(int count) { mCount = new AtomicInteger(count); mPackageStats = new ArrayList<>(count); } @Override public void onGetStatsCompleted(PackageStats packageStats, boolean succeeded) throws RemoteException { if (succeeded) { mPackageStats.add(packageStats); } if (mCount.decrementAndGet() == 0) { mStats.complete(mPackageStats); } } } private class BackgroundHandler extends Handler { static final int MSG_START_LOADING_SIZES = 0; private final VolumeInfo mVolume; private final PackageManager mPm; private final UserManager mUm; private final StorageStatsManager mStorageStatsManager; BackgroundHandler(Looper looper, @NonNull VolumeInfo volume, PackageManager pm, UserManager um) { BackgroundHandler(Looper looper, @NonNull VolumeInfo volume, PackageManager pm, UserManager um, StorageStatsManager storageStatsManager) { super(looper); mVolume = volume; mPm = pm; mUm = um; mStorageStatsManager = storageStatsManager; } @Override Loading @@ -149,14 +133,20 @@ public class AppCollector { mStats.complete(new ArrayList<>()); } // Kick off the async package size query for all apps. final StatsObserver observer = new StatsObserver(count); List<PackageStats> stats = new ArrayList<>(); for (UserInfo user : users) { for (ApplicationInfo app : volumeApps) { mPm.getPackageSizeInfoAsUser(app.packageName, user.id, observer); PackageStats packageStats = new PackageStats(app.packageName, user.id); StorageStats storageStats = mStorageStatsManager.queryStatsForPackage( app.volumeUuid, app.packageName, user.getUserHandle()); packageStats.cacheSize = storageStats.getCacheBytes(); packageStats.codeSize = storageStats.getCodeBytes(); packageStats.dataSize = storageStats.getDataBytes(); stats.add(packageStats); } } mStats.complete(stats); } } } Loading services/tests/servicestests/src/com/android/server/storage/AppCollectorTest.java +13 −70 Original line number Diff line number Diff line Loading @@ -16,12 +16,15 @@ package com.android.server.storage; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.pm.UserInfo; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.VolumeInfo; import android.test.AndroidTestCase; Loading Loading @@ -53,6 +56,7 @@ public class AppCollectorTest extends AndroidTestCase { @Mock private Context mContext; @Mock private PackageManager mPm; @Mock private UserManager mUm; @Mock private StorageStatsManager mSsm; private List<ApplicationInfo> mApps; private List<UserInfo> mUsers; Loading @@ -63,6 +67,7 @@ public class AppCollectorTest extends AndroidTestCase { mApps = new ArrayList<>(); when(mContext.getPackageManager()).thenReturn(mPm); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm); when(mContext.getSystemService(Context.STORAGE_STATS_SERVICE)).thenReturn(mSsm); // Set up the app list. when(mPm.getInstalledApplications(anyInt())).thenReturn(mApps); Loading Loading @@ -100,39 +105,9 @@ public class AppCollectorTest extends AndroidTestCase { AppCollector collector = new AppCollector(mContext, volume); PackageStats stats = new PackageStats("com.test.app"); // Set up this to handle the asynchronous call to the PackageManager. This returns the // package info for the specified package. doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { try { ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(stats, true); } catch (Exception e) { // We fail instead of just letting the exception fly because throwing // out of the callback like this on the background thread causes the test // runner to crash, rather than reporting the failure. fail(); } return null; } }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); // Because getPackageStats is a blocking call, we block execution of the test until the // call finishes. In order to finish the call, we need the above answer to execute. List<PackageStats> myStats = new ArrayList<>(); CountDownLatch latch = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run() { myStats.addAll(collector.getPackageStats(TIMEOUT)); latch.countDown(); } }).start(); latch.await(); assertThat(myStats).containsExactly(stats); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats); } @Test Loading @@ -151,43 +126,11 @@ public class AppCollectorTest extends AndroidTestCase { PackageStats otherStats = new PackageStats("com.test.app"); otherStats.userHandle = 1; // Set up this to handle the asynchronous call to the PackageManager. This returns the // package info for our packages. doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { try { ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(stats, true); // Now callback for the other uid. ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(otherStats, true); } catch (Exception e) { // We fail instead of just letting the exception fly because throwing // out of the callback like this on the background thread causes the test // runner to crash, rather than reporting the failure. fail(); } return null; } }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); // Because getPackageStats is a blocking call, we block execution of the test until the // call finishes. In order to finish the call, we need the above answer to execute. List<PackageStats> myStats = new ArrayList<>(); CountDownLatch latch = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run() { myStats.addAll(collector.getPackageStats(TIMEOUT)); latch.countDown(); } }).start(); latch.await(); assertThat(myStats).containsAllOf(stats, otherStats); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(1)))).thenReturn(new StorageStats()); assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats, otherStats); } @Test(expected=NullPointerException.class) Loading Loading
core/java/android/content/pm/PackageStats.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ package android.content.pm; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; import java.util.Objects; /** * implementation of PackageStats associated with a Loading Loading @@ -173,4 +176,31 @@ public class PackageStats implements Parcelable { dest.writeLong(externalMediaSize); dest.writeLong(externalObbSize); } @Override public boolean equals(Object obj) { if (!(obj instanceof PackageStats)) { return false; } final PackageStats otherStats = (PackageStats) obj; return ((TextUtils.equals(packageName, otherStats.packageName)) && userHandle == otherStats.userHandle && codeSize == otherStats.codeSize && dataSize == otherStats.dataSize && cacheSize == otherStats.cacheSize && externalCodeSize == otherStats.externalCodeSize && externalDataSize == otherStats.externalDataSize && externalCacheSize == otherStats.externalCacheSize && externalMediaSize == otherStats.externalMediaSize && externalObbSize == otherStats.externalObbSize); } @Override public int hashCode() { return Objects.hash(packageName, userHandle, codeSize, dataSize, cacheSize, externalCodeSize, externalDataSize, externalCacheSize, externalMediaSize, externalObbSize); } }
services/core/java/com/android/server/storage/AppCollector.java +18 −28 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.storage; import android.annotation.NonNull; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageStatsObserver; Loading Loading @@ -64,7 +66,8 @@ public class AppCollector { mBackgroundHandler = new BackgroundHandler(BackgroundThread.get().getLooper(), volume, context.getPackageManager(), (UserManager) context.getSystemService(Context.USER_SERVICE)); (UserManager) context.getSystemService(Context.USER_SERVICE), (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE)); } /** Loading Loading @@ -93,39 +96,20 @@ public class AppCollector { return value; } private class StatsObserver extends IPackageStatsObserver.Stub { private AtomicInteger mCount; private final ArrayList<PackageStats> mPackageStats; public StatsObserver(int count) { mCount = new AtomicInteger(count); mPackageStats = new ArrayList<>(count); } @Override public void onGetStatsCompleted(PackageStats packageStats, boolean succeeded) throws RemoteException { if (succeeded) { mPackageStats.add(packageStats); } if (mCount.decrementAndGet() == 0) { mStats.complete(mPackageStats); } } } private class BackgroundHandler extends Handler { static final int MSG_START_LOADING_SIZES = 0; private final VolumeInfo mVolume; private final PackageManager mPm; private final UserManager mUm; private final StorageStatsManager mStorageStatsManager; BackgroundHandler(Looper looper, @NonNull VolumeInfo volume, PackageManager pm, UserManager um) { BackgroundHandler(Looper looper, @NonNull VolumeInfo volume, PackageManager pm, UserManager um, StorageStatsManager storageStatsManager) { super(looper); mVolume = volume; mPm = pm; mUm = um; mStorageStatsManager = storageStatsManager; } @Override Loading @@ -149,14 +133,20 @@ public class AppCollector { mStats.complete(new ArrayList<>()); } // Kick off the async package size query for all apps. final StatsObserver observer = new StatsObserver(count); List<PackageStats> stats = new ArrayList<>(); for (UserInfo user : users) { for (ApplicationInfo app : volumeApps) { mPm.getPackageSizeInfoAsUser(app.packageName, user.id, observer); PackageStats packageStats = new PackageStats(app.packageName, user.id); StorageStats storageStats = mStorageStatsManager.queryStatsForPackage( app.volumeUuid, app.packageName, user.getUserHandle()); packageStats.cacheSize = storageStats.getCacheBytes(); packageStats.codeSize = storageStats.getCodeBytes(); packageStats.dataSize = storageStats.getDataBytes(); stats.add(packageStats); } } mStats.complete(stats); } } } Loading
services/tests/servicestests/src/com/android/server/storage/AppCollectorTest.java +13 −70 Original line number Diff line number Diff line Loading @@ -16,12 +16,15 @@ package com.android.server.storage; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.pm.UserInfo; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.VolumeInfo; import android.test.AndroidTestCase; Loading Loading @@ -53,6 +56,7 @@ public class AppCollectorTest extends AndroidTestCase { @Mock private Context mContext; @Mock private PackageManager mPm; @Mock private UserManager mUm; @Mock private StorageStatsManager mSsm; private List<ApplicationInfo> mApps; private List<UserInfo> mUsers; Loading @@ -63,6 +67,7 @@ public class AppCollectorTest extends AndroidTestCase { mApps = new ArrayList<>(); when(mContext.getPackageManager()).thenReturn(mPm); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm); when(mContext.getSystemService(Context.STORAGE_STATS_SERVICE)).thenReturn(mSsm); // Set up the app list. when(mPm.getInstalledApplications(anyInt())).thenReturn(mApps); Loading Loading @@ -100,39 +105,9 @@ public class AppCollectorTest extends AndroidTestCase { AppCollector collector = new AppCollector(mContext, volume); PackageStats stats = new PackageStats("com.test.app"); // Set up this to handle the asynchronous call to the PackageManager. This returns the // package info for the specified package. doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { try { ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(stats, true); } catch (Exception e) { // We fail instead of just letting the exception fly because throwing // out of the callback like this on the background thread causes the test // runner to crash, rather than reporting the failure. fail(); } return null; } }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); // Because getPackageStats is a blocking call, we block execution of the test until the // call finishes. In order to finish the call, we need the above answer to execute. List<PackageStats> myStats = new ArrayList<>(); CountDownLatch latch = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run() { myStats.addAll(collector.getPackageStats(TIMEOUT)); latch.countDown(); } }).start(); latch.await(); assertThat(myStats).containsExactly(stats); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats); } @Test Loading @@ -151,43 +126,11 @@ public class AppCollectorTest extends AndroidTestCase { PackageStats otherStats = new PackageStats("com.test.app"); otherStats.userHandle = 1; // Set up this to handle the asynchronous call to the PackageManager. This returns the // package info for our packages. doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) { try { ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(stats, true); // Now callback for the other uid. ((IPackageStatsObserver.Stub) invocation.getArguments()[2]) .onGetStatsCompleted(otherStats, true); } catch (Exception e) { // We fail instead of just letting the exception fly because throwing // out of the callback like this on the background thread causes the test // runner to crash, rather than reporting the failure. fail(); } return null; } }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any()); // Because getPackageStats is a blocking call, we block execution of the test until the // call finishes. In order to finish the call, we need the above answer to execute. List<PackageStats> myStats = new ArrayList<>(); CountDownLatch latch = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run() { myStats.addAll(collector.getPackageStats(TIMEOUT)); latch.countDown(); } }).start(); latch.await(); assertThat(myStats).containsAllOf(stats, otherStats); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats()); when(mSsm.queryStatsForPackage(eq("testuuid"), eq("com.test.app"), eq(UserHandle.of(1)))).thenReturn(new StorageStats()); assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats, otherStats); } @Test(expected=NullPointerException.class) Loading