summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt4
-rw-r--r--core/java/android/app/usage/StorageStats.java77
-rw-r--r--core/java/android/app/usage/flags.aconfig7
-rw-r--r--core/java/android/content/pm/PackageStats.java39
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java69
5 files changed, 189 insertions, 7 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ecb242a6a217..b043503561de 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9315,10 +9315,14 @@ package android.app.usage {
public final class StorageStats implements android.os.Parcelable {
method public int describeContents();
method public long getAppBytes();
+ method @FlaggedApi("android.app.usage.get_app_bytes_by_data_type_api") public long getAppBytesByDataType(int);
method public long getCacheBytes();
method public long getDataBytes();
method public long getExternalCacheBytes();
method public void writeToParcel(android.os.Parcel, int);
+ field @FlaggedApi("android.app.usage.get_app_bytes_by_data_type_api") public static final int APP_DATA_TYPE_FILE_TYPE_APK = 0; // 0x0
+ field @FlaggedApi("android.app.usage.get_app_bytes_by_data_type_api") public static final int APP_DATA_TYPE_FILE_TYPE_DM = 1; // 0x1
+ field @FlaggedApi("android.app.usage.get_app_bytes_by_data_type_api") public static final int APP_DATA_TYPE_LIB = 2; // 0x2
field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
}
diff --git a/core/java/android/app/usage/StorageStats.java b/core/java/android/app/usage/StorageStats.java
index 8d25d7bfb11b..87d97d55318a 100644
--- a/core/java/android/app/usage/StorageStats.java
+++ b/core/java/android/app/usage/StorageStats.java
@@ -17,11 +17,16 @@
package android.app.usage;
import android.annotation.BytesLong;
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Storage statistics for a UID, package, or {@link UserHandle} on a single
* storage volume.
@@ -29,10 +34,47 @@ import android.os.UserHandle;
* @see StorageStatsManager
*/
public final class StorageStats implements Parcelable {
- /** {@hide} */ public long codeBytes;
- /** {@hide} */ public long dataBytes;
- /** {@hide} */ public long cacheBytes;
- /** {@hide} */ public long externalCacheBytes;
+ /** @hide */ public long codeBytes;
+ /** @hide */ public long dataBytes;
+ /** @hide */ public long cacheBytes;
+ /** @hide */ public long apkBytes;
+ /** @hide */ public long libBytes;
+ /** @hide */ public long dmBytes;
+ /** @hide */ public long externalCacheBytes;
+
+ /** Represents all .apk files in application code path.
+ * Can be used as an input to {@link #getAppBytesByDataType(int)}
+ * to get the sum of sizes for files of this type.
+ */
+ @FlaggedApi(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API)
+ public static final int APP_DATA_TYPE_FILE_TYPE_APK = 0;
+
+ /** Represents all .dm files in application code path.
+ * Can be used as an input to {@link #getAppBytesByDataType(int)}
+ * to get the sum of sizes for files of this type.
+ */
+ @FlaggedApi(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API)
+ public static final int APP_DATA_TYPE_FILE_TYPE_DM = 1;
+
+ /** Represents lib/ in application code path.
+ * Can be used as an input to {@link #getAppBytesByDataType(int)}
+ * to get the size of lib/ directory.
+ */
+ @FlaggedApi(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API)
+ public static final int APP_DATA_TYPE_LIB = 2;
+
+ /**
+ * Keep in sync with the file types defined above.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API)
+ @IntDef(flag = false, value = {
+ APP_DATA_TYPE_FILE_TYPE_APK,
+ APP_DATA_TYPE_FILE_TYPE_DM,
+ APP_DATA_TYPE_LIB,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AppDataType {}
/**
* Return the size of app. This includes {@code APK} files, optimized
@@ -48,6 +90,27 @@ public final class StorageStats implements Parcelable {
}
/**
+ * Return the size of the specified data type. This includes files stored under
+ * application code path.
+ * <p>
+ * If there is more than one package inside a uid, the return represents the aggregated
+ * stats when query StorageStat for package or uid.
+ * The data is not collected and the return defaults to 0 when query StorageStats for user.
+ *
+ * <p>
+ * Data is isolated for each user on a multiuser device.
+ */
+ @FlaggedApi(Flags.FLAG_GET_APP_BYTES_BY_DATA_TYPE_API)
+ public long getAppBytesByDataType(@AppDataType int dataType) {
+ switch (dataType) {
+ case APP_DATA_TYPE_FILE_TYPE_APK: return apkBytes;
+ case APP_DATA_TYPE_LIB: return libBytes;
+ case APP_DATA_TYPE_FILE_TYPE_DM: return dmBytes;
+ default: return 0;
+ }
+ }
+
+ /**
* Return the size of all data. This includes files stored under
* {@link Context#getDataDir()}, {@link Context#getCacheDir()},
* {@link Context#getCodeCacheDir()}.
@@ -98,6 +161,9 @@ public final class StorageStats implements Parcelable {
this.codeBytes = in.readLong();
this.dataBytes = in.readLong();
this.cacheBytes = in.readLong();
+ this.apkBytes = in.readLong();
+ this.libBytes = in.readLong();
+ this.dmBytes = in.readLong();
this.externalCacheBytes = in.readLong();
}
@@ -111,6 +177,9 @@ public final class StorageStats implements Parcelable {
dest.writeLong(codeBytes);
dest.writeLong(dataBytes);
dest.writeLong(cacheBytes);
+ dest.writeLong(apkBytes);
+ dest.writeLong(libBytes);
+ dest.writeLong(dmBytes);
dest.writeLong(externalCacheBytes);
}
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index a611255c3817..4d9d911ed563 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -35,3 +35,10 @@ flag {
description: " Feature flag to support filter based event query API"
bug: "194321117"
}
+
+flag {
+ name: "get_app_bytes_by_data_type_api"
+ namespace: "system_performance"
+ description: "Feature flag for collecting app data size by file type API"
+ bug: "294088945"
+}
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 81cfc078c035..b919c4b065fd 100644
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -55,6 +55,18 @@ public class PackageStats implements Parcelable {
/** Size of cache used by the application. (e.g., /data/data/<app>/cache) */
public long cacheSize;
+ /** Size of .apk files of the application. */
+ /** @hide */
+ public long apkSize;
+
+ /** Size of the libraries of the application. */
+ /** @hide */
+ public long libSize;
+
+ /** Size of the .dm files of the application. */
+ /** @hide */
+ public long dmSize;
+
/**
* Size of the secure container on external storage holding the
* application's code.
@@ -108,6 +120,18 @@ public class PackageStats implements Parcelable {
sb.append(" cache=");
sb.append(cacheSize);
}
+ if (apkSize != 0) {
+ sb.append(" apk=");
+ sb.append(apkSize);
+ }
+ if (libSize != 0) {
+ sb.append(" lib=");
+ sb.append(libSize);
+ }
+ if (dmSize != 0) {
+ sb.append(" dm=");
+ sb.append(dmSize);
+ }
if (externalCodeSize != 0) {
sb.append(" extCode=");
sb.append(externalCodeSize);
@@ -149,6 +173,9 @@ public class PackageStats implements Parcelable {
codeSize = source.readLong();
dataSize = source.readLong();
cacheSize = source.readLong();
+ apkSize = source.readLong();
+ libSize = source.readLong();
+ dmSize = source.readLong();
externalCodeSize = source.readLong();
externalDataSize = source.readLong();
externalCacheSize = source.readLong();
@@ -162,6 +189,9 @@ public class PackageStats implements Parcelable {
codeSize = pStats.codeSize;
dataSize = pStats.dataSize;
cacheSize = pStats.cacheSize;
+ apkSize = pStats.apkSize;
+ libSize = pStats.libSize;
+ dmSize = pStats.dmSize;
externalCodeSize = pStats.externalCodeSize;
externalDataSize = pStats.externalDataSize;
externalCacheSize = pStats.externalCacheSize;
@@ -179,6 +209,9 @@ public class PackageStats implements Parcelable {
dest.writeLong(codeSize);
dest.writeLong(dataSize);
dest.writeLong(cacheSize);
+ dest.writeLong(apkSize);
+ dest.writeLong(libSize);
+ dest.writeLong(dmSize);
dest.writeLong(externalCodeSize);
dest.writeLong(externalDataSize);
dest.writeLong(externalCacheSize);
@@ -198,6 +231,9 @@ public class PackageStats implements Parcelable {
&& codeSize == otherStats.codeSize
&& dataSize == otherStats.dataSize
&& cacheSize == otherStats.cacheSize
+ && apkSize == otherStats.apkSize
+ && libSize == otherStats.libSize
+ && dmSize == otherStats.dmSize
&& externalCodeSize == otherStats.externalCodeSize
&& externalDataSize == otherStats.externalDataSize
&& externalCacheSize == otherStats.externalCacheSize
@@ -208,7 +244,8 @@ public class PackageStats implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(packageName, userHandle, codeSize, dataSize,
- cacheSize, externalCodeSize, externalDataSize, externalCacheSize, externalMediaSize,
+ apkSize, libSize, dmSize, cacheSize, externalCodeSize,
+ externalDataSize, externalCacheSize, externalMediaSize,
externalObbSize);
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 4c978ad01a81..2445f51a4241 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -28,6 +28,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.usage.ExternalStorageStats;
+import android.app.usage.Flags;
import android.app.usage.IStorageStatsManager;
import android.app.usage.StorageStats;
import android.app.usage.UsageStatsManagerInternal;
@@ -434,6 +435,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
final long[] ceDataInodes = new long[packageNames.length];
String[] codePaths = new String[0];
+ final PackageStats stats = new PackageStats(TAG);
for (int i = 0; i < packageNames.length; i++) {
try {
final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageNames[i],
@@ -443,7 +445,11 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
} else {
if (appInfo.getCodePath() != null) {
codePaths = ArrayUtils.appendElement(String.class, codePaths,
- appInfo.getCodePath());
+ appInfo.getCodePath());
+ }
+ if (Flags.getAppBytesByDataTypeApi()) {
+ computeAppStatsByDataTypes(
+ stats, appInfo.sourceDir);
}
}
} catch (NameNotFoundException e) {
@@ -451,7 +457,6 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
}
}
- final PackageStats stats = new PackageStats(TAG);
try {
mInstaller.getAppSize(volumeUuid, packageNames, userId, getDefaultFlags(),
appId, ceDataInodes, codePaths, stats);
@@ -587,6 +592,9 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
res.codeBytes = stats.codeSize + stats.externalCodeSize;
res.dataBytes = stats.dataSize + stats.externalDataSize;
res.cacheBytes = stats.cacheSize + stats.externalCacheSize;
+ res.apkBytes = stats.apkSize;
+ res.libBytes = stats.libSize;
+ res.dmBytes = stats.dmSize;
res.externalCacheBytes = stats.externalCacheSize;
return res;
}
@@ -894,4 +902,61 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
mStorageStatsAugmenters.add(Pair.create(tag, storageStatsAugmenter));
}
}
+
+ private long getDirBytes(File dir) {
+ if (!dir.isDirectory()) {
+ return 0;
+ }
+
+ long size = 0;
+ try {
+ for (File file : dir.listFiles()) {
+ if (file.isFile()) {
+ size += file.length();
+ continue;
+ }
+ if (file.isDirectory()) {
+ size += getDirBytes(file);
+ }
+ }
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed to list directory " + dir.getName());
+ }
+
+ return size;
+ }
+
+ private long getFileBytesInDir(File dir, String suffix) {
+ if (!dir.isDirectory()) {
+ return 0;
+ }
+
+ long size = 0;
+ try {
+ for (File file : dir.listFiles()) {
+ if (file.isFile() && file.getName().endsWith(suffix)) {
+ size += file.length();
+ }
+ }
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed to list directory " + dir.getName());
+ }
+
+ return size;
+ }
+
+ private void computeAppStatsByDataTypes(
+ PackageStats stats, String sourceDirName) {
+
+ // Get apk, lib, dm file sizes.
+ File srcDir = new File(sourceDirName);
+ if (srcDir.isFile()) {
+ sourceDirName = srcDir.getParent();
+ srcDir = new File(sourceDirName);
+ }
+
+ stats.apkSize += getFileBytesInDir(srcDir, ".apk");
+ stats.dmSize += getFileBytesInDir(srcDir, ".dm");
+ stats.libSize += getDirBytes(new File(sourceDirName + "/lib/"));
+ }
}