Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec7a413c authored by Haiping Yang's avatar Haiping Yang
Browse files

Add getAppBytesByDataType API to StorageStats.

Bug: 294088945
Test: CtsAppSecurityHostTestCases:android.appsecurity.cts.StorageStatsTest

Change-Id: I09c425a5ee2d053d7ce7d7931db2bdeb2af92bc3
parent 483e3f63
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -9312,10 +9312,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;
  }
+73 −4
Original line number Diff line number Diff line
@@ -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
@@ -47,6 +89,27 @@ public final class StorageStats implements Parcelable {
        return codeBytes;
    }

    /**
     * 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()},
@@ -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);
    }

+7 −0
Original line number Diff line number Diff line
@@ -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"
}
+38 −1
Original line number Diff line number Diff line
@@ -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);
    }

+67 −2
Original line number Diff line number Diff line
@@ -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],
@@ -445,13 +447,16 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
                        codePaths = ArrayUtils.appendElement(String.class, codePaths,
                            appInfo.getCodePath());
                    }
                    if (Flags.getAppBytesByDataTypeApi()) {
                        computeAppStatsByDataTypes(
                            stats, appInfo.sourceDir);
                    }
                }
            } catch (NameNotFoundException e) {
                throw new ParcelableException(e);
            }
        }

        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/"));
    }
}