diff --git a/api/current.txt b/api/current.txt index 5b55fdc4b9666..9f72f12f1e875 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6924,6 +6924,7 @@ package android.app.usage { public final class ExternalStorageStats implements android.os.Parcelable { method public int describeContents(); + method public long getAppBytes(); method public long getAudioBytes(); method public long getImageBytes(); method public long getTotalBytes(); diff --git a/api/system-current.txt b/api/system-current.txt index 23a8cad152daf..3d95d0d550777 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7389,6 +7389,7 @@ package android.app.usage { public final class ExternalStorageStats implements android.os.Parcelable { method public int describeContents(); + method public long getAppBytes(); method public long getAudioBytes(); method public long getImageBytes(); method public long getTotalBytes(); diff --git a/api/test-current.txt b/api/test-current.txt index 3373ab735a364..329b87199858b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6954,6 +6954,7 @@ package android.app.usage { public final class ExternalStorageStats implements android.os.Parcelable { method public int describeContents(); + method public long getAppBytes(); method public long getAudioBytes(); method public long getImageBytes(); method public long getTotalBytes(); diff --git a/core/java/android/app/usage/ExternalStorageStats.java b/core/java/android/app/usage/ExternalStorageStats.java index 1166df06c9175..10c9b5ff5a504 100644 --- a/core/java/android/app/usage/ExternalStorageStats.java +++ b/core/java/android/app/usage/ExternalStorageStats.java @@ -31,6 +31,7 @@ public final class ExternalStorageStats implements Parcelable { /** {@hide} */ public long audioBytes; /** {@hide} */ public long videoBytes; /** {@hide} */ public long imageBytes; + /** {@hide} */ public long appBytes; /** * Return the total bytes used by all files in the shared/external storage @@ -64,6 +65,17 @@ public final class ExternalStorageStats implements Parcelable { return imageBytes; } + /** + * Return the total bytes used by app files in the shared/external storage + * hosted on this volume. + *
+ * This data is already accounted against individual apps as returned
+ * through {@link StorageStats}.
+ */
+ public long getAppBytes() {
+ return appBytes;
+ }
+
/** {@hide} */
public ExternalStorageStats() {
}
@@ -74,6 +86,7 @@ public final class ExternalStorageStats implements Parcelable {
this.audioBytes = in.readLong();
this.videoBytes = in.readLong();
this.imageBytes = in.readLong();
+ this.appBytes = in.readLong();
}
@Override
@@ -87,6 +100,7 @@ public final class ExternalStorageStats implements Parcelable {
dest.writeLong(audioBytes);
dest.writeLong(videoBytes);
dest.writeLong(imageBytes);
+ dest.writeLong(appBytes);
}
public static final Creator
- * Note: multiple packages using the same {@code sharedUserId} in their manifest
- * will be merged into a single UID.
- *
+ * If the primary external/shared storage is hosted on this storage device,
+ * then this includes files stored under {@link Context#getObbDir()}.
+ *
* Code is shared between all users on a multiuser device.
*/
public long getCodeBytes() {
@@ -51,6 +50,12 @@ public final class StorageStats implements Parcelable {
* {@link Context#getDataDir()}, {@link Context#getCacheDir()},
* {@link Context#getCodeCacheDir()}.
*
+ * If the primary external/shared storage is hosted on this storage device,
+ * then this includes files stored under
+ * {@link Context#getExternalFilesDir(String)},
+ * {@link Context#getExternalCacheDir()}, and
+ * {@link Context#getExternalMediaDirs()}.
+ *
* Data is isolated for each user on a multiuser device.
*/
public long getDataBytes() {
@@ -61,6 +66,10 @@ public final class StorageStats implements Parcelable {
* Return the size of all cached data. This includes files stored under
* {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}.
*
+ * If the primary external/shared storage is hosted on this storage device,
+ * then this includes files stored under
+ * {@link Context#getExternalCacheDir()}.
+ *
* Cached data is isolated for each user on a multiuser device.
*/
public long getCacheBytes() {
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index 4b6479ad4a7b8..5497d57ba2640 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -73,7 +73,8 @@ public class StorageStatsManager {
}
/**
- * Return the total size of the media hosting this storage volume.
+ * Return the total size of the underlying media that is hosting this
+ * storage volume.
*
* To reduce end user confusion, this value matches the total storage size
* advertised in a retail environment, which is typically larger than the
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3942531735534..e8c256f2279f5 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -730,7 +730,7 @@ public class StorageManager {
*/
public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Preconditions.checkNotNull(path);
- final String pathString = path.getAbsolutePath();
+ final String pathString = path.getCanonicalPath();
if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
return UUID_DEFAULT;
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 1e2b743d5e46c..c5cefc804f7e0 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -258,10 +258,11 @@ public class Installer extends SystemService {
}
}
- public long[] getExternalSize(String uuid, int userId, int flags) throws InstallerException {
+ public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
+ throws InstallerException {
if (!checkBeforeRemote()) return new long[4];
try {
- return mInstalld.getExternalSize(uuid, userId, flags);
+ return mInstalld.getExternalSize(uuid, userId, flags, appIds);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
index b5a6178da700f..3fd1d556df147 100644
--- a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
@@ -120,15 +120,7 @@ public class InstallerTest extends AndroidTestCase {
}
public void testGetUserSize() throws Exception {
- int[] appIds = null;
-
- final PackageManager pm = getContext().getPackageManager();
- for (ApplicationInfo app : pm.getInstalledApplications(0)) {
- final int appId = UserHandle.getAppId(app.uid);
- if (!ArrayUtils.contains(appIds, appId)) {
- appIds = ArrayUtils.appendInt(appIds, appId);
- }
- }
+ final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
final PackageStats stats = new PackageStats("android");
final PackageStats quotaStats = new PackageStats("android");
@@ -147,13 +139,15 @@ public class InstallerTest extends AndroidTestCase {
}
public void testGetExternalSize() throws Exception {
+ final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
+
mManual.start();
- final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0);
+ final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0, appIds);
mManual.stop();
mQuota.start();
final long[] quotaStats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM,
- Installer.FLAG_USE_QUOTA);
+ Installer.FLAG_USE_QUOTA, appIds);
mQuota.stop();
for (int i = 0; i < stats.length; i++) {
@@ -161,6 +155,18 @@ public class InstallerTest extends AndroidTestCase {
}
}
+ private int[] getAppIds(int userId) {
+ int[] appIds = null;
+ for (ApplicationInfo app : getContext().getPackageManager().getInstalledApplicationsAsUser(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
+ final int appId = UserHandle.getAppId(app.uid);
+ if (!ArrayUtils.contains(appIds, appId)) {
+ appIds = ArrayUtils.appendInt(appIds, appId);
+ }
+ }
+ return appIds;
+ }
+
private static void checkEquals(String msg, PackageStats a, PackageStats b) {
checkEquals(msg + " codeSize", a.codeSize, b.codeSize);
checkEquals(msg + " dataSize", a.dataSize, b.dataSize);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 094c7bd89ba0b..2ebf5fc1c5331 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -235,7 +235,14 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
final int appId = UserHandle.getUserId(appInfo.uid);
final String[] packageNames = new String[] { packageName };
final long[] ceDataInodes = new long[1];
- final String[] codePaths = new String[] { appInfo.getCodePath() };
+ String[] codePaths = new String[0];
+
+ if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
+ // We don't count code baked into system image
+ } else {
+ codePaths = ArrayUtils.appendElement(String.class, codePaths,
+ appInfo.getCodePath());
+ }
final PackageStats stats = new PackageStats(TAG);
try {
@@ -261,12 +268,18 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
final String[] packageNames = mPackage.getPackagesForUid(uid);
final long[] ceDataInodes = new long[packageNames.length];
- final String[] codePaths = new String[packageNames.length];
+ String[] codePaths = new String[0];
for (int i = 0; i < packageNames.length; i++) {
try {
- codePaths[i] = mPackage.getApplicationInfoAsUser(packageNames[i],
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId).getCodePath();
+ final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageNames[i],
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
+ // We don't count code baked into system image
+ } else {
+ codePaths = ArrayUtils.appendElement(String.class, codePaths,
+ appInfo.getCodePath());
+ }
} catch (NameNotFoundException e) {
throw new ParcelableException(e);
}
@@ -297,15 +310,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}
- int[] appIds = null;
- for (ApplicationInfo app : mPackage.getInstalledApplicationsAsUser(
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
- final int appId = UserHandle.getAppId(app.uid);
- if (!ArrayUtils.contains(appIds, appId)) {
- appIds = ArrayUtils.appendInt(appIds, appId);
- }
- }
-
+ final int[] appIds = getAppIds(userId);
final PackageStats stats = new PackageStats(TAG);
try {
mInstaller.getUserSize(volumeUuid, userId, getDefaultFlags(), appIds, stats);
@@ -330,12 +335,14 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
}
+ final int[] appIds = getAppIds(userId);
final long[] stats;
try {
- stats = mInstaller.getExternalSize(volumeUuid, userId, getDefaultFlags());
+ stats = mInstaller.getExternalSize(volumeUuid, userId, getDefaultFlags(), appIds);
if (SystemProperties.getBoolean(PROP_VERIFY_STORAGE, false)) {
- final long[] manualStats = mInstaller.getExternalSize(volumeUuid, userId, 0);
+ final long[] manualStats = mInstaller.getExternalSize(volumeUuid, userId, 0,
+ appIds);
checkEquals("External " + userId, manualStats, stats);
}
} catch (InstallerException e) {
@@ -347,9 +354,22 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
res.audioBytes = stats[1];
res.videoBytes = stats[2];
res.imageBytes = stats[3];
+ res.appBytes = stats[4];
return res;
}
+ private int[] getAppIds(int userId) {
+ int[] appIds = null;
+ for (ApplicationInfo app : mPackage.getInstalledApplicationsAsUser(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
+ final int appId = UserHandle.getAppId(app.uid);
+ if (!ArrayUtils.contains(appIds, appId)) {
+ appIds = ArrayUtils.appendInt(appIds, appId);
+ }
+ }
+ return appIds;
+ }
+
private static int getDefaultFlags() {
if (SystemProperties.getBoolean(PROP_DISABLE_QUOTA, false)) {
return 0;