storaged: add --hours flag for dumpsys

1. Add a flag to report IO usage for last N hours.
2. Change interval back to 1 hour so that we have finer usage data.
3. Don't clear events after dumpsys call. Use a max buffer limit.
4. Clear old events if they're more than 5 days old or when no room
for new events.
5. Skip uids with no IO usage to save space.
6. Replace interval with a timestamp in event entry.

Test: adb shell dumpsys storaged --hours 2
Bug: 34198239
Bug: 33086174
Change-Id: I66e8fb6ec155584115fab817c3ed2c78e637ac40
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 5f664e4..93c9df4 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -101,25 +101,48 @@
     return uids;
 }
 
-static const int MAX_UID_EVENTS = 1000;
+static const int MAX_UID_EVENTS_SIZE = 1000 * 48; // 1000 uids in 48 hours
 
-void uid_monitor::add_event(const struct uid_event& event)
+void uid_monitor::add_events(const std::vector<struct uid_event>& new_events,
+                             uint64_t curr_ts)
 {
     std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
 
-    if (events.size() > MAX_UID_EVENTS) {
-        LOG_TO(SYSTEM, ERROR) << "event buffer full";
-        return;
-    }
-    events.push_back(event);
+    // remove events more than 5 days old
+    struct uid_event first_event;
+    first_event.ts = curr_ts / SEC_TO_USEC - 5 * DAY_TO_SEC;
+    auto it = std::upper_bound(events.begin(), events.end(), first_event);
+    events.erase(events.begin(), it);
+
+    // make some room for new events
+    int overflow = events.size() + new_events.size() - MAX_UID_EVENTS_SIZE;
+    if (overflow > 0)
+        events.erase(events.begin(), events.begin() + overflow);
+
+    events.insert(events.end(), new_events.begin(), new_events.end());
 }
 
-std::vector<struct uid_event> uid_monitor::dump_events()
+std::vector<struct uid_event> uid_monitor::dump_events(int hours)
 {
     std::unique_ptr<lock_t> lock(new lock_t(&events_lock));
-    std::vector<struct uid_event> dump_events = events;
+    std::vector<struct uid_event> dump_events;
+    struct timespec ts;
 
-    events.clear();
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        return dump_events;
+    }
+
+    struct uid_event first_event;
+    if (hours == 0) {
+        first_event.ts = 0; // dump all events
+    } else {
+        first_event.ts = ts.tv_sec - (uint64_t)hours * HOUR_TO_SEC;
+    }
+    auto it = std::upper_bound(events.begin(), events.end(), first_event);
+
+    dump_events.assign(it, events.end());
+
     return dump_events;
 }
 
@@ -143,10 +166,12 @@
         return;
     }
 
+    std::vector<struct uid_event> new_events;
     for (const auto& it : uids) {
         const struct uid_info& uid = it.second;
         struct uid_event event;
 
+        event.ts = ts.tv_sec;
         event.name = uid.name;
         event.fg_read_bytes = uid.io[UID_FOREGROUND].read_bytes -
             last_uids[uid.uid].io[UID_FOREGROUND].read_bytes;;
@@ -156,11 +181,16 @@
             last_uids[uid.uid].io[UID_BACKGROUND].read_bytes;;
         event.bg_write_bytes = uid.io[UID_BACKGROUND].write_bytes -
             last_uids[uid.uid].io[UID_BACKGROUND].write_bytes;;
-        event.interval = uint64_t(ts_delta / NS_PER_SEC);
 
-        add_event(event);
+        if (event.fg_read_bytes + event.fg_write_bytes +
+            event.bg_read_bytes + event.bg_write_bytes == 0) {
+            continue;
+        }
+
+        new_events.push_back(event);
     }
 
+    add_events(new_events, curr_ts);
     set_last_uids(std::move(uids), curr_ts);
 }