storaged: monitor per-uid IO usage

Add uid_monitor class to query /proc/uid_io/stats periodically.
Add a log tag to record any UID that exceeds IO threshold.

Test: adb shell storaged -u
Bug: 34198239
Change-Id: I53568c30dbefe2f4bdb18054d3dedb30b4133d8b
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 0cb0f5f..9151574 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -105,9 +105,11 @@
 static void help_message(void) {
     printf("usage: storaged [OPTION]\n");
     printf("  -d    --dump                  Dump task I/O usage to stdout\n");
+    printf("  -u    --uid                   Dump uid I/O usage to stdout\n");
     printf("  -s    --start                 Start storaged (default)\n");
     printf("        --emmc=INTERVAL         Set publish interval of emmc lifetime information (in days)\n");
     printf("        --diskstats=INTERVAL    Set publish interval of diskstats (in hours)\n");
+    printf("        --uidio=INTERVAL        Set publish interval of uid io (in hours)\n");
     printf("        --unit=INTERVAL         Set storaged's refresh interval (in seconds)\n");
     fflush(stdout);
 }
@@ -118,10 +120,12 @@
 int main(int argc, char** argv) {
     int flag_main_service = 0;
     int flag_dump_task = 0;
+    int flag_dump_uid = 0;
     int flag_config = 0;
     int unit_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT;
     int diskstats_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH;
     int emmc_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH;
+    int uid_io_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT;
     int fd_emmc = -1;
     int opt;
 
@@ -131,12 +135,14 @@
             {"start",       no_argument,        0, 's'},
             {"kill",        no_argument,        0, 'k'},
             {"dump",        no_argument,        0, 'd'},
+            {"uid",         no_argument,        0, 'u'},
             {"help",        no_argument,        0, 'h'},
             {"unit",        required_argument,  0,  0 },
             {"diskstats",   required_argument,  0,  0 },
-            {"emmc",        required_argument,  0,  0 }
+            {"emmc",        required_argument,  0,  0 },
+            {"uidio",       required_argument,  0,  0 }
         };
-        opt = getopt_long(argc, argv, ":skdh0", long_options, &opt_idx);
+        opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx);
         if (opt == -1) {
             break;
         }
@@ -165,7 +171,15 @@
 
                 } else if (strcmp(long_options[opt_idx].name, "emmc") == 0) {
                     emmc_interval = atoi(optarg) * DAY_TO_SEC;
-                    if (diskstats_interval == 0) {
+                    if (emmc_interval == 0) {
+                        fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n",
+                                long_options[opt_idx].name);
+                        help_message();
+                        return -1;
+                    }
+                } else if (strcmp(long_options[opt_idx].name, "uidio") == 0) {
+                    uid_io_interval = atoi(optarg) * HOUR_TO_SEC;
+                    if (uid_io_interval == 0) {
                         fprintf(stderr, "Invalid argument. Option %s requires an integer argument greater than 0.\n",
                                 long_options[opt_idx].name);
                         help_message();
@@ -187,6 +201,9 @@
         case 'd':
             flag_dump_task = 1;
             break;
+        case 'u':
+            flag_dump_uid = 1;
+            break;
         case 'h':
             help_message();
             return 0;
@@ -230,6 +247,7 @@
             storaged.set_unit_interval(unit_interval);
             storaged.set_diskstats_interval(diskstats_interval);
             storaged.set_emmc_interval(emmc_interval);
+            storaged.set_uid_io_interval(uid_io_interval);
         }
 
         // Start the main thread of storaged
@@ -278,5 +296,24 @@
         return 0;
     }
 
+    if (flag_dump_uid) {
+        sp<IStoraged> storaged_service = get_storaged_service();
+        if (storaged_service == NULL) {
+            fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
+            return -1;
+        }
+        std::vector<struct uid_info> res = storaged_service->dump_uids(NULL);
+
+        if (res.size() == 0) {
+            fprintf(stderr, "UID I/O is not readable in this version of kernel.\n");
+            return 0;
+        }
+
+        sort_running_uids_info(res);
+        log_console_running_uids_info(res);
+
+        return 0;
+    }
+
     return 0;
 }