storaged: replace cmd arguments with properties

Add properties to control event intervals.
Add a property to check time spent in event loop.

Bug: 34612341
Bug: 34198239
Change-Id: I01f64c84e17153377ece7ae530be106e3f55287e
diff --git a/storaged/README.properties b/storaged/README.properties
new file mode 100644
index 0000000..70e6026
--- /dev/null
+++ b/storaged/README.properties
@@ -0,0 +1,6 @@
+ro.storaged.event.interval    # interval storaged scans for IO stats, in seconds
+ro.storaged.event.perf_check  # check for time spent in event loop, in microseconds
+ro.storaged.disk_stats_pub    # interval storaged publish disk stats, in seconds
+ro.storaged.emmc_info_pub     # interval storaged publish emmc info, in seconds
+ro.storaged.uid_io.interval   # interval storaged checks Per UID IO usage, in seconds
+ro.storaged.uid_io.threshold  # Per UID IO usage limit, in bytes
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index 7fa9958..d3e6b71 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -40,6 +40,12 @@
 #define debuginfo(...)
 #endif
 
+#define SECTOR_SIZE ( 512 )
+#define SEC_TO_MSEC ( 1000 )
+#define MSEC_TO_USEC ( 1000 )
+#define USEC_TO_NSEC ( 1000 )
+#define SEC_TO_USEC ( 1000000 )
+
 // number of attributes diskstats has
 #define DISK_STATS_SIZE ( 11 )
 // maximum size limit of a stats file
@@ -266,7 +272,10 @@
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
 #define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 )
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT ( 3600 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
+
+// UID IO threshold in bytes
+#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
 
 struct storaged_config {
     int periodic_chores_interval_unit;
@@ -277,6 +286,7 @@
     bool proc_uid_io_available;      // whether uid_io is accessible
     bool emmc_available;        // whether eMMC est_csd file is readable
     bool diskstats_available;   // whether diskstats is accessible
+    int event_time_check_usec;  // check how much cputime spent in event loop
 };
 
 class storaged_t {
@@ -293,21 +303,10 @@
     storaged_t(void);
     ~storaged_t() {}
     void event(void);
+    void event_checked(void);
     void pause(void) {
         sleep(mConfig.periodic_chores_interval_unit);
     }
-    void set_unit_interval(int unit) {
-        mConfig.periodic_chores_interval_unit = unit;
-    }
-    void set_diskstats_interval(int disk_stats) {
-        mConfig.periodic_chores_interval_disk_stats_publish = disk_stats;
-    }
-    void set_emmc_interval(int emmc_info) {
-        mConfig.periodic_chores_interval_emmc_info_publish = emmc_info;
-    }
-    void set_uid_io_interval(int uid_io) {
-        mUidm.set_periodic_chores_interval(uid_io);
-    }
     std::vector<struct task_info> get_tasks(void) {
         // There could be a race when get_tasks() and the main thread is updating at the same time
         // While update_running_tasks() is updating the critical sections at the end of the function
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
index eceb7fd..9f95c51 100644
--- a/storaged/include/storaged_uid_monitor.h
+++ b/storaged/include/storaged_uid_monitor.h
@@ -46,11 +46,12 @@
 private:
     std::unordered_map<uint32_t, struct uid_info> last_uids;
     void set_last_uids(std::unordered_map<uint32_t, struct uid_info>&& uids, uint64_t ts);
-    int interval; // monitor interval in seconds
+    int interval;  // monitor interval in seconds
+    int threshold; // monitor threshold in bytes
     uint64_t last_report_ts; // timestamp of last report in nsec
 public:
     uid_monitor();
-    void set_periodic_chores_interval(int t) { interval = t; }
+    void set_periodic_chores_params(int intvl, int thold) { interval = intvl; threshold = thold; }
     int get_periodic_chores_interval() { return interval; }
     std::unordered_map<uint32_t, struct uid_info> get_uids();
     void report();
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 9151574..c7f3dff 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -96,7 +96,7 @@
     LOG_TO(SYSTEM, INFO) << "storaged: Start";
 
     for (;;) {
-        storaged->event();
+        storaged->event_checked();
         storaged->pause();
     }
     return NULL;
@@ -107,10 +107,6 @@
     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);
 }
 
@@ -121,11 +117,6 @@
     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;
 
@@ -136,11 +127,7 @@
             {"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 },
-            {"uidio",       required_argument,  0,  0 }
+            {"help",        no_argument,        0, 'h'}
         };
         opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx);
         if (opt == -1) {
@@ -148,53 +135,6 @@
         }
 
         switch (opt) {
-        case 0:
-            printf("option %s", long_options[opt_idx].name);
-            if (optarg) {
-                printf(" with arg %s", optarg);
-                if (strcmp(long_options[opt_idx].name, "unit") == 0) {
-                    unit_interval = atoi(optarg);
-                    if (unit_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, "diskstats") == 0) {
-                    diskstats_interval = atoi(optarg) * HOUR_TO_SEC;
-                    if (diskstats_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, "emmc") == 0) {
-                    emmc_interval = atoi(optarg) * DAY_TO_SEC;
-                    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();
-                        return -1;
-                    }
-                }
-                flag_config = 1;
-            } else {
-                fprintf(stderr, "Invalid argument. Option %s requires an argument.\n",
-                        long_options[opt_idx].name);
-                help_message();
-                return -1;
-            }
-            printf("\n");
-            break;
         case 's':
             flag_main_service = 1;
             break;
@@ -225,12 +165,6 @@
         return -1;
     }
 
-    if (flag_config && flag_dump_task) {
-        fprintf(stderr, "Invalid arguments. Cannot set configs in \'dump\' option.\n");
-        help_message();
-        return -1;
-    }
-
     if (flag_main_service) { // start main thread
         static const char mmc0_ext_csd[] = "/d/mmc0/mmc0:0001/ext_csd";
         fd_emmc = android_get_control_file(mmc0_ext_csd);
@@ -243,13 +177,6 @@
 
         storaged.set_privileged_fds(fd_emmc);
 
-        if (flag_config) {
-            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
         pthread_t storaged_main_thread;
         errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged);
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 0c53f44..1950c21 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <android-base/logging.h>
+#include <cutils/properties.h>
 
 #include <storaged.h>
 #include <storaged_utils.h>
@@ -176,10 +177,21 @@
 
     mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0);
 
-    mConfig.periodic_chores_interval_unit = DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT;
-    mConfig.periodic_chores_interval_disk_stats_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH;
-    mConfig.periodic_chores_interval_emmc_info_publish = DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH;
-    mUidm.set_periodic_chores_interval(DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_ALERT);
+    mConfig.periodic_chores_interval_unit =
+        property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
+
+    mConfig.event_time_check_usec =
+        property_get_int32("ro.storaged.event.perf_check", 0);
+
+    mConfig.periodic_chores_interval_disk_stats_publish =
+        property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
+
+    mConfig.periodic_chores_interval_emmc_info_publish =
+        property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH);
+
+    mUidm.set_periodic_chores_params(
+        property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO),
+        property_get_int32("ro.storaged.uid_io.threshold", DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD));
 
     mStarttime = time(NULL);
 }
@@ -212,3 +224,30 @@
 
     mTimer += mConfig.periodic_chores_interval_unit;
 }
+
+void storaged_t::event_checked(void) {
+    struct timespec start_ts, end_ts;
+    bool check_time = true;
+
+    if (mConfig.event_time_check_usec &&
+        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
+        check_time = false;
+        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+    }
+
+    event();
+
+    if (mConfig.event_time_check_usec) {
+        if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
+            PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+            return;
+        }
+        int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
+                       (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
+        if (cost > mConfig.event_time_check_usec) {
+            LOG_TO(SYSTEM, ERROR)
+                << "event loop spent " << cost << " usec, threshold "
+                << mConfig.event_time_check_usec << " usec";
+        }
+    }
+}
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 4105dae..2a84a0c 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -33,8 +33,6 @@
 #include "storaged.h"
 #include "storaged_uid_monitor.h"
 
-static const uint64_t io_alert_threshold = 1024 * 1024 * 1024; // 1GB
-
 using namespace android;
 using namespace android::base;
 
@@ -116,7 +114,7 @@
 
     uint64_t curr_ts = ts.tv_sec * NS_PER_SEC + ts.tv_nsec;
     uint64_t ts_delta = curr_ts - last_report_ts;
-    uint64_t adjusted_threshold = io_alert_threshold * ((double)ts_delta / interval / NS_PER_SEC);
+    uint64_t adjusted_threshold = threshold * ((double)ts_delta / interval / NS_PER_SEC);
 
     std::unordered_map<uint32_t, struct uid_info> uids = get_uids();
     if (uids.empty()) {
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
index 6e4ddb6..1dcd0ff 100644
--- a/storaged/storaged_utils.cpp
+++ b/storaged/storaged_utils.cpp
@@ -41,11 +41,6 @@
 #include <storaged.h>
 #include <storaged_utils.h>
 
-#define SECTOR_SIZE ( 512 )
-#define SEC_TO_MSEC ( 1000 )
-#define MSEC_TO_USEC ( 1000 )
-#define USEC_TO_NSEC ( 1000 )
-
 bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
     // Get time
     struct timespec ts;