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

Commit f45badef authored by Amith Yamasani's avatar Amith Yamasani Committed by Android (Google) Code Review
Browse files

Merge "Protobufferize DiskStats dumpsys"

parents bae6c26f 38f91ff9
Loading
Loading
Loading
Loading
+94 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

syntax = "proto3";

package android.service.diskstats;

option java_multiple_files = true;
option java_outer_classname = "DiskStatsServiceProto";

message DiskStatsServiceDumpProto {
    enum EncryptionType {
        // Unknown encryption type
        ENCRYPTION_UNKNOWN = 0;
        // No encryption
        ENCRYPTION_NONE = 1;
        // Full disk encryption
        ENCRYPTION_FULL_DISK = 2;
        // File-based encryption
        ENCRYPTION_FILE_BASED = 3;
    }
    // Whether the latency test resulted in an error
    bool has_test_error = 1;
    // If the test errored, error message is contained here
    string error_message = 2;
    // 512B write latency in milliseconds, if the test was successful
    int32 write_512b_latency_millis = 3;
    // Free Space in the major partitions
    repeated DiskStatsFreeSpaceProto partitions_free_space = 4;
    // Is the device using file-based encryption, full disk encryption or other
    EncryptionType encryption = 5;
    // Cached values of folder sizes, etc.
    DiskStatsCachedValuesProto cached_folder_sizes = 6;
}

message DiskStatsCachedValuesProto {
    // Total app data size, in kilobytes
    int64 agg_apps_size = 1;
    // Total app cache size, in kilobytes
    int64 agg_apps_cache_size = 2;
    // Size of image files, in kilobytes
    int64 photos_size = 3;
    // Size of video files, in kilobytes
    int64 videos_size = 4;
    // Size of audio files, in kilobytes
    int64 audio_size = 5;
    // Size of downloads, in kilobytes
    int64 downloads_size = 6;
    // Size of system directory, in kilobytes
    int64 system_size = 7;
    // Size of other files, in kilobytes
    int64 other_size = 8;
    // Sizes of individual packages
    repeated DiskStatsAppSizesProto app_sizes = 9;
}

message DiskStatsAppSizesProto {
    // Name of the package
    string package_name = 1;
    // App's data size in kilobytes
    int64 app_size = 2;
    // App's cache size in kilobytes
    int64 cache_size = 3;
}

message DiskStatsFreeSpaceProto {
    enum Folder {
        // Data folder
        FOLDER_DATA = 0;
        // Cache folder
        FOLDER_CACHE = 1;
        // System folder
        FOLDER_SYSTEM = 2;
    }
    // Which folder?
    Folder folder = 1;
    // Available space, in kilobytes
    int64 available_space = 2;
    // Total space, in kilobytes
    int64 total_space = 3;
}
+138 −23
Original line number Diff line number Diff line
@@ -22,13 +22,20 @@ import android.os.Environment;
import android.os.StatFs;
import android.os.SystemClock;
import android.os.storage.StorageManager;
import android.service.diskstats.DiskStatsAppSizesProto;
import android.service.diskstats.DiskStatsCachedValuesProto;
import android.service.diskstats.DiskStatsFreeSpaceProto;
import android.service.diskstats.DiskStatsServiceDumpProto;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;

import libcore.io.IoUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

@@ -78,6 +85,19 @@ public class DiskStatsService extends Binder {
        long after = SystemClock.uptimeMillis();
        if (tmp.exists()) tmp.delete();

        boolean protoFormat = hasOption(args, "--proto");
        ProtoOutputStream proto = null;

        if (protoFormat) {
            proto = new ProtoOutputStream(fd);
            pw = null;
            proto.write(DiskStatsServiceDumpProto.HAS_TEST_ERROR, error != null);
            if (error != null) {
                proto.write(DiskStatsServiceDumpProto.ERROR_MESSAGE, error.toString());
            } else {
                proto.write(DiskStatsServiceDumpProto.WRITE_512B_LATENCY_MILLIS, after - before);
            }
        } else {
            if (error != null) {
                pw.print("Test-Error: ");
                pw.println(error.toString());
@@ -86,22 +106,47 @@ public class DiskStatsService extends Binder {
                pw.print(after - before);
                pw.println("ms [512B Data Write]");
            }
        }

        reportFreeSpace(Environment.getDataDirectory(), "Data", pw);
        reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
        reportFreeSpace(new File("/system"), "System", pw);
        reportFreeSpace(Environment.getDataDirectory(), "Data", pw, proto,
                DiskStatsFreeSpaceProto.FOLDER_DATA);
        reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw, proto,
                DiskStatsFreeSpaceProto.FOLDER_CACHE);
        reportFreeSpace(new File("/system"), "System", pw, proto,
                DiskStatsFreeSpaceProto.FOLDER_SYSTEM);

        if (StorageManager.isFileEncryptedNativeOnly()) {
        boolean fileBased = StorageManager.isFileEncryptedNativeOnly();
        boolean blockBased = fileBased ? false : StorageManager.isBlockEncrypted();
        if (protoFormat) {
            if (fileBased) {
                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
                        DiskStatsServiceDumpProto.ENCRYPTION_FILE_BASED);
            } else if (blockBased) {
                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
                        DiskStatsServiceDumpProto.ENCRYPTION_FULL_DISK);
            } else {
                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
                        DiskStatsServiceDumpProto.ENCRYPTION_NONE);
            }
        } else if (fileBased) {
            pw.println("File-based Encryption: true");
        }

        if (protoFormat) {
            reportCachedValuesProto(proto);
        } else {
            reportCachedValues(pw);
        }

        if (protoFormat) {
            proto.flush();
        }
        // TODO: Read /proc/yaffs and report interesting values;
        // add configurable (through args) performance test parameters.
    }

    private void reportFreeSpace(File path, String name, PrintWriter pw) {
    private void reportFreeSpace(File path, String name, PrintWriter pw,
            ProtoOutputStream proto, int folderType) {
        try {
            StatFs statfs = new StatFs(path.getPath());
            long bsize = statfs.getBlockSize();
@@ -112,6 +157,13 @@ public class DiskStatsService extends Binder {
                        "Invalid stat: bsize=" + bsize + " avail=" + avail + " total=" + total);
            }

            if (proto != null) {
                long freeSpaceToken = proto.start(DiskStatsServiceDumpProto.PARTITIONS_FREE_SPACE);
                proto.write(DiskStatsFreeSpaceProto.FOLDER, folderType);
                proto.write(DiskStatsFreeSpaceProto.AVAILABLE_SPACE, avail * bsize / 1024);
                proto.write(DiskStatsFreeSpaceProto.TOTAL_SPACE, total * bsize / 1024);
                proto.end(freeSpaceToken);
            } else {
                pw.print(name);
                pw.print("-Free: ");
                pw.print(avail * bsize / 1024);
@@ -120,14 +172,29 @@ public class DiskStatsService extends Binder {
                pw.print("K total = ");
                pw.print(avail * 100 / total);
                pw.println("% free");
            }
        } catch (IllegalArgumentException e) {
            if (proto != null) {
                // Empty proto
            } else {
                pw.print(name);
                pw.print("-Error: ");
                pw.println(e.toString());
            }
            return;
        }
    }

    private boolean hasOption(String[] args, String arg) {
        for (String opt : args) {
            if (arg.equals(opt)) {
                return true;
            }
        }
        return false;
    }

    // If you change this method, make sure to modify the Proto version of this method as well.
    private void reportCachedValues(PrintWriter pw) {
        try {
            String jsonString = IoUtils.readFileAsString(DISKSTATS_DUMP_FILE);
@@ -159,4 +226,52 @@ public class DiskStatsService extends Binder {
        }
    }

    private void reportCachedValuesProto(ProtoOutputStream proto) {
        try {
            String jsonString = IoUtils.readFileAsString(DISKSTATS_DUMP_FILE);
            JSONObject json = new JSONObject(jsonString);
            long cachedValuesToken = proto.start(DiskStatsServiceDumpProto.CACHED_FOLDER_SIZES);

            proto.write(DiskStatsCachedValuesProto.AGG_APPS_SIZE,
                    json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY));
            proto.write(DiskStatsCachedValuesProto.AGG_APPS_CACHE_SIZE,
                    json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY));
            proto.write(DiskStatsCachedValuesProto.PHOTOS_SIZE,
                    json.getLong(DiskStatsFileLogger.PHOTOS_KEY));
            proto.write(DiskStatsCachedValuesProto.VIDEOS_SIZE,
                    json.getLong(DiskStatsFileLogger.VIDEOS_KEY));
            proto.write(DiskStatsCachedValuesProto.AUDIO_SIZE,
                    json.getLong(DiskStatsFileLogger.AUDIO_KEY));
            proto.write(DiskStatsCachedValuesProto.DOWNLOADS_SIZE,
                    json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY));
            proto.write(DiskStatsCachedValuesProto.SYSTEM_SIZE,
                    json.getLong(DiskStatsFileLogger.SYSTEM_KEY));
            proto.write(DiskStatsCachedValuesProto.OTHER_SIZE,
                    json.getLong(DiskStatsFileLogger.MISC_KEY));

            JSONArray packageNamesArray = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
            JSONArray appSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
            JSONArray cacheSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
            final int len = packageNamesArray.length();
            if (len == appSizesArray.length() && len == cacheSizesArray.length()) {
                for (int i = 0; i < len; i++) {
                    long packageToken = proto.start(DiskStatsCachedValuesProto.APP_SIZES);

                    proto.write(DiskStatsAppSizesProto.PACKAGE_NAME,
                            packageNamesArray.getString(i));
                    proto.write(DiskStatsAppSizesProto.APP_SIZE, appSizesArray.getLong(i));
                    proto.write(DiskStatsAppSizesProto.CACHE_SIZE, cacheSizesArray.getLong(i));

                    proto.end(packageToken);
                }
            } else {
                Slog.wtf(TAG, "Sizes of packageNamesArray, appSizesArray and cacheSizesArray "
                        + "are not the same");
            }

            proto.end(cachedValuesToken);
        } catch (IOException | JSONException e) {
            Log.w(TAG, "exception reading diskstats cache file", e);
        }
    }
}