From 60f95aa00a24c8f8548726bf2f30c951a4efe20a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 8 Mar 2017 13:57:15 -0700 Subject: [PATCH] Move lagging users over to new storage API. Over the last month we've been moving everyone over to the new StorageStatsManager public APIs, but we missed these users. The ApplicationsState changes are straightforward, but we had to completely rewrite StorageMeasurement to use the new fast-path quota APIs. Test: builds, boots, UI using StorageMeasurement works. Bug: 36056120 Change-Id: If02177c95bf8c96ae4eceac4d631a168f99bef84 --- api/current.txt | 2 +- api/system-current.txt | 2 +- api/test-current.txt | 2 +- .../android/content/pm/PackageManager.java | 5 + .../java/android/content/pm/PackageStats.java | 9 +- .../applications/ApplicationsState.java | 38 +- .../deviceinfo/StorageMeasurement.java | 436 ++++-------------- 7 files changed, 130 insertions(+), 364 deletions(-) diff --git a/api/current.txt b/api/current.txt index d68610edf9fdd..b40da5c7a0581 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10703,7 +10703,7 @@ package android.content.pm { ctor public PackageManager.NameNotFoundException(java.lang.String); } - public class PackageStats implements android.os.Parcelable { + public deprecated class PackageStats implements android.os.Parcelable { ctor public PackageStats(java.lang.String); ctor public PackageStats(android.os.Parcel); ctor public PackageStats(android.content.pm.PackageStats); diff --git a/api/system-current.txt b/api/system-current.txt index cb0d7b1371b02..7a43b66469a1b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11423,7 +11423,7 @@ package android.content.pm { public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation { } - public class PackageStats implements android.os.Parcelable { + public deprecated class PackageStats implements android.os.Parcelable { ctor public PackageStats(java.lang.String); ctor public PackageStats(android.os.Parcel); ctor public PackageStats(android.content.pm.PackageStats); diff --git a/api/test-current.txt b/api/test-current.txt index f8e6785345c4a..9b3992bd74100 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -10739,7 +10739,7 @@ package android.content.pm { ctor public PackageManager.NameNotFoundException(java.lang.String); } - public class PackageStats implements android.os.Parcelable { + public deprecated class PackageStats implements android.os.Parcelable { ctor public PackageStats(java.lang.String); ctor public PackageStats(android.os.Parcel); ctor public PackageStats(android.content.pm.PackageStats); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 664e76b914798..3a875bc79aa8e 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -34,6 +34,7 @@ import android.annotation.XmlRes; import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; import android.app.admin.DevicePolicyManager; +import android.app.usage.StorageStatsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -5466,8 +5467,10 @@ public abstract class PackageManager { * the status of the operation. observer may be null to indicate that * no callback is desired. * + * @deprecated use {@link StorageStatsManager} instead. * @hide */ + @Deprecated public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId, IPackageStatsObserver observer); @@ -5475,8 +5478,10 @@ public abstract class PackageManager { * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but * returns the size for the calling user. * + * @deprecated use {@link StorageStatsManager} instead. * @hide */ + @Deprecated public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) { getPackageSizeInfoAsUser(packageName, UserHandle.myUserId(), observer); } diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java index c746af4c9ea3b..27b3506f49a70 100644 --- a/core/java/android/content/pm/PackageStats.java +++ b/core/java/android/content/pm/PackageStats.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.app.usage.StorageStatsManager; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; @@ -24,9 +25,13 @@ import android.text.TextUtils; import java.util.Objects; /** - * implementation of PackageStats associated with a - * application package. + * implementation of PackageStats associated with a application package. + * + * @deprecated this class is an orphan that could never be obtained from a valid + * public API. If you need package storage statistics use the new + * {@link StorageStatsManager} APIs. */ +@Deprecated public class PackageStats implements Parcelable { /** Name of the package to which this stats applies. */ public String packageName; diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index fda3914d1fc08..8f7efb59d8c43 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -19,6 +19,8 @@ package com.android.settingslib.applications; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.Application; +import android.app.usage.StorageStats; +import android.app.usage.StorageStatsManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -92,6 +94,7 @@ public class ApplicationsState { final PackageManager mPm; final IPackageManager mIpm; final UserManager mUm; + final StorageStatsManager mStats; final int mAdminRetrieveFlags; final int mRetrieveFlags; PackageIntentReceiver mPackageIntentReceiver; @@ -111,6 +114,7 @@ public class ApplicationsState { final ArrayList mAppEntries = new ArrayList(); List mApplications = new ArrayList(); long mCurId = 1; + String mCurComputingSizeUuid; String mCurComputingSizePkg; int mCurComputingSizeUserId; boolean mSessionsChanged; @@ -126,7 +130,8 @@ public class ApplicationsState { mContext = app; mPm = mContext.getPackageManager(); mIpm = AppGlobals.getPackageManager(); - mUm = (UserManager) app.getSystemService(Context.USER_SERVICE); + mUm = mContext.getSystemService(UserManager.class); + mStats = mContext.getSystemService(StorageStatsManager.class); for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) { mEntriesMap.put(userId, new HashMap()); } @@ -328,7 +333,18 @@ public class ApplicationsState { synchronized (mEntriesMap) { AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry != null) { - mPm.getPackageSizeInfoAsUser(packageName, userId, mBackgroundHandler.mStatsObserver); + mBackgroundHandler.post(() -> { + final StorageStats stats = mStats.queryStatsForPackage(entry.info.volumeUuid, + packageName, UserHandle.of(userId)); + final PackageStats legacyStats = new PackageStats(packageName, userId); + legacyStats.codeSize = stats.getCodeBytes(); + legacyStats.dataSize = stats.getDataBytes(); + legacyStats.cacheSize = stats.getCacheBytes(); + try { + mBackgroundHandler.mStatsObserver.onGetStatsCompleted(legacyStats, true); + } catch (RemoteException ignored) { + } + }); } if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock"); } @@ -958,10 +974,24 @@ public class ApplicationsState { mMainHandler.sendMessage(m); } entry.sizeLoadStart = now; + mCurComputingSizeUuid = entry.info.volumeUuid; mCurComputingSizePkg = entry.info.packageName; mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); - mPm.getPackageSizeInfoAsUser(mCurComputingSizePkg, - mCurComputingSizeUserId, mStatsObserver); + + mBackgroundHandler.post(() -> { + final StorageStats stats = mStats.queryStatsForPackage( + mCurComputingSizeUuid, mCurComputingSizePkg, + UserHandle.of(mCurComputingSizeUserId)); + final PackageStats legacyStats = new PackageStats( + mCurComputingSizePkg, mCurComputingSizeUserId); + legacyStats.codeSize = stats.getCodeBytes(); + legacyStats.dataSize = stats.getDataBytes(); + legacyStats.cacheSize = stats.getCacheBytes(); + try { + mStatsObserver.onGetStatsCompleted(legacyStats, true); + } catch (RemoteException ignored) { + } + }); } if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing"); return; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index e520319c1eb7f..953dda29d7c4f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -16,22 +16,14 @@ package com.android.settingslib.deviceinfo; -import android.app.ActivityManager; -import android.content.ComponentName; +import android.app.usage.ExternalStorageStats; +import android.app.usage.StorageStats; +import android.app.usage.StorageStatsManager; import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.PackageManager; -import android.content.pm.PackageStats; import android.content.pm.UserInfo; +import android.os.AsyncTask; import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageVolume; @@ -40,93 +32,54 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseLongArray; -import com.android.internal.app.IMediaContainerService; -import com.android.internal.util.ArrayUtils; -import com.google.android.collect.Sets; - -import java.io.File; import java.lang.ref.WeakReference; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Objects; -import java.util.Set; /** * Utility for measuring the disk usage of internal storage or a physical - * {@link StorageVolume}. Connects with a remote {@link IMediaContainerService} - * and delivers results to {@link MeasurementReceiver}. + * {@link StorageVolume}. */ public class StorageMeasurement { private static final String TAG = "StorageMeasurement"; - private static final boolean LOCAL_LOGV = false; - static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE); - - private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; - - public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( - DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService"); - - /** Media types to measure on external storage. */ - private static final Set sMeasureMediaTypes = Sets.newHashSet( - Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES, - Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC, - Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS, - Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS, - Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID); - public static class MeasurementDetails { + /** Size of storage device. */ public long totalSize; + /** Size of available space. */ public long availSize; + /** Size of all cached data. */ + public long cacheSize; /** - * Total apps disk usage per profiles of the current user. + * Total disk space used by everything. *

- * When measuring internal storage, this value includes the code size of - * all apps (regardless of install status for the given profile), and - * internal disk used by the profile's apps. When the device - * emulates external storage, this value also includes emulated storage - * used by the profile's apps. - *

- * When measuring a physical {@link StorageVolume}, this value includes - * usage by all apps on that volume and only for the primary profile. + * Key is {@link UserHandle}. + */ + public SparseLongArray usersSize = new SparseLongArray(); + + /** + * Total disk space used by apps. *

* Key is {@link UserHandle}. */ public SparseLongArray appsSize = new SparseLongArray(); /** - * Total cache disk usage by apps (over all users and profiles). - */ - public long cacheSize; - - /** - * Total media disk usage, categorized by types such as - * {@link Environment#DIRECTORY_MUSIC} for every user profile of the current user. + * Total disk space used by media on shared storage. *

- * When measuring internal storage, this reflects media on emulated - * storage for the respective profile. - *

- * When measuring a physical {@link StorageVolume}, this reflects media - * on that volume. - *

- * Key of the {@link SparseArray} is {@link UserHandle}. + * First key is {@link UserHandle}. Second key is media type, such as + * {@link Environment#DIRECTORY_PICTURES}. */ public SparseArray> mediaSize = new SparseArray<>(); /** - * Misc external disk usage for the current user's profiles, unaccounted in - * {@link #mediaSize}. Key is {@link UserHandle}. + * Total disk space used by non-media on shared storage. + *

+ * Key is {@link UserHandle}. */ public SparseLongArray miscSize = new SparseLongArray(); - /** - * Total disk usage for users, which is only meaningful for emulated - * internal storage. Key is {@link UserHandle}. - */ - public SparseLongArray usersSize = new SparseLongArray(); - @Override public String toString() { return "MeasurementDetails: [totalSize: " + totalSize + " availSize: " + availSize @@ -142,25 +95,19 @@ public class StorageMeasurement { private WeakReference mReceiver; private final Context mContext; + private final UserManager mUser; + private final StorageStatsManager mStats; private final VolumeInfo mVolume; private final VolumeInfo mSharedVolume; - private final MainHandler mMainHandler; - private final MeasurementHandler mMeasurementHandler; - public StorageMeasurement(Context context, VolumeInfo volume, VolumeInfo sharedVolume) { mContext = context.getApplicationContext(); + mUser = mContext.getSystemService(UserManager.class); + mStats = mContext.getSystemService(StorageStatsManager.class); mVolume = volume; mSharedVolume = sharedVolume; - - // Start the thread that will measure the disk usage. - final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement"); - handlerThread.start(); - - mMainHandler = new MainHandler(); - mMeasurementHandler = new MeasurementHandler(handlerThread.getLooper()); } public void setReceiver(MeasurementReceiver receiver) { @@ -170,315 +117,94 @@ public class StorageMeasurement { } public void forceMeasure() { - invalidate(); measure(); } public void measure() { - if (!mMeasurementHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) { - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE); - } + new MeasureTask().execute(); } public void onDestroy() { mReceiver = null; - mMeasurementHandler.removeMessages(MeasurementHandler.MSG_MEASURE); - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT); } - private void invalidate() { - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE); - } - - private static class StatsObserver extends IPackageStatsObserver.Stub { - private final boolean mIsPrivate; - private final MeasurementDetails mDetails; - private final int mCurrentUser; - private final Message mFinished; - - private int mRemaining; - - public StatsObserver(boolean isPrivate, MeasurementDetails details, int currentUser, - List profiles, Message finished, int remaining) { - mIsPrivate = isPrivate; - mDetails = details; - mCurrentUser = currentUser; - if (isPrivate) { - // Add the profile ids as keys to detail's app sizes. - for (UserInfo userInfo : profiles) { - mDetails.appsSize.put(userInfo.id, 0); - } - } - mFinished = finished; - mRemaining = remaining; + private class MeasureTask extends AsyncTask { + @Override + protected MeasurementDetails doInBackground(Void... params) { + return measureExactStorage(); } @Override - public void onGetStatsCompleted(PackageStats stats, boolean succeeded) { - synchronized (mDetails) { - if (succeeded) { - addStatsLocked(stats); - } - if (--mRemaining == 0) { - mFinished.sendToTarget(); - } - } - } - - private void addStatsLocked(PackageStats stats) { - if (mIsPrivate) { - long codeSize = stats.codeSize; - long dataSize = stats.dataSize; - long cacheSize = stats.cacheSize; - if (Environment.isExternalStorageEmulated()) { - // Include emulated storage when measuring internal. OBB is - // shared on emulated storage, so treat as code. - codeSize += stats.externalCodeSize + stats.externalObbSize; - dataSize += stats.externalDataSize + stats.externalMediaSize; - cacheSize += stats.externalCacheSize; - } - - // Count code and data for current user's profiles (keys prepared in constructor) - addValueIfKeyExists(mDetails.appsSize, stats.userHandle, codeSize + dataSize); - - // User summary only includes data (code is only counted once - // for the current user) - addValue(mDetails.usersSize, stats.userHandle, dataSize); - - // Include cache for all users - mDetails.cacheSize += cacheSize; - - } else { - // Physical storage; only count external sizes - addValue(mDetails.appsSize, mCurrentUser, - stats.externalCodeSize + stats.externalDataSize - + stats.externalMediaSize + stats.externalObbSize); - mDetails.cacheSize += stats.externalCacheSize; - } - } - } - - private class MainHandler extends Handler { - @Override - public void handleMessage(Message msg) { - final MeasurementDetails details = (MeasurementDetails) msg.obj; + protected void onPostExecute(MeasurementDetails result) { final MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null; if (receiver != null) { - receiver.onDetailsChanged(details); + receiver.onDetailsChanged(result); } } } - private class MeasurementHandler extends Handler { - public static final int MSG_MEASURE = 1; - public static final int MSG_CONNECTED = 2; - public static final int MSG_DISCONNECT = 3; - public static final int MSG_COMPLETED = 4; - public static final int MSG_INVALIDATE = 5; + private MeasurementDetails measureExactStorage() { + final List users = mUser.getUsers(); - private Object mLock = new Object(); - - private IMediaContainerService mDefaultContainer; - - private volatile boolean mBound = false; - - private MeasurementDetails mCached; - - private final ServiceConnection mDefContainerConn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - final IMediaContainerService imcs = IMediaContainerService.Stub.asInterface( - service); - mDefaultContainer = imcs; - mBound = true; - sendMessage(obtainMessage(MSG_CONNECTED, imcs)); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - removeMessages(MSG_CONNECTED); - } - }; - - public MeasurementHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_MEASURE: { - if (mCached != null) { - mMainHandler.obtainMessage(0, mCached).sendToTarget(); - break; - } - - synchronized (mLock) { - if (mBound) { - removeMessages(MSG_DISCONNECT); - sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer)); - } else { - Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); - mContext.bindServiceAsUser(service, mDefContainerConn, - Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); - } - } - break; - } - case MSG_CONNECTED: { - final IMediaContainerService imcs = (IMediaContainerService) msg.obj; - measureExactStorage(imcs); - break; - } - case MSG_DISCONNECT: { - synchronized (mLock) { - if (mBound) { - mBound = false; - mContext.unbindService(mDefContainerConn); - } - } - break; - } - case MSG_COMPLETED: { - mCached = (MeasurementDetails) msg.obj; - mMainHandler.obtainMessage(0, mCached).sendToTarget(); - break; - } - case MSG_INVALIDATE: { - mCached = null; - break; - } - } - } - } - - private void measureExactStorage(IMediaContainerService imcs) { - final UserManager userManager = mContext.getSystemService(UserManager.class); - final PackageManager packageManager = mContext.getPackageManager(); - - final List users = userManager.getUsers(); - final List currentProfiles = userManager.getEnabledProfiles( - ActivityManager.getCurrentUser()); + final long start = SystemClock.elapsedRealtime(); final MeasurementDetails details = new MeasurementDetails(); - final Message finished = mMeasurementHandler.obtainMessage(MeasurementHandler.MSG_COMPLETED, - details); + if (mVolume == null) return details; - if (mVolume == null || !mVolume.isMountedReadable()) { - finished.sendToTarget(); - return; - } + details.totalSize = mStats.getTotalBytes(mVolume.fsUuid); + details.availSize = mStats.getFreeBytes(mVolume.fsUuid); + + final long finishTotal = SystemClock.elapsedRealtime(); + Log.d(TAG, "Measured total storage in " + (finishTotal - start) + "ms"); if (mSharedVolume != null && mSharedVolume.isMountedReadable()) { - for (UserInfo currentUserInfo : currentProfiles) { - final int userId = currentUserInfo.id; - final File basePath = mSharedVolume.getPathForUser(userId); - HashMap mediaMap = new HashMap<>(sMeasureMediaTypes.size()); - details.mediaSize.put(userId, mediaMap); - - // Measure media types for emulated storage, or for primary physical - // external volume - for (String type : sMeasureMediaTypes) { - final File path = new File(basePath, type); - final long size = getDirectorySize(imcs, path); - mediaMap.put(type, size); - } - - // Measure misc files not counted under media - addValue(details.miscSize, userId, measureMisc(imcs, basePath)); - } - - if (mSharedVolume.getType() == VolumeInfo.TYPE_EMULATED) { - // Measure total emulated storage of all users; internal apps data - // will be spliced in later - for (UserInfo user : users) { - final File userPath = mSharedVolume.getPathForUser(user.id); - final long size = getDirectorySize(imcs, userPath); - addValue(details.usersSize, user.id, size); - } - } - } - - final File file = mVolume.getPath(); - if (file != null) { - details.totalSize = file.getTotalSpace(); - details.availSize = file.getFreeSpace(); - } - - // Measure all apps hosted on this volume for all users - if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) { - final List apps = packageManager.getInstalledApplications( - PackageManager.MATCH_ANY_USER - | PackageManager.MATCH_DISABLED_COMPONENTS); - - final List volumeApps = new ArrayList<>(); - for (ApplicationInfo app : apps) { - if (Objects.equals(app.volumeUuid, mVolume.getFsUuid())) { - volumeApps.add(app); - } - } - - final int count = users.size() * volumeApps.size(); - if (count == 0) { - finished.sendToTarget(); - return; - } - - final StatsObserver observer = new StatsObserver(true, details, - ActivityManager.getCurrentUser(), currentProfiles, finished, count); for (UserInfo user : users) { - for (ApplicationInfo app : volumeApps) { - packageManager.getPackageSizeInfoAsUser(app.packageName, user.id, observer); + final HashMap mediaMap = new HashMap<>(); + details.mediaSize.put(user.id, mediaMap); + + final ExternalStorageStats stats = mStats + .queryExternalStatsForUser(mSharedVolume.fsUuid, UserHandle.of(user.id)); + + addValue(details.usersSize, user.id, stats.getTotalBytes()); + + // Track detailed data types + mediaMap.put(Environment.DIRECTORY_MUSIC, stats.getAudioBytes()); + mediaMap.put(Environment.DIRECTORY_MOVIES, stats.getVideoBytes()); + mediaMap.put(Environment.DIRECTORY_PICTURES, stats.getImageBytes()); + + final long miscBytes = stats.getTotalBytes() - stats.getAudioBytes() + - stats.getVideoBytes() - stats.getImageBytes(); + addValue(details.miscSize, user.id, miscBytes); + } + } + + final long finishShared = SystemClock.elapsedRealtime(); + Log.d(TAG, "Measured shared storage in " + (finishShared - finishTotal) + "ms"); + + if ((mVolume.getType() == VolumeInfo.TYPE_PRIVATE) && mVolume.isMountedReadable()) { + for (UserInfo user : users) { + final StorageStats stats = mStats.queryStatsForUser(mVolume.fsUuid, + UserHandle.of(user.id)); + + // Only count code once against current user + if (user.id == UserHandle.myUserId()) { + addValue(details.usersSize, user.id, stats.getCodeBytes()); } - } - } else { - finished.sendToTarget(); - return; - } - } + addValue(details.usersSize, user.id, stats.getDataBytes()); + addValue(details.appsSize, user.id, stats.getCodeBytes() + stats.getDataBytes()); - private static long getDirectorySize(IMediaContainerService imcs, File path) { - try { - final long size = imcs.calculateDirectorySize(path.toString()); - if (LOGV) Log.v(TAG, "getDirectorySize(" + path + ") returned " + size); - return size; - } catch (Exception e) { - Log.w(TAG, "Could not read memory from default container service for " + path, e); - return 0; - } - } - - private long measureMisc(IMediaContainerService imcs, File dir) { - final File[] files = dir.listFiles(); - if (ArrayUtils.isEmpty(files)) return 0; - - // Get sizes of all top level nodes except the ones already computed - long miscSize = 0; - for (File file : files) { - final String name = file.getName(); - if (sMeasureMediaTypes.contains(name)) { - continue; - } - - if (file.isFile()) { - miscSize += file.length(); - } else if (file.isDirectory()) { - miscSize += getDirectorySize(imcs, file); + details.cacheSize += stats.getCacheBytes(); } } - return miscSize; + + final long finishPrivate = SystemClock.elapsedRealtime(); + Log.d(TAG, "Measured private storage in " + (finishPrivate - finishShared) + "ms"); + + return details; } private static void addValue(SparseLongArray array, int key, long value) { array.put(key, array.get(key) + value); } - - private static void addValueIfKeyExists(SparseLongArray array, int key, long value) { - final int index = array.indexOfKey(key); - if (index >= 0) { - array.put(key, array.valueAt(index) + value); - } - } }