Revert "Revert "DiskStats Westworld Migration""

This reverts commit 6188aa32946f6372f912ccc9281956ca38a8a264.

Reason for revert: ag/4819964 has now been submitted. undoing the roll back.
Test: revert
Test: manually verified output is the same as diskstats.

Change-Id: I9a3292f66e1e28661e1d29f3befd002073b681c1
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2ecfbe7..27b4442 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -153,13 +153,17 @@
         SystemUptime system_uptime = 10015;
         CpuActiveTime cpu_active_time = 10016;
         CpuClusterTime cpu_cluster_time = 10017;
-        DiskSpace disk_space = 10018;
+        DiskSpace disk_space = 10018 [deprecated=true];
         RemainingBatteryCapacity remaining_battery_capacity = 10019;
         FullBatteryCapacity full_battery_capacity = 10020;
         Temperature temperature = 10021;
         BinderCalls binder_calls = 10022;
         BinderCallsExceptions binder_calls_exceptions = 10023;
         LooperStats looper_stats = 10024;
+        DiskStats disk_stats = 10025;
+        DirectoryUsage directory_usage = 10026;
+        AppSize app_size = 10027;
+        CategorySize category_size = 10028;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
@@ -2251,3 +2255,82 @@
     // recorded_total_cpu_micros / recorded_message_count * call_count.
     optional int64 recorded_total_cpu_micros = 9;
 }
+
+/**
+ * Pulls disk information, such as write speed and latency.
+ */
+message DiskStats {
+    // Time taken to open, write 512B to, and close a file.
+    // -1 if error performing the check.
+    optional int64 data_write_latency_millis = 1;
+
+    optional bool file_based_encryption = 2;
+
+    // Recent disk write speed in kB/s.
+    // -1 if error querying storageed.
+    // 0 if data is unavailable.
+    optional int32 recent_disk_write_speed = 3;
+}
+
+
+/**
+ * Free and total bytes of the Data, Cache, and System partition.
+ */
+message DirectoryUsage {
+    enum Directory {
+        UNKNOWN = 0;
+        DATA = 1;
+        CACHE = 2;
+        SYSTEM = 3;
+    }
+    optional Directory directory = 1;
+    optional int64 free_bytes = 2;
+    optional int64 total_bytes = 3;
+}
+
+
+/**
+ * Size of an application: apk size, data size, and cache size.
+ * Reads from a cached file produced daily by DiskStatsLoggingService.java.
+ * Information is only reported for apps with the primary user (user 0).
+ * Sizes are aggregated by package name.
+ */
+message AppSize {
+    // Including uids will involve modifying diskstats logic.
+    optional string package_name = 1;
+    // App size in bytes. -1 if unavailable.
+    optional int64 app_size_bytes = 2;
+    // App data size in bytes. -1 if unavailable.
+    optional int64 app_data_size_bytes = 3;
+    // App cache size in bytes. -1 if unavailable.
+    optional int64 app_cache_size_bytes = 4;
+    // Time that the cache file was produced.
+    // Uses System.currentTimeMillis(), which is wall clock time.
+    optional int64 cache_time_millis = 5;
+}
+
+
+/**
+ * Size of a particular category. Eg: photos, videos.
+ * Reads from a cached file produced daily by DiskStatsLoggingService.java.
+ */
+message CategorySize {
+    enum Category {
+        UNKNOWN = 0;
+        APP_SIZE = 1;
+        APP_DATA_SIZE = 2;
+        APP_CACHE_SIZE = 3;
+        PHOTOS = 4;
+        VIDEOS = 5;
+        AUDIO = 6;
+        DOWNLOADS = 7;
+        SYSTEM = 8;
+        OTHER = 9;
+    }
+    optional Category category = 1;
+    // Category size in bytes.
+    optional int64 size_bytes = 2;
+    // Time that the cache file was produced.
+    // Uses System.currentTimeMillis(), which is wall clock time.
+    optional int64 cache_time_millis = 3;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 2871882..dbc13dc 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -149,9 +149,6 @@
         // system_uptime
         {android::util::SYSTEM_UPTIME,
          {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
-        // disk_space
-        {android::util::DISK_SPACE,
-         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
         // remaining_battery_capacity
         {android::util::REMAINING_BATTERY_CAPACITY,
          {{},
@@ -189,7 +186,31 @@
          {{5, 6, 7, 8, 9},
           {2, 3, 4},
           1 * NS_PER_SEC,
-          new StatsCompanionServicePuller(android::util::LOOPER_STATS)}}
+          new StatsCompanionServicePuller(android::util::LOOPER_STATS)}},
+        // Disk Stats
+        {android::util::DISK_STATS,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::DISK_STATS)}},
+        // Directory usage
+        {android::util::DIRECTORY_USAGE,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}},
+        // Size of app's code, data, and cache
+        {android::util::APP_SIZE,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::APP_SIZE)}},
+        // Size of specific categories of files. Eg. Music.
+        {android::util::CATEGORY_SIZE,
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
         };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index 7b3ea57..b13bcac 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -127,6 +127,15 @@
     }
 
     /**
+     * Adds a boolean by adding either a 1 or 0 to the output.
+     */
+    public void writeBoolean(boolean val) {
+        int toWrite = val ? 1 : 0;
+        mStorage.write(EVENT_TYPE_INT);
+        write4Bytes(toWrite);
+    }
+
+    /**
      * Writes the stored fields to a byte array. Will first write a new-line character to denote
      * END_LIST before writing contents to byte array.
      */
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index b922e40a..6f9d803 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,6 +43,7 @@
 import android.os.IBinder;
 import android.os.IStatsCompanionService;
 import android.os.IStatsManager;
+import android.os.IStoraged;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
@@ -54,6 +55,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -76,9 +78,19 @@
 import com.android.server.BinderCallsStatsService;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+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;
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -861,14 +873,6 @@
         pulledData.add(e);
     }
 
-    private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) {
-        StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 3);
-        e.writeLong(mStatFsData.getAvailableBytes());
-        e.writeLong(mStatFsSystem.getAvailableBytes());
-        e.writeLong(mStatFsTemp.getAvailableBytes());
-        pulledData.add(e);
-    }
-
     private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) {
         StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1);
         e.writeLong(SystemClock.uptimeMillis());
@@ -962,6 +966,183 @@
         }
     }
 
+    private void pullDiskStats(int tagId, List<StatsLogEventWrapper> pulledData) {
+        // Run a quick-and-dirty performance test: write 512 bytes
+        byte[] junk = new byte[512];
+        for (int i = 0; i < junk.length; i++) junk[i] = (byte) i;  // Write nonzero bytes
+
+        File tmp = new File(Environment.getDataDirectory(), "system/statsdperftest.tmp");
+        FileOutputStream fos = null;
+        IOException error = null;
+
+        long before = SystemClock.elapsedRealtime();
+        try {
+            fos = new FileOutputStream(tmp);
+            fos.write(junk);
+        } catch (IOException e) {
+            error = e;
+        } finally {
+            try {
+                if (fos != null) fos.close();
+            } catch (IOException e) {
+                // Do nothing.
+            }
+        }
+
+        long latency = SystemClock.elapsedRealtime() - before;
+        if (tmp.exists()) tmp.delete();
+
+        if (error != null) {
+            Slog.e(TAG, "Error performing diskstats latency test");
+            latency = -1;
+        }
+        // File based encryption.
+        boolean fileBased = StorageManager.isFileEncryptedNativeOnly();
+
+        //Recent disk write speed. Binder call to storaged.
+        int writeSpeed = -1;
+        try {
+            IBinder binder = ServiceManager.getService("storaged");
+            if (binder == null) {
+                Slog.e(TAG, "storaged not found");
+            }
+            IStoraged storaged = IStoraged.Stub.asInterface(binder);
+            writeSpeed = storaged.getRecentPerf();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "storaged not found");
+        }
+
+        // Add info pulledData.
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e.writeLong(latency);
+        e.writeBoolean(fileBased);
+        e.writeInt(writeSpeed);
+        pulledData.add(e);
+    }
+
+    private void pullDirectoryUsage(int tagId, List<StatsLogEventWrapper> pulledData) {
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
+        StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
+        StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
+
+        StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__DATA);
+        e.writeLong(statFsData.getAvailableBytes());
+        e.writeLong(statFsData.getTotalBytes());
+        pulledData.add(e);
+
+        e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE);
+        e.writeLong(statFsCache.getAvailableBytes());
+        e.writeLong(statFsCache.getTotalBytes());
+        pulledData.add(e);
+
+        e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+        e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM);
+        e.writeLong(statFsSystem.getAvailableBytes());
+        e.writeLong(statFsSystem.getTotalBytes());
+        pulledData.add(e);
+    }
+
+    private void pullAppSize(int tagId, List<StatsLogEventWrapper> pulledData) {
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        try {
+            String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
+            JSONObject json = new JSONObject(jsonStr);
+            long cache_time = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L);
+            JSONArray pkg_names = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
+            JSONArray app_sizes = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
+            JSONArray app_data_sizes = json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY);
+            JSONArray app_cache_sizes = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
+            // Sanity check: Ensure all 4 lists have the same length.
+            int length = pkg_names.length();
+            if (app_sizes.length() != length || app_data_sizes.length() != length
+                    || app_cache_sizes.length() != length) {
+                Slog.e(TAG, "formatting error in diskstats cache file!");
+                return;
+            }
+            for (int i = 0; i < length; i++) {
+                StatsLogEventWrapper e =
+                        new StatsLogEventWrapper(elapsedNanos, tagId, 5 /* fields */);
+                e.writeString(pkg_names.getString(i));
+                e.writeLong(app_sizes.optLong(i, -1L));
+                e.writeLong(app_data_sizes.optLong(i, -1L));
+                e.writeLong(app_cache_sizes.optLong(i, -1L));
+                e.writeLong(cache_time);
+                pulledData.add(e);
+            }
+        } catch (IOException | JSONException e) {
+            Slog.e(TAG, "exception reading diskstats cache file", e);
+        }
+    }
+
+    private void pullCategorySize(int tagId, List<StatsLogEventWrapper> pulledData) {
+        long elapsedNanos = SystemClock.elapsedRealtimeNanos();
+        try {
+            String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
+            JSONObject json = new JSONObject(jsonStr);
+            long cacheTime = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L);
+
+            StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE);
+            e.writeLong(json.optLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE);
+            e.writeLong(json.optLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE);
+            e.writeLong(json.optLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS);
+            e.writeLong(json.optLong(DiskStatsFileLogger.PHOTOS_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS);
+            e.writeLong(json.optLong(DiskStatsFileLogger.VIDEOS_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__AUDIO);
+            e.writeLong(json.optLong(DiskStatsFileLogger.AUDIO_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS);
+            e.writeLong(json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM);
+            e.writeLong(json.optLong(DiskStatsFileLogger.SYSTEM_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+
+            e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */);
+            e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__OTHER);
+            e.writeLong(json.optLong(DiskStatsFileLogger.MISC_KEY, -1L));
+            e.writeLong(cacheTime);
+            pulledData.add(e);
+        } catch (IOException | JSONException e) {
+            Slog.e(TAG, "exception reading diskstats cache file", e);
+        }
+    }
+
     /**
      * Pulls various data.
      */
@@ -1036,10 +1217,6 @@
                 pullSystemElapsedRealtime(tagId, ret);
                 break;
             }
-            case StatsLog.DISK_SPACE: {
-                pullDiskSpace(tagId, ret);
-                break;
-            }
             case StatsLog.PROCESS_MEMORY_STATE: {
                 pullProcessMemoryState(tagId, ret);
                 break;
@@ -1056,6 +1233,22 @@
                 pullLooperStats(tagId, ret);
                 break;
             }
+            case StatsLog.DISK_STATS: {
+                pullDiskStats(tagId, ret);
+                break;
+            }
+            case StatsLog.DIRECTORY_USAGE: {
+                pullDirectoryUsage(tagId, ret);
+                break;
+            }
+            case StatsLog.APP_SIZE: {
+                pullAppSize(tagId, ret);
+                break;
+            }
+            case StatsLog.CATEGORY_SIZE: {
+                pullCategorySize(tagId, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;