storaged: fix divide-by-zero when updating history

Bug: 75984894
Test: storaged unit tests on x86/64 platforms
Change-Id: I8c491f70705c662d40d0b212bcbc43a0de279bec
Merged-In: I8c491f70705c662d40d0b212bcbc43a0de279bec
(cherry picked from commit f2dd78bb2c9fe0e6482cf012e26664752fc64401)
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index 88a53de..9c3d0e7 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -38,6 +38,7 @@
 class storage_info_t {
   protected:
     FRIEND_TEST(storaged_test, storage_info_t);
+    FRIEND_TEST(storaged_test, storage_info_t_proto);
     // emmc lifetime
     uint16_t eol;                   // pre-eol (end of life) information
     uint16_t lifetime_a;            // device life time estimation (type A)
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 055f375..5605f66 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -157,11 +157,14 @@
         return;
     }
 
-    recent_perf.erase(recent_perf.begin() + nr_samples,
-                      recent_perf.end());
+    if (nr_samples < recent_perf.size()) {
+        recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
+    }
 
-    uint32_t daily_avg_bw = accumulate(recent_perf.begin(),
-        recent_perf.begin() + nr_samples, 0) / nr_samples;
+    uint32_t daily_avg_bw = 0;
+    if (!recent_perf.empty()) {
+        daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size();
+    }
 
     day_start_tp = tp - chrono::seconds(duration_cast<chrono::seconds>(
         tp.time_since_epoch()).count() % DAY_TO_SEC);
@@ -176,6 +179,7 @@
         return;
     }
 
+    DCHECK(nr_days > 0);
     uint32_t week_avg_bw = accumulate(daily_perf.begin(),
         daily_perf.begin() + nr_days, 0) / nr_days;
 
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index d1fa9ed..ec47b65 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -416,6 +416,31 @@
     }
 }
 
+TEST(storaged_test, storage_info_t_proto) {
+    storage_info_t si;
+    si.day_start_tp = {};
+
+    IOPerfHistory proto;
+    proto.set_nr_samples(10);
+    proto.set_day_start_sec(0);
+    si.load_perf_history_proto(proto);
+
+    // Skip ahead > 1 day, with no data points in the previous day.
+    time_point<system_clock> stp;
+    stp += hours(36);
+    si.update_perf_history(100, stp);
+
+    vector<int> history = si.get_perf_history();
+    EXPECT_EQ(history.size(), 63UL);
+    EXPECT_EQ(history[0], 1);
+    EXPECT_EQ(history[1], 7);
+    EXPECT_EQ(history[2], 52);
+    EXPECT_EQ(history[3], 100);
+    for (size_t i = 4; i < history.size(); i++) {
+        EXPECT_EQ(history[i], 0);
+    }
+}
+
 TEST(storaged_test, uid_monitor) {
     uid_monitor uidm;