Loading core/proto/android/service/diskstats.proto 0 → 100644 +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; } services/core/java/com/android/server/DiskStatsService.java +138 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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(); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); } } } Loading
core/proto/android/service/diskstats.proto 0 → 100644 +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; }
services/core/java/com/android/server/DiskStatsService.java +138 −23 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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(); Loading @@ -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); Loading @@ -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); Loading Loading @@ -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); } } }