Bug fix of bandwidth estimation

Bug fix of bandwidth estimation metrics: report AvgBandwidthKbps in wifi metrics based on the daily stats instead of the device historical average. That's because avgBandwidthKbps and count are meant to be daily stats which will be aggregated in the pipeline. Reporting the device historical average will result in over-counting of some stats.

In addition, the memory store of some devices may already have invalid values due to the early potential overflow bug. Reset them if invalid values are detected.

Bug: 189939948
Test: run mixed traffic for 30 mins and check reported BW
Test: atest com.android.server.wifi
Change-Id: I12794b17a80977a0982555da4388dbc19b5c29e6
diff --git a/service/java/com/android/server/wifi/WifiScoreCard.java b/service/java/com/android/server/wifi/WifiScoreCard.java
index 2da125e..ad6fb8a 100644
--- a/service/java/com/android/server/wifi/WifiScoreCard.java
+++ b/service/java/com/android/server/wifi/WifiScoreCard.java
@@ -134,8 +134,8 @@
             new long[NUM_LINK_BAND][NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
     private final long[][][] mBwEstErrorAccPercent =
             new long[NUM_LINK_BAND][NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
-    private final int[][][] mBwEstValue =
-            new int[NUM_LINK_BAND][NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
+    private final long[][][] mBwEstValue =
+            new long[NUM_LINK_BAND][NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
     private final int[][][] mBwEstCount =
             new int[NUM_LINK_BAND][NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL];
 
@@ -1373,6 +1373,7 @@
 
         private void updateBandwidthSample(long bytesDelta, int link, int onTimeMs,
                 int maxSupportedLinkSpeedMbps) {
+            checkAndPossiblyResetBandwidthStats(link, maxSupportedLinkSpeedMbps);
             if (bytesDelta < mByteDeltaAccThr[link]) {
                 return;
             }
@@ -1396,6 +1397,26 @@
             }
         }
 
+        private void checkAndPossiblyResetBandwidthStats(int link, int maxSupportedLinkSpeedMbps) {
+            if (getAvgUsedLinkBandwidthKbps(link) > (maxSupportedLinkSpeedMbps * 1000)) {
+                resetBandwidthStats(link);
+            }
+        }
+
+        private void resetBandwidthStats(int link) {
+            changed = true;
+            // Reset SSID level stats
+            mBandwidthStatsValue[mBandIdx][link][mSignalLevel] = 0;
+            mBandwidthStatsCount[mBandIdx][link][mSignalLevel] = 0;
+            // Reset BSSID level stats
+            PerBssid perBssid = lookupBssid(ssid, mBssid);
+            if (perBssid != mPlaceholderPerBssid) {
+                perBssid.changed = true;
+                perBssid.bandwidthStatsValue[mBandIdx][link][mSignalLevel] = 0;
+                perBssid.bandwidthStatsCount[mBandIdx][link][mSignalLevel] = 0;
+            }
+        }
+
         private int getByteDeltaAccThr(int link) {
             int maxTimeDeltaMs = mContext.getResources().getInteger(
                     R.integer.config_wifiPollRssiIntervalMilliseconds);
@@ -1563,7 +1584,7 @@
             int l2ErrPercent = calculateErrorPercent(l2Kbps, bwSampleKbps);
             mBwEstErrorAccPercent[mBandIdx][link][mSignalLevel] += Math.abs(bwEstExtErrPercent);
             mL2ErrorAccPercent[mBandIdx][link][mSignalLevel] += Math.abs(l2ErrPercent);
-            mBwEstValue[mBandIdx][link][mSignalLevel] = mAvgUsedKbps[link];
+            mBwEstValue[mBandIdx][link][mSignalLevel] += bwSampleKbps;
             mBwEstCount[mBandIdx][link][mSignalLevel]++;
             StringBuilder sb = new StringBuilder();
             logv(sb.append(link)
@@ -2613,10 +2634,10 @@
         BandwidthEstimatorStats.PerLevel stats = new BandwidthEstimatorStats.PerLevel();
         stats.signalLevel = level;
         stats.count = count;
-        stats.avgBandwidthKbps = mBwEstValue[bandIdx][linkIdx][level];
-        stats.l2ErrorPercent = calculateAvgError(
+        stats.avgBandwidthKbps = calculateAvg(mBwEstValue[bandIdx][linkIdx][level], count);
+        stats.l2ErrorPercent = calculateAvg(
                 mL2ErrorAccPercent[bandIdx][linkIdx][level], count);
-        stats.bandwidthEstErrorPercent = calculateAvgError(
+        stats.bandwidthEstErrorPercent = calculateAvg(
                 mBwEstErrorAccPercent[bandIdx][linkIdx][level], count);
 
         // reset counters for next run
@@ -2627,8 +2648,8 @@
         return stats;
     }
 
-    private int calculateAvgError(long errorAccPercent, int count) {
-        return (count > 0) ? (int) (errorAccPercent / count) : 0;
+    private int calculateAvg(long acc, int count) {
+        return (count > 0) ? (int) (acc / count) : 0;
     }
 
     /**
@@ -2654,7 +2675,7 @@
                 pw.println(" Count");
                 printValues(mBwEstCount[i][j], pw);
                 pw.println(" AvgKbps");
-                printValues(mBwEstValue[i][j], pw);
+                printAvgStats(mBwEstValue[i][j], mBwEstCount[i][j], pw);
                 pw.println(" BwEst error");
                 printAvgStats(mBwEstErrorAccPercent[i][j], mBwEstCount[i][j], pw);
                 pw.println(" L2 error");
@@ -2675,7 +2696,7 @@
     private void printAvgStats(long[] stats, int[] count, PrintWriter pw) {
         StringBuilder sb = new StringBuilder();
         for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
-            sb.append(" " + calculateAvgError(stats[k], count[k]));
+            sb.append(" " + calculateAvg(stats[k], count[k]));
         }
         pw.println(sb.toString());
     }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
index 3cf091a..20fb0b9 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreCardTest.java
@@ -1773,7 +1773,6 @@
         assertEquals(0, stats.statsAbove2G.rx.level.length);
     }
 
-
     @Test
     public void testLinkBandwidthLargeByteCountReturnNonNegativeValue() {
         mWifiInfo.setRssi(-70);
@@ -1818,6 +1817,48 @@
         assertEquals(0, stats.stats2G.tx.level.length);
         assertEquals(1, stats.stats2G.rx.level.length);
         assertEquals(128_000_000, stats.stats2G.rx.level[0].avgBandwidthKbps);
+        assertEquals(1, stats.stats2G.rx.level[0].count);
+
+        mNewLlStats.on_time = 2000;
+        for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
+            addTotalBytes(txBytes, rxBytes);
+            millisecondsPass(3_000);
+            perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo);
+            perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
+        }
+        stats = mWifiScoreCard.dumpBandwidthEstimatorStats();
+        assertEquals(64_000_000, stats.stats2G.rx.level[0].avgBandwidthKbps);
+        assertEquals(BANDWIDTH_STATS_COUNT_THR + 2, stats.stats2G.rx.level[0].count);
+    }
+
+    @Test
+    public void testLinkBandwidthResetInvalidStats() {
+        mWifiInfo.setRssi(-70);
+        mWifiInfo.setMaxSupportedRxLinkSpeedMbps(200_000);
+        mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
+        PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
+        mWifiScoreCard.noteIpConfiguration(mWifiInfo);
+        mOldLlStats.timeStampInMs = 7_000;
+        mNewLlStats.timeStampInMs = 10_000;
+        long txBytes = 8_000_000_000L;
+        long rxBytes = 16_000_000_000L;
+        mWifiInfo.setFrequency(2412);
+        mNewLlStats.on_time = 1000;
+        for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
+            addTotalBytes(txBytes, rxBytes);
+            millisecondsPass(3_000);
+            perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo);
+        }
+        assertEquals(128_000_000, perNetwork.getRxLinkBandwidthKbps());
+        // Reduce max supported Rx link speed so that stats in the memory become invalid
+        // and fall back to cold start values
+        mWifiInfo.setMaxSupportedRxLinkSpeedMbps(100);
+        for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
+            addTotalBytes(txBytes, rxBytes);
+            millisecondsPass(3_000);
+            perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo);
+        }
+        assertEquals(10_070, perNetwork.getRxLinkBandwidthKbps());
     }
 
     @Test