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

Commit 24173f52 authored by Haiping Yang's avatar Haiping Yang Committed by Android (Google) Code Review
Browse files

Merge "Add getAppBytesByDataType API to StorageStats." into main

parents ad40446e ec7a413c
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;
  }
+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/"));
    }
}