diff options
| -rw-r--r-- | core/api/current.txt | 4 | ||||
| -rw-r--r-- | core/java/android/app/usage/StorageStats.java | 77 | ||||
| -rw-r--r-- | core/java/android/app/usage/flags.aconfig | 7 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageStats.java | 39 | ||||
| -rw-r--r-- | services/usage/java/com/android/server/usage/StorageStatsService.java | 69 |
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/")); + } } |