• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static com.android.server.wifi.DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT;
20 import static com.android.server.wifi.WifiHealthMonitor.REASON_ASSOC_REJECTION;
21 import static com.android.server.wifi.WifiHealthMonitor.REASON_ASSOC_TIMEOUT;
22 import static com.android.server.wifi.WifiHealthMonitor.REASON_AUTH_FAILURE;
23 import static com.android.server.wifi.WifiHealthMonitor.REASON_CONNECTION_FAILURE;
24 import static com.android.server.wifi.WifiHealthMonitor.REASON_DISCONNECTION_NONLOCAL;
25 import static com.android.server.wifi.WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL;
26 import static com.android.server.wifi.WifiScoreCard.BANDWIDTH_STATS_COUNT_THR;
27 import static com.android.server.wifi.WifiScoreCard.CNT_ASSOCIATION_REJECTION;
28 import static com.android.server.wifi.WifiScoreCard.CNT_ASSOCIATION_TIMEOUT;
29 import static com.android.server.wifi.WifiScoreCard.CNT_AUTHENTICATION_FAILURE;
30 import static com.android.server.wifi.WifiScoreCard.CNT_CONNECTION_ATTEMPT;
31 import static com.android.server.wifi.WifiScoreCard.CNT_CONNECTION_DURATION_SEC;
32 import static com.android.server.wifi.WifiScoreCard.CNT_CONNECTION_FAILURE;
33 import static com.android.server.wifi.WifiScoreCard.CNT_CONSECUTIVE_CONNECTION_FAILURE;
34 import static com.android.server.wifi.WifiScoreCard.CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE;
35 import static com.android.server.wifi.WifiScoreCard.CNT_DISCONNECTION_NONLOCAL;
36 import static com.android.server.wifi.WifiScoreCard.CNT_DISCONNECTION_NONLOCAL_CONNECTING;
37 import static com.android.server.wifi.WifiScoreCard.CNT_SHORT_CONNECTION_NONLOCAL;
38 import static com.android.server.wifi.WifiScoreCard.LINK_BANDWIDTH_INIT_KBPS;
39 import static com.android.server.wifi.WifiScoreCard.LINK_RX;
40 import static com.android.server.wifi.WifiScoreCard.LINK_TX;
41 import static com.android.server.wifi.util.NativeUtil.hexStringFromByteArray;
42 
43 import static org.junit.Assert.*;
44 import static org.mockito.Mockito.*;
45 
46 import android.content.Context;
47 import android.content.res.Resources;
48 import android.net.MacAddress;
49 import android.net.wifi.SupplicantState;
50 import android.net.wifi.WifiInfo;
51 import android.net.wifi.WifiSsid;
52 import android.util.Base64;
53 import android.util.Pair;
54 
55 import androidx.test.filters.SmallTest;
56 
57 import com.android.server.wifi.WifiHealthMonitor.FailureStats;
58 import com.android.server.wifi.WifiScoreCard.NetworkConnectionStats;
59 import com.android.server.wifi.WifiScoreCard.PerNetwork;
60 import com.android.server.wifi.proto.WifiScoreCardProto.AccessPoint;
61 import com.android.server.wifi.proto.WifiScoreCardProto.BandwidthStatsAll;
62 import com.android.server.wifi.proto.WifiScoreCardProto.ConnectionStats;
63 import com.android.server.wifi.proto.WifiScoreCardProto.Event;
64 import com.android.server.wifi.proto.WifiScoreCardProto.Network;
65 import com.android.server.wifi.proto.WifiScoreCardProto.NetworkList;
66 import com.android.server.wifi.proto.WifiScoreCardProto.NetworkStats;
67 import com.android.server.wifi.proto.WifiScoreCardProto.Signal;
68 import com.android.server.wifi.proto.nano.WifiMetricsProto.BandwidthEstimatorStats;
69 import com.android.server.wifi.util.IntHistogram;
70 import com.android.server.wifi.util.RssiUtil;
71 import com.android.wifi.resources.R;
72 
73 import org.junit.Before;
74 import org.junit.Test;
75 import org.mockito.Mock;
76 import org.mockito.MockitoAnnotations;
77 
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.List;
81 
82 /**
83  * Unit tests for {@link com.android.server.wifi.WifiScoreCard}.
84  */
85 @SmallTest
86 public class WifiScoreCardTest extends WifiBaseTest {
87 
88     static final WifiSsid TEST_SSID_1 = WifiSsid.fromUtf8Text("Joe's Place");
89     static final WifiSsid TEST_SSID_2 = WifiSsid.fromUtf8Text("Poe's Ravn");
90 
91     static final MacAddress TEST_BSSID_1 = MacAddress.fromString("aa:bb:cc:dd:ee:ff");
92     static final MacAddress TEST_BSSID_2 = MacAddress.fromString("1:2:3:4:5:6");
93 
94     static final int TEST_NETWORK_AGENT_ID = 123;
95     static final int TEST_NETWORK_CONFIG_ID = 1492;
96 
97     static final double TOL = 1e-6; // for assertEquals(double, double, tolerance)
98 
99     static final int TEST_BSSID_FAILURE_REASON =
100             WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION;
101 
102     private static final String WIFI_IFACE_NAME = "wlanTest";
103 
104     WifiScoreCard mWifiScoreCard;
105 
106     @Mock Clock mClock;
107     @Mock WifiScoreCard.MemoryStore mMemoryStore;
108     @Mock DeviceConfigFacade mDeviceConfigFacade;
109     @Mock Context mContext;
110     @Mock Resources mResources;
111     @Mock WifiGlobals mWifiGlobals;
112 
113     private WifiLinkLayerStats mOldLlStats;
114     private WifiLinkLayerStats mNewLlStats;
115     private long mTotalTxBytes;
116     private long mTotalRxBytes;
117 
118     final ArrayList<String> mKeys = new ArrayList<>();
119     final ArrayList<WifiScoreCard.BlobListener> mBlobListeners = new ArrayList<>();
120     final ArrayList<byte[]> mBlobs = new ArrayList<>();
121 
122     long mMilliSecondsSinceBoot;
123     ExtendedWifiInfo mWifiInfo;
124 
millisecondsPass(long ms)125     void millisecondsPass(long ms) {
126         mMilliSecondsSinceBoot += ms;
127         when(mClock.getElapsedSinceBootMillis()).thenReturn(mMilliSecondsSinceBoot);
128     }
129 
secondsPass(long s)130     void secondsPass(long s) {
131         millisecondsPass(s * 1000);
132     }
133 
134     /**
135      * Sets up for unit test
136      */
137     @Before
setUp()138     public void setUp() throws Exception {
139         MockitoAnnotations.initMocks(this);
140         mKeys.clear();
141         mBlobListeners.clear();
142         mBlobs.clear();
143         mMilliSecondsSinceBoot = 0;
144         mWifiInfo = new ExtendedWifiInfo(mock(WifiGlobals.class), WIFI_IFACE_NAME);
145         mWifiInfo.setSSID(TEST_SSID_1);
146         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
147         mWifiInfo.setNetworkId(TEST_NETWORK_CONFIG_ID);
148         mWifiInfo.setTxLinkSpeedMbps(866);
149         mWifiInfo.setRxLinkSpeedMbps(866);
150         mWifiInfo.setMaxSupportedTxLinkSpeedMbps(866);
151         mWifiInfo.setMaxSupportedRxLinkSpeedMbps(866);
152         millisecondsPass(0);
153         mWifiScoreCard = new WifiScoreCard(mClock, "some seed", mDeviceConfigFacade,
154                 mContext, mWifiGlobals);
155         mWifiScoreCard.mPersistentHistograms = true; // TODO - remove when ready
156         when(mDeviceConfigFacade.getConnectionFailureHighThrPercent()).thenReturn(
157                 DeviceConfigFacade.DEFAULT_CONNECTION_FAILURE_HIGH_THR_PERCENT);
158         when(mDeviceConfigFacade.getConnectionFailureCountMin()).thenReturn(
159                 DeviceConfigFacade.DEFAULT_CONNECTION_FAILURE_COUNT_MIN);
160         when(mDeviceConfigFacade.getConnectionFailureDisconnectionHighThrPercent()).thenReturn(
161                 DeviceConfigFacade.DEFAULT_CONNECTION_FAILURE_DISCONNECTION_HIGH_THR_PERCENT);
162         when(mDeviceConfigFacade.getConnectionFailureDisconnectionCountMin()).thenReturn(
163                 DeviceConfigFacade.DEFAULT_CONNECTION_FAILURE_DISCONNECTION_COUNT_MIN);
164         when(mDeviceConfigFacade.getAssocRejectionHighThrPercent()).thenReturn(
165                 DeviceConfigFacade.DEFAULT_ASSOC_REJECTION_HIGH_THR_PERCENT);
166         when(mDeviceConfigFacade.getAssocRejectionCountMin()).thenReturn(
167                 DeviceConfigFacade.DEFAULT_ASSOC_REJECTION_COUNT_MIN);
168         when(mDeviceConfigFacade.getAssocTimeoutHighThrPercent()).thenReturn(
169                 DeviceConfigFacade.DEFAULT_ASSOC_TIMEOUT_HIGH_THR_PERCENT);
170         when(mDeviceConfigFacade.getAssocTimeoutCountMin()).thenReturn(
171                 DeviceConfigFacade.DEFAULT_ASSOC_TIMEOUT_COUNT_MIN);
172         when(mDeviceConfigFacade.getAuthFailureHighThrPercent()).thenReturn(
173                 DeviceConfigFacade.DEFAULT_AUTH_FAILURE_HIGH_THR_PERCENT);
174         when(mDeviceConfigFacade.getAuthFailureCountMin()).thenReturn(
175                 DeviceConfigFacade.DEFAULT_AUTH_FAILURE_COUNT_MIN);
176         when(mDeviceConfigFacade.getShortConnectionNonlocalHighThrPercent()).thenReturn(
177                 DeviceConfigFacade.DEFAULT_SHORT_CONNECTION_NONLOCAL_HIGH_THR_PERCENT);
178         when(mDeviceConfigFacade.getShortConnectionNonlocalCountMin()).thenReturn(
179                 DeviceConfigFacade.DEFAULT_SHORT_CONNECTION_NONLOCAL_COUNT_MIN);
180         when(mDeviceConfigFacade.getDisconnectionNonlocalHighThrPercent()).thenReturn(
181                 DeviceConfigFacade.DEFAULT_DISCONNECTION_NONLOCAL_HIGH_THR_PERCENT);
182         when(mDeviceConfigFacade.getDisconnectionNonlocalCountMin()).thenReturn(
183                 DeviceConfigFacade.DEFAULT_DISCONNECTION_NONLOCAL_COUNT_MIN);
184         when(mDeviceConfigFacade.getHealthMonitorMinRssiThrDbm()).thenReturn(
185                 DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_MIN_RSSI_THR_DBM);
186         when(mDeviceConfigFacade.getHealthMonitorRatioThrNumerator()).thenReturn(
187                 DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_RATIO_THR_NUMERATOR);
188         when(mDeviceConfigFacade.getHealthMonitorMinNumConnectionAttempt()).thenReturn(
189                 DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT);
190         when(mDeviceConfigFacade.getHealthMonitorShortConnectionDurationThrMs()).thenReturn(
191                 DeviceConfigFacade.DEFAULT_HEALTH_MONITOR_SHORT_CONNECTION_DURATION_THR_MS);
192         when(mDeviceConfigFacade.getAbnormalDisconnectionReasonCodeMask()).thenReturn(
193                 DeviceConfigFacade.DEFAULT_ABNORMAL_DISCONNECTION_REASON_CODE_MASK);
194         when(mDeviceConfigFacade.getHealthMonitorRssiPollValidTimeMs()).thenReturn(3000);
195         // Disable FW alert time check by default
196         when(mDeviceConfigFacade.getHealthMonitorFwAlertValidTimeMs()).thenReturn(-1);
197         when(mDeviceConfigFacade.getBugReportThresholdExtraRatio()).thenReturn(1);
198         when(mDeviceConfigFacade.getBandwidthEstimatorLargeTimeConstantSec()).thenReturn(6);
199         when(mDeviceConfigFacade.getTrafficStatsThresholdMaxKbyte()).thenReturn(4000);
200         mWifiScoreCard.enableVerboseLogging(true);
201         when(mContext.getResources()).thenReturn(mResources);
202         when(mResources.getIntArray(R.array.config_wifiRssiLevelThresholds))
203                 .thenReturn(new int[]{-88, -77, -66, -55});
204         when(mWifiGlobals.getPollRssiIntervalMillis()).thenReturn(3000);
205         mOldLlStats = new WifiLinkLayerStats();
206         mNewLlStats = new WifiLinkLayerStats();
207         mTotalTxBytes = 0;
208         mTotalRxBytes = 0;
209     }
210 
211     /**
212      * Test generic update
213      */
214     @Test
testUpdate()215     public void testUpdate() throws Exception {
216         mWifiInfo.setSSID(TEST_SSID_1);
217         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
218 
219         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
220 
221         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
222         assertTrue(perBssid.id > 0);
223         assertNotNull(perBssid.getL2Key());
224         assertTrue("L2Key length should be more than 16.", perBssid.getL2Key().length() > 16);
225 
226         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
227 
228         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
229 
230         assertEquals(perBssid, mWifiScoreCard.fetchByBssid(TEST_BSSID_1));
231         assertNotEquals(perBssid.id, mWifiScoreCard.fetchByBssid(TEST_BSSID_2).id);
232         assertNotEquals(perBssid.getL2Key(), mWifiScoreCard.fetchByBssid(TEST_BSSID_2).getL2Key());
233     }
234 
235     /**
236      * Test the get, increment, and removal of Bssid blocklist streak counts.
237      */
238     @Test
testBssidBlocklistStreakOperations()239     public void testBssidBlocklistStreakOperations() {
240         mWifiInfo.setSSID(TEST_SSID_1);
241         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
242         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
243 
244         String ssid = mWifiInfo.getSSID();
245         String bssid = mWifiInfo.getBSSID();
246         assertEquals(0, mWifiScoreCard.getBssidBlocklistStreak(
247                 ssid, bssid, TEST_BSSID_FAILURE_REASON));
248         for (int i = 1; i < 3; i++) {
249             assertEquals(i, mWifiScoreCard.incrementBssidBlocklistStreak(
250                     ssid, bssid, TEST_BSSID_FAILURE_REASON));
251             assertEquals(i, mWifiScoreCard.getBssidBlocklistStreak(
252                     ssid, bssid, TEST_BSSID_FAILURE_REASON));
253         }
254         mWifiScoreCard.resetBssidBlocklistStreak(ssid, bssid, TEST_BSSID_FAILURE_REASON);
255         assertEquals(0, mWifiScoreCard.getBssidBlocklistStreak(
256                 ssid, bssid, TEST_BSSID_FAILURE_REASON));
257     }
258 
259     /**
260      * Test clearing the blocklist streak for all APs belonging to a SSID.
261      */
262     @Test
testClearBssidBlocklistStreakForSsid()263     public void testClearBssidBlocklistStreakForSsid() {
264         // Increment and verify the blocklist streak for SSID_1, BSSID_1
265         mWifiInfo.setSSID(TEST_SSID_1);
266         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
267         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
268         for (int i = 1; i < 3; i++) {
269             assertEquals(i, mWifiScoreCard.incrementBssidBlocklistStreak(
270                     mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
271             assertEquals(i, mWifiScoreCard.getBssidBlocklistStreak(
272                     mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
273         }
274 
275         // Increment and verify the blocklist streak for SSID_2, BSSID_2
276         mWifiInfo.setSSID(TEST_SSID_2);
277         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
278         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
279         for (int i = 1; i < 3; i++) {
280             assertEquals(i, mWifiScoreCard.incrementBssidBlocklistStreak(
281                     mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
282             assertEquals(i, mWifiScoreCard.getBssidBlocklistStreak(
283                     mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
284         }
285 
286         // Clear the blocklist streak for SSID_2
287         mWifiScoreCard.resetBssidBlocklistStreakForSsid(mWifiInfo.getSSID());
288         // Verify that the blocklist streak for SSID_2 is cleared.
289         assertEquals(0, mWifiScoreCard.getBssidBlocklistStreak(
290                 mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
291 
292         // verify that the blocklist streak for SSID_1 is not cleared.
293         mWifiInfo.setSSID(TEST_SSID_1);
294         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
295         assertEquals(2, mWifiScoreCard.getBssidBlocklistStreak(
296                 mWifiInfo.getSSID(), mWifiInfo.getBSSID(), TEST_BSSID_FAILURE_REASON));
297     }
298 
299     /**
300      * Test the update and retrieval of the last connection time to a BSSID.
301      */
302     @Test
testSetBssidConnectionTimestampMs()303     public void testSetBssidConnectionTimestampMs() {
304         mWifiInfo.setSSID(TEST_SSID_1);
305         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
306         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
307 
308         String ssid = mWifiInfo.getSSID();
309         String bssid = mWifiInfo.getBSSID();
310         assertEquals(0L, mWifiScoreCard.getBssidConnectionTimestampMs(ssid, bssid));
311         assertEquals(0L, mWifiScoreCard.setBssidConnectionTimestampMs(ssid, bssid, 100L));
312         assertEquals(100L, mWifiScoreCard.getBssidConnectionTimestampMs(ssid, bssid));
313     }
314 
315     /**
316      * Test identifiers.
317      */
318     @Test
testIdentifiers()319     public void testIdentifiers() throws Exception {
320         mWifiInfo.setSSID(TEST_SSID_1);
321         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
322         Pair<String, String> p1 = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
323         assertNotNull(p1.first);
324         assertNotNull(p1.second);
325         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
326         Pair<String, String> p2 = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
327         assertNotEquals(p1.first, p2.first);
328         assertEquals(p1.second, p2.second);
329         mWifiInfo.setBSSID(null);
330         Pair<String, String> p3 = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
331         assertNull(p3.first);
332         assertNull(p3.second);
333         mWifiInfo.setBSSID("02:00:00:00:00:00");
334         Pair<String, String> p4 = mWifiScoreCard.getL2KeyAndGroupHint(mWifiInfo);
335         assertNull(p4.first);
336         assertNull(p4.second);
337     }
338 
339     /**
340      * Test rssi poll updates
341      */
342     @Test
testRssiPollUpdates()343     public void testRssiPollUpdates() throws Exception {
344         // Start out on one frequency
345         mWifiInfo.setFrequency(5805);
346         mWifiInfo.setRssi(-77);
347         mWifiInfo.setLinkSpeed(12);
348         mWifiScoreCard.noteSignalPoll(mWifiInfo);
349         // Switch channels for a bit
350         mWifiInfo.setFrequency(5290);
351         mWifiInfo.setRssi(-66);
352         mWifiInfo.setLinkSpeed(666);
353         mWifiScoreCard.noteSignalPoll(mWifiInfo);
354         // Back to the first channel
355         mWifiInfo.setFrequency(5805);
356         mWifiInfo.setRssi(-55);
357         mWifiInfo.setLinkSpeed(86);
358         mWifiScoreCard.noteSignalPoll(mWifiInfo);
359 
360         double expectSum = -77 + -55;
361         double expectSumSq = 77 * 77 + 55 * 55;
362 
363         // Now verify
364         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
365         // Looking up the same thing twice should yield the same object.
366         assertTrue(perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
367                 == perBssid.lookupSignal(Event.SIGNAL_POLL, 5805));
368         // Check the rssi statistics for the first channel
369         assertEquals(2, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805).rssi.count);
370         assertEquals(expectSum, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
371                 .rssi.sum, TOL);
372         assertEquals(expectSumSq, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
373                 .rssi.sumOfSquares, TOL);
374         assertEquals(-77.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
375                 .rssi.minValue, TOL);
376         assertEquals(-55.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
377                 .rssi.maxValue, TOL);
378         // Check the rssi statistics for the second channel
379         assertEquals(1, perBssid.lookupSignal(Event.SIGNAL_POLL, 5290).rssi.count);
380         // Check that the linkspeed was updated
381         assertEquals(666.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 5290).linkspeed.sum, TOL);
382     }
383 
384     /**
385      * Statistics on time-to-connect, connection duration
386      */
387     @Test
testDurationStatistics()388     public void testDurationStatistics() throws Exception {
389         // Start out disconnected; start connecting
390         mWifiInfo.setBSSID(android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS);
391         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
392         // First poll has a bad RSSI
393         millisecondsPass(111);
394         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
395         mWifiInfo.setFrequency(5805);
396         mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
397         // A bit later, connection is complete (up through DHCP)
398         millisecondsPass(222);
399         mWifiInfo.setRssi(-55);
400         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
401         millisecondsPass(666);
402         // Rssi polls for 99 seconds
403         for (int i = 0; i < 99; i += 3) {
404             mWifiScoreCard.noteSignalPoll(mWifiInfo);
405             secondsPass(3);
406         }
407         // Make sure our simulated time adds up
408         assertEquals(mMilliSecondsSinceBoot, 99999);
409         // Validation success, rather late!
410         mWifiScoreCard.noteValidationSuccess(mWifiInfo);
411         // A long while later, wifi is toggled off
412         secondsPass(9900);
413         // Second validation success should not matter.
414         mWifiScoreCard.noteValidationSuccess(mWifiInfo);
415         mWifiInfo.setRssi(-88);
416         mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
417         mWifiScoreCard.noteWifiDisabled(mWifiInfo);
418 
419         // Now verify
420         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
421         assertEquals(1, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
422                 .elapsedMs.count);
423         assertEquals(333.0, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
424                 .elapsedMs.sum, TOL);
425         assertEquals(9999999.0, perBssid.lookupSignal(Event.WIFI_DISABLED, 5805)
426                 .elapsedMs.maxValue, TOL);
427         assertEquals(999.0, perBssid.lookupSignal(Event.FIRST_POLL_AFTER_CONNECTION, 5805)
428                 .elapsedMs.minValue, TOL);
429         assertEquals(99999.0, perBssid.lookupSignal(Event.VALIDATION_SUCCESS, 5805)
430                 .elapsedMs.sum, TOL);
431         assertEquals(-88.0, perBssid.lookupSignal(Event.IP_REACHABILITY_LOST, 5805)
432                 .rssi.sum, TOL);
433         assertNull(perBssid.lookupSignal(Event.SIGNAL_POLL, 5805).elapsedMs);
434     }
435 
436     /**
437      * Firmware roam
438      */
439     @Test
testFirmwareRoam()440     public void testFirmwareRoam() throws Exception {
441         // Start out disconnected; start connecting
442         mWifiInfo.setBSSID(android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS);
443         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
444 
445         // First poll has a bad RSSI
446         millisecondsPass(111);
447         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
448         mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
449         mWifiInfo.setFrequency(5805);
450         mWifiInfo.setRssi(WifiInfo.INVALID_RSSI);
451 
452         // A bit later, connection is complete (up through DHCP)
453         millisecondsPass(222);
454         mWifiInfo.setRssi(-55);
455         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
456 
457         millisecondsPass(666);
458         mWifiInfo.setRssi(-77);
459         // Rssi polls for 99 seconds
460         for (int i = 0; i < 99; i += 9) {
461             mWifiScoreCard.noteSignalPoll(mWifiInfo);
462             secondsPass(9);
463         }
464 
465         // Make sure our simulated time adds up
466         assertEquals(mMilliSecondsSinceBoot, 99999);
467         // Validation success, rather late!
468         mWifiScoreCard.noteValidationSuccess(mWifiInfo);
469         // Simulate a successful roam
470         mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, SupplicantState.COMPLETED);
471         millisecondsPass(1);
472         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
473         mWifiInfo.setRssi(-66);
474         mWifiInfo.setFrequency(2412);
475         mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
476         mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
477         secondsPass(9);
478         assertEquals(mMilliSecondsSinceBoot, 109000);
479         mWifiScoreCard.noteSignalPoll(mWifiInfo);
480 
481         // Simulate an unsuccessful roam
482         secondsPass(1);
483         mWifiInfo.setRssi(-74);
484         mWifiScoreCard.noteSignalPoll(mWifiInfo);
485         secondsPass(1);
486         mWifiScoreCard.noteSupplicantStateChanging(mWifiInfo, SupplicantState.COMPLETED);
487         mWifiInfo.setBSSID(TEST_BSSID_1.toString());
488         mWifiInfo.setFrequency(5805);
489         mWifiInfo.setSupplicantState(SupplicantState.COMPLETED);
490         mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
491         secondsPass(3);
492         mWifiScoreCard.noteIpReachabilityLost(mWifiInfo);
493 
494         // Now verify
495         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
496         assertEquals(1, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
497                 .elapsedMs.count);
498         assertEquals(-77, perBssid.lookupSignal(Event.LAST_POLL_BEFORE_ROAM, 5805)
499                 .rssi.minValue, TOL);
500         assertEquals(1, perBssid.lookupSignal(Event.ROAM_FAILURE, 5805)
501                 .rssi.count);
502 
503         assertEquals(67, perBssid.estimatePercentInternetAvailability());
504 
505         perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_2);
506         assertEquals(-66.0, perBssid.lookupSignal(Event.ROAM_SUCCESS, 2412)
507                 .rssi.sum, TOL);
508         assertEquals(50, perBssid.estimatePercentInternetAvailability());
509     }
510 
511     /**
512      * Constructs a protobuf form of AccessPoint example.
513      */
makeSerializedAccessPointExample()514     private byte[] makeSerializedAccessPointExample() {
515         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
516         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
517         millisecondsPass(10);
518         // Association completes, a NetworkAgent is created
519         mWifiScoreCard.noteNetworkAgentCreated(mWifiInfo, TEST_NETWORK_AGENT_ID);
520         millisecondsPass(101);
521         mWifiInfo.setRssi(-55);
522         mWifiInfo.setFrequency(5805);
523         mWifiInfo.setLinkSpeed(384);
524         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
525         perNetwork.addFrequency(mWifiInfo.getFrequency());
526         millisecondsPass(888);
527         mWifiScoreCard.noteSignalPoll(mWifiInfo);
528         millisecondsPass(1000);
529         mWifiInfo.setRssi(-44);
530         mWifiScoreCard.noteSignalPoll(mWifiInfo);
531         mWifiInfo.setFrequency(2432);
532         perNetwork.addFrequency(mWifiInfo.getFrequency());
533         for (int round = 0; round < 4; round++) {
534             for (int i = 0; i < HISTOGRAM_COUNT.length; i++) {
535                 if (HISTOGRAM_COUNT[i] > round) {
536                     mWifiInfo.setRssi(HISTOGRAM_RSSI[i]);
537                     mWifiScoreCard.noteSignalPoll(mWifiInfo);
538                 }
539             }
540         }
541         makeUpdateLinkBandwidthExample();
542         mWifiScoreCard.resetAllConnectionStates();
543 
544         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
545         perBssid.lookupSignal(Event.SIGNAL_POLL, 2412).rssi.historicalMean = -42.0;
546         perBssid.lookupSignal(Event.SIGNAL_POLL, 2412).rssi.historicalVariance = 4.0;
547         checkSerializationBssidExample("before serialization", perBssid);
548         // Now convert to protobuf form
549         byte[] serialized = perBssid.toAccessPoint().toByteArray();
550         return serialized;
551     }
552     private static final int[] HISTOGRAM_RSSI = {-80, -79, -78};
553     private static final int[] HISTOGRAM_COUNT = {3, 1, 4};
554 
checkHistogramExample(String diag, IntHistogram rssiHistogram)555     private void checkHistogramExample(String diag, IntHistogram rssiHistogram) {
556         int i = 0;
557         for (IntHistogram.Bucket bucket : rssiHistogram) {
558             if (bucket.count != 0) {
559                 assertTrue(diag, i < HISTOGRAM_COUNT.length);
560                 assertEquals(diag, HISTOGRAM_RSSI[i], bucket.start);
561                 assertEquals(diag, HISTOGRAM_COUNT[i], bucket.count);
562                 i++;
563             }
564         }
565         assertEquals(diag, HISTOGRAM_COUNT.length, i);
566     }
567 
568     /**
569      * Checks that the fields of the bssid serialization example are as expected
570      */
checkSerializationBssidExample(String diag, WifiScoreCard.PerBssid perBssid)571     private void checkSerializationBssidExample(String diag, WifiScoreCard.PerBssid perBssid) {
572         assertEquals(diag, 2, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805).rssi.count);
573         assertEquals(diag, -55.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
574                 .rssi.minValue, TOL);
575         assertEquals(diag, -44.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 5805)
576                 .rssi.maxValue, TOL);
577         assertEquals(diag, 384.0, perBssid.lookupSignal(Event.FIRST_POLL_AFTER_CONNECTION, 5805)
578                 .linkspeed.sum, TOL);
579         assertEquals(diag, 111.0, perBssid.lookupSignal(Event.IP_CONFIGURATION_SUCCESS, 5805)
580                 .elapsedMs.minValue, TOL);
581         assertEquals(diag, 0, perBssid.lookupSignal(Event.SIGNAL_POLL, 2412).rssi.count);
582         assertEquals(diag, -42.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 2412)
583                 .rssi.historicalMean, TOL);
584         assertEquals(diag, 4.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 2412)
585                 .rssi.historicalVariance, TOL);
586         checkHistogramExample(diag, perBssid.lookupSignal(Event.SIGNAL_POLL,
587                 2432).rssi.intHistogram);
588     }
589 
590     /**
591      * Checks that the fields of the network are as expected with bssid serialization example
592      */
checkSerializationBssidExample(String diag, PerNetwork perNetwork)593     private void checkSerializationBssidExample(String diag, PerNetwork perNetwork) {
594         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
595         assertEquals(diag, 1, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
596         assertEquals(diag, 0, dailyStats.getCount(CNT_CONNECTION_FAILURE));
597         assertEquals(diag, 1, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
598         assertEquals(diag, 0, dailyStats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
599         assertEquals(diag, 0, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL));
600         assertEquals(diag, 0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
601         assertEquals(diag, 0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
602         assertEquals(diag, 0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
603         assertEquals(diag, 0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
604         List<Integer> frequencies = perNetwork.getFrequencies(Long.MAX_VALUE);
605         assertEquals(diag, 2, frequencies.size());
606         List<Integer> expectedFrequencies = new ArrayList<>(Arrays.asList(2432, 5805));
607         assertEquals(diag, expectedFrequencies, frequencies);
608     }
609 
610     /**
611      * AccessPoint serialization
612      */
613     @Test
testAccessPointSerialization()614     public void testAccessPointSerialization() throws Exception {
615         byte[] serialized = makeSerializedAccessPointExample();
616 
617         // Verify by parsing it and checking that we see the expected results
618         AccessPoint ap = AccessPoint.parseFrom(serialized);
619         assertEquals(5, ap.getEventStatsCount());
620         for (Signal signal: ap.getEventStatsList()) {
621             if (signal.getFrequency() == 2412) {
622                 assertFalse(signal.getRssi().hasCount());
623                 assertEquals(-42.0, signal.getRssi().getHistoricalMean(), TOL);
624                 assertEquals(4.0, signal.getRssi().getHistoricalVariance(), TOL);
625                 continue;
626             }
627             if (signal.getFrequency() == 2432) {
628                 assertEquals(Event.SIGNAL_POLL, signal.getEvent());
629                 assertEquals(HISTOGRAM_RSSI[2], signal.getRssi().getBuckets(2).getLow());
630                 assertEquals(HISTOGRAM_COUNT[2], signal.getRssi().getBuckets(2).getNumber());
631                 continue;
632             }
633             assertEquals(5805, signal.getFrequency());
634             switch (signal.getEvent()) {
635                 case IP_CONFIGURATION_SUCCESS:
636                     assertEquals(384.0, signal.getLinkspeed().getMaxValue(), TOL);
637                     assertEquals(111.0, signal.getElapsedMs().getMinValue(), TOL);
638                     break;
639                 case SIGNAL_POLL:
640                     assertEquals(2, signal.getRssi().getCount());
641                     break;
642                 case FIRST_POLL_AFTER_CONNECTION:
643                     assertEquals(-55.0, signal.getRssi().getSum(), TOL);
644                     break;
645                 default:
646                     fail(signal.getEvent().toString());
647             }
648         }
649         checkSerializationUpdateLinkBandwidthExample(ap.getBandwidthStatsAll());
650     }
651 
652     /**
653      * Serialization should be reproducible
654      */
655     @Test
testReproducableSerialization()656     public void testReproducableSerialization() throws Exception {
657         byte[] serialized = makeSerializedAccessPointExample();
658         setUp();
659         assertArrayEquals(serialized, makeSerializedAccessPointExample());
660     }
661 
662     /**
663      * AccessPoint Deserialization
664      */
665     @Test
testAccessPointDeserialization()666     public void testAccessPointDeserialization() throws Exception {
667         byte[] serialized = makeSerializedAccessPointExample();
668         setUp(); // Get back to the initial state
669 
670         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.perBssidFromAccessPoint(
671                 mWifiInfo.getSSID(),
672                 AccessPoint.parseFrom(serialized));
673 
674         // Now verify
675         String diag = hexStringFromByteArray(serialized);
676         checkSerializationBssidExample(diag, perBssid);
677     }
678 
679     /**
680      * Serialization of all internally represented networks
681      */
682     @Test
testNetworksSerialization()683     public void testNetworksSerialization() throws Exception {
684         makeSerializedAccessPointExample();
685 
686         byte[] serialized = mWifiScoreCard.getNetworkListByteArray(false);
687         byte[] cleaned = mWifiScoreCard.getNetworkListByteArray(true);
688         String base64Encoded = mWifiScoreCard.getNetworkListBase64(true);
689 
690         setUp(); // Get back to the initial state
691         String diag = hexStringFromByteArray(serialized);
692         NetworkList networkList = NetworkList.parseFrom(serialized);
693         assertEquals(diag, 1, networkList.getNetworksCount());
694         Network network = networkList.getNetworks(0);
695         assertEquals(diag, 1, network.getAccessPointsCount());
696         AccessPoint accessPoint = network.getAccessPoints(0);
697         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.perBssidFromAccessPoint(network.getSsid(),
698                 accessPoint);
699         NetworkStats networkStats = network.getNetworkStats();
700         PerNetwork perNetwork = mWifiScoreCard.perNetworkFromNetworkStats(network.getSsid(),
701                 networkStats);
702 
703         checkSerializationBssidExample(diag, perBssid);
704         checkSerializationBssidExample(diag, perNetwork);
705         // Leaving out the bssids should make the cleaned version shorter.
706         assertTrue(cleaned.length < serialized.length);
707         // Check the Base64 version
708         assertTrue(Arrays.equals(cleaned, Base64.decode(base64Encoded, Base64.DEFAULT)));
709         // Check that the network ids were carried over
710         assertEquals(TEST_NETWORK_AGENT_ID, network.getNetworkAgentId());
711         assertEquals(TEST_NETWORK_CONFIG_ID, network.getNetworkConfigId());
712     }
713 
714     /**
715      * Installation of memory store does not crash
716      */
717     @Test
718     public void testInstallationOfMemoryStoreDoesNotCrash() throws Exception {
719         mWifiScoreCard.installMemoryStore(mMemoryStore);
720         makeSerializedAccessPointExample();
721         mWifiScoreCard.installMemoryStore(mMemoryStore);
722     }
723 
724     /**
725      * Merge of lazy reads
726      */
727     @Test
728     public void testLazyReads() {
729         // Install our own MemoryStore object, which records read requests
730         mWifiScoreCard.installMemoryStore(new WifiScoreCard.MemoryStore() {
731             @Override
732             public void read(String key, String name, WifiScoreCard.BlobListener listener) {
733                 mKeys.add(key);
734                 mBlobListeners.add(listener);
735             }
736             @Override
737             public void write(String key, String name, byte[] value) {
738                 // ignore for now
739             }
740             @Override
741             public void setCluster(String key, String cluster) {
742                 // ignore for now
743             }
744             @Override
745             public void removeCluster(String cluster) {
746                 // ignore for now
747             }
748         });
749 
750         // Now make some changes
751         byte[] serialized = makeSerializedAccessPointExample();
752         // 1 for perfBssid and 1 for perNetwork
753         assertEquals(2, mKeys.size());
754 
755         // Simulate the asynchronous completion of the read request
756         millisecondsPass(33);
757         mBlobListeners.get(0).onBlobRetrieved(serialized);
758 
759         // Check that the historical mean and variance were updated accordingly
760         WifiScoreCard.PerBssid perBssid = mWifiScoreCard.fetchByBssid(TEST_BSSID_1);
761         assertEquals(-42.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 2412)
762                 .rssi.historicalMean, TOL);
763         assertEquals(4.0, perBssid.lookupSignal(Event.SIGNAL_POLL, 2412)
764                 .rssi.historicalVariance, TOL);
765     }
766 
767     /**
768      * Write test
769      */
770     @Test
771     public void testWrites() throws Exception {
772         // Install our own MemoryStore object, which records write requests
773         mWifiScoreCard.installMemoryStore(new WifiScoreCard.MemoryStore() {
774             @Override
775             public void read(String key, String name, WifiScoreCard.BlobListener listener) {
776                 // Just record these, never answer
777                 mBlobListeners.add(listener);
778             }
779             @Override
780             public void write(String key, String name, byte[] value) {
781                 mKeys.add(key);
782                 mBlobs.add(value);
783             }
784             @Override
785             public void setCluster(String key, String cluster) {
786             }
787             @Override
788             public void removeCluster(String cluster) {
789                 // ignore for now
790             }
791         });
792 
793         // Make some changes
794         byte[] serialized = makeSerializedAccessPointExample();
795         // 1 for perfBssid and 1 for perNetwork
796         assertEquals(2, mBlobListeners.size());
797 
798         secondsPass(33);
799 
800         // There should be one changed bssid now. We may have already done some writes.
801         mWifiScoreCard.doWrites();
802         assertTrue(mKeys.size() > 0);
803 
804         // The written blob should not contain the BSSID, though the full serialized version does
805         String writtenHex = hexStringFromByteArray(mBlobs.get(mKeys.size() - 1));
806         String fullHex = hexStringFromByteArray(serialized);
807         String bssidHex = hexStringFromByteArray(TEST_BSSID_1.toByteArray());
808         assertFalse(writtenHex, writtenHex.contains(bssidHex));
809         assertTrue(fullHex, fullHex.contains(bssidHex));
810 
811         // A second write request should not find anything to write
812         final int beforeSize = mKeys.size();
813         assertEquals(0, mWifiScoreCard.doWrites());
814         assertEquals(beforeSize, mKeys.size());
815     }
816 
817     /**
818      * Calling doWrites before installing a MemoryStore should do nothing.
819      */
820     @Test
testNoWritesUntilReady()821     public void testNoWritesUntilReady() throws Exception {
822         makeSerializedAccessPointExample();
823         assertEquals(0, mWifiScoreCard.doWrites());
824     }
825 
826     /**
827      * Installing a MemoryStore after startup should issue reads.
828      */
829     @Test
testReadAfterDelayedMemoryStoreInstallation()830     public void testReadAfterDelayedMemoryStoreInstallation() throws Exception {
831         makeSerializedAccessPointExample();
832         mWifiScoreCard.installMemoryStore(mMemoryStore);
833         // 1 for requestReadBssid
834         verify(mMemoryStore, times(1)).read(any(), any(), any());
835     }
836 
837     /**
838      * Calling clear should forget the state.
839      */
840     @Test
testClearReallyDoesClearTheState()841     public void testClearReallyDoesClearTheState() throws Exception {
842         byte[] serialized = makeSerializedAccessPointExample();
843         assertNotEquals(0, serialized.length);
844         mWifiScoreCard.clear();
845         byte[] leftovers = mWifiScoreCard.getNetworkListByteArray(false);
846         assertEquals(0, leftovers.length);
847     }
848 
849     /**
850      * Test that older items are evicted from memory.
851      */
852     @Test
testOlderItemsShouldBeEvicted()853     public void testOlderItemsShouldBeEvicted() throws Exception {
854         mWifiInfo.setRssi(-55);
855         mWifiInfo.setFrequency(5805);
856         mWifiInfo.setLinkSpeed(384);
857         mWifiScoreCard.installMemoryStore(mMemoryStore);
858         for (int i = 0; i < 256; i++) {
859             MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i});
860             mWifiInfo.setBSSID(bssid.toString());
861             mWifiScoreCard.noteSignalPoll(mWifiInfo);
862         }
863         // 256 for requestReadBssid() and 1 for requestReadNetwork()
864         verify(mMemoryStore, times(256 + 1)).read(any(), any(), any());
865         verify(mMemoryStore, atLeastOnce()).write(any(), any(), any()); // Assumes target size < 256
866         reset(mMemoryStore);
867 
868         for (int i = 256 - 3; i < 256; i++) {
869             MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i});
870             mWifiInfo.setBSSID(bssid.toString());
871             mWifiScoreCard.noteSignalPoll(mWifiInfo);
872         }
873         verify(mMemoryStore, never()).read(any(), any(), any()); // Assumes target size >= 3
874 
875         for (int i = 0; i < 3; i++) {
876             MacAddress bssid = MacAddress.fromBytes(new byte[]{2, 2, 2, 2, 2, (byte) i});
877             mWifiInfo.setBSSID(bssid.toString());
878             mWifiScoreCard.noteSignalPoll(mWifiInfo);
879         }
880         verify(mMemoryStore, times(3)).read(any(), any(), any()); // Assumes target size < 253
881     }
882 
makeAssocTimeOutExample()883     private void makeAssocTimeOutExample() {
884         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
885         millisecondsPass(1000);
886         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
887                 WifiBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT);
888     }
889 
makeAssocRejectionExample()890     private void makeAssocRejectionExample() {
891         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
892         millisecondsPass(1000);
893         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
894                 WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION);
895     }
896 
makeApUnableToHandleNewStaExample()897     private void makeApUnableToHandleNewStaExample() {
898         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
899         millisecondsPass(1000);
900         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
901                 WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA);
902     }
903 
904     /**
905      * Check network stats after association timeout.
906      */
907     @Test
testNetworkAssocTimeOut()908     public void testNetworkAssocTimeOut() throws Exception {
909         makeAssocTimeOutExample();
910 
911         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
912         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
913 
914         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
915         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
916         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
917         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
918         assertEquals(1, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
919         assertEquals(0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
920         assertEquals(1, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
921         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
922     }
923 
924     /**
925      * Check network stats after association rejection.
926      */
927     @Test
testNetworkAssocRejection()928     public void testNetworkAssocRejection() throws Exception {
929         makeAssocRejectionExample();
930         makeApUnableToHandleNewStaExample();
931 
932         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
933         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
934 
935         assertEquals(2, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
936         assertEquals(2, dailyStats.getCount(CNT_CONNECTION_FAILURE));
937         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
938         assertEquals(1, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
939         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
940         assertEquals(0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
941         assertEquals(2, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
942         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
943     }
944 
945 
946     /**
947      * Check network stats after auth timeout/disconnection and a normal connection
948      */
949     @Test
testAuthTimeoutDisconnection()950     public void testAuthTimeoutDisconnection() throws Exception {
951         makeAuthFailureExample();
952         mWifiScoreCard.resetAllConnectionStates();
953 
954         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
955         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
956 
957         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
958         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
959         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
960         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
961         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
962         assertEquals(1, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
963         assertEquals(1, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
964         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
965 
966         makeNormalConnectionExample();
967         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
968     }
969 
makeAuthFailureAndWrongPassword()970     private void makeAuthFailureAndWrongPassword() {
971         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
972         millisecondsPass(500);
973         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
974                 WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE);
975         millisecondsPass(1000);
976         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
977         millisecondsPass(1000);
978         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
979                 WifiBlocklistMonitor.REASON_WRONG_PASSWORD);
980     }
981 
makeAuthFailureExample()982     private void makeAuthFailureExample() {
983         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
984         millisecondsPass(500);
985         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
986                 WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE);
987     }
988 
989     /**
990      * Check network stats after authentication failure and wrong password.
991      */
992     @Test
testNetworkAuthenticationFailureWrongPassword()993     public void testNetworkAuthenticationFailureWrongPassword() throws Exception {
994         makeAuthFailureAndWrongPassword();
995         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
996         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
997 
998         assertEquals(2, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
999         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
1000         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
1001         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
1002         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
1003         assertEquals(1, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
1004         assertEquals(1, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
1005         assertEquals(1, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
1006 
1007         makeNormalConnectionExample();
1008         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
1009         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
1010     }
1011 
makeDisconnectionConnectingExample(boolean nonlocal)1012     private void makeDisconnectionConnectingExample(boolean nonlocal) {
1013         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1014         millisecondsPass(500);
1015         int disconnectionReason = 3;
1016         if (nonlocal) {
1017             mWifiScoreCard.noteNonlocalDisconnect(WIFI_IFACE_NAME, disconnectionReason);
1018         }
1019         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
1020                 WifiBlocklistMonitor.REASON_NONLOCAL_DISCONNECT_CONNECTING);
1021         millisecondsPass(500);
1022     }
1023 
1024     /**
1025      * Check network stats after nonlocal disconnection in middle of connection
1026      */
1027     @Test
testDisconnectionConnecting()1028     public void testDisconnectionConnecting() throws Exception {
1029         makeDisconnectionConnectingExample(true);
1030         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1031         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1032 
1033         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
1034         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
1035         assertEquals(1, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL_CONNECTING));
1036         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
1037         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
1038         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
1039         assertEquals(0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
1040         assertEquals(0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
1041     }
1042 
1043     /**
1044      * Check network stats after local disconnection in middle of connection
1045      */
1046     @Test
testLocalDisconnectionConnecting()1047     public void testLocalDisconnectionConnecting() throws Exception {
1048         makeDisconnectionConnectingExample(false);
1049         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1050         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1051 
1052         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
1053         assertEquals(1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
1054         assertEquals(1, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL_CONNECTING));
1055     }
1056 
1057     /**
1058      * Check network stats when a new connection attempt for SSID2 is issued
1059      * before disconnection of SSID1
1060      */
1061     @Test
testNetworkSwitchWithOverlapping()1062     public void testNetworkSwitchWithOverlapping() throws Exception {
1063         // Connect to SSID_1
1064         String ssid1 = mWifiInfo.getSSID();
1065         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, ssid1);
1066         millisecondsPass(5000);
1067 
1068         // Attempt to connect to SSID_2
1069         mWifiInfo.setSSID(TEST_SSID_2);
1070         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
1071         String ssid2 = mWifiInfo.getSSID();
1072         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, ssid2);
1073 
1074         // Disconnect from SSID_1
1075         millisecondsPass(100);
1076         int disconnectionReason = 4;
1077         mWifiScoreCard.noteNonlocalDisconnect(WIFI_IFACE_NAME, disconnectionReason);
1078         millisecondsPass(100);
1079         mWifiScoreCard.resetConnectionState(WIFI_IFACE_NAME);
1080 
1081         // SSID_2 is connected and then disconnected
1082         millisecondsPass(2000);
1083         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1084         millisecondsPass(2000);
1085         mWifiScoreCard.resetConnectionState(WIFI_IFACE_NAME);
1086 
1087         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(ssid1);
1088         assertEquals(5, perNetwork.getRecentStats().getCount(CNT_CONNECTION_DURATION_SEC));
1089 
1090         perNetwork = mWifiScoreCard.fetchByNetwork(ssid2);
1091         assertEquals(4, perNetwork.getRecentStats().getCount(CNT_CONNECTION_DURATION_SEC));
1092     }
1093 
1094     /**
1095      * Check network stats after 2 connection failures at low RSSI.
1096      */
1097     @Test
testNetworkConnectionFailureLowRssi()1098     public void testNetworkConnectionFailureLowRssi() throws Exception {
1099         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -83, mWifiInfo.getSSID());
1100         millisecondsPass(1000);
1101         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -83, mWifiInfo.getSSID(),
1102                 WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION);
1103         millisecondsPass(3000);
1104         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -83, mWifiInfo.getSSID());
1105         millisecondsPass(1000);
1106         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -83, mWifiInfo.getSSID(),
1107                 WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION);
1108 
1109         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1110         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1111         checkShortConnectionExample(dailyStats, 0);
1112     }
1113 
makeShortConnectionExample(boolean addFwAlert)1114     private void makeShortConnectionExample(boolean addFwAlert) {
1115         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1116         millisecondsPass(5000);
1117         mWifiInfo.setTxLinkSpeedMbps(100);
1118         mWifiInfo.setSuccessfulTxPacketsPerSecond(20.0);
1119         mWifiInfo.setRetriedTxPacketsRate(1.0);
1120         mWifiInfo.setRssi(-80);
1121         millisecondsPass(1000);
1122         mWifiScoreCard.noteSignalPoll(mWifiInfo);
1123         millisecondsPass(2000);
1124         int disconnectionReason = 34;
1125         mWifiScoreCard.noteNonlocalDisconnect(WIFI_IFACE_NAME, disconnectionReason);
1126         if (addFwAlert) {
1127             mWifiScoreCard.noteFirmwareAlert(6);
1128         }
1129         millisecondsPass(1000);
1130         mWifiScoreCard.resetAllConnectionStates();
1131     }
1132 
checkShortConnectionExample(NetworkConnectionStats stats, int scale)1133     private void checkShortConnectionExample(NetworkConnectionStats stats, int scale) {
1134         assertEquals(1 * scale, stats.getCount(CNT_CONNECTION_ATTEMPT));
1135         assertEquals(0, stats.getCount(CNT_CONNECTION_FAILURE));
1136         assertEquals(0, stats.getCount(CNT_DISCONNECTION_NONLOCAL_CONNECTING));
1137         assertEquals(9 * scale, stats.getCount(CNT_CONNECTION_DURATION_SEC));
1138         assertEquals(0, stats.getCount(CNT_ASSOCIATION_REJECTION));
1139         assertEquals(0, stats.getCount(CNT_ASSOCIATION_TIMEOUT));
1140         assertEquals(0, stats.getCount(CNT_AUTHENTICATION_FAILURE));
1141         assertEquals(1 * scale, stats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
1142         assertEquals(1 * scale, stats.getCount(CNT_DISCONNECTION_NONLOCAL));
1143         assertEquals(0, stats.getCount(CNT_CONSECUTIVE_CONNECTION_FAILURE));
1144     }
1145 
makeShortConnectionOldRssiPollingExample()1146     private void makeShortConnectionOldRssiPollingExample() {
1147         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1148         millisecondsPass(2000);
1149         mWifiInfo.setRssi(-55);
1150         millisecondsPass(1000);
1151         mWifiScoreCard.noteSignalPoll(mWifiInfo);
1152         millisecondsPass(29000);
1153         int disconnectionReason = 3;
1154         mWifiScoreCard.noteNonlocalDisconnect(WIFI_IFACE_NAME, disconnectionReason);
1155         millisecondsPass(1000);
1156         mWifiScoreCard.resetAllConnectionStates();
1157     }
1158 
checkShortConnectionOldPollingExample(NetworkConnectionStats stats)1159     private void checkShortConnectionOldPollingExample(NetworkConnectionStats stats) {
1160         assertEquals(1, stats.getCount(CNT_CONNECTION_ATTEMPT));
1161         assertEquals(0, stats.getCount(CNT_CONNECTION_FAILURE));
1162         assertEquals(0, stats.getCount(CNT_DISCONNECTION_NONLOCAL_CONNECTING));
1163         assertEquals(33, stats.getCount(CNT_CONNECTION_DURATION_SEC));
1164         assertEquals(0, stats.getCount(CNT_ASSOCIATION_REJECTION));
1165         assertEquals(0, stats.getCount(CNT_ASSOCIATION_TIMEOUT));
1166         assertEquals(0, stats.getCount(CNT_AUTHENTICATION_FAILURE));
1167         assertEquals(0, stats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
1168         assertEquals(0, stats.getCount(CNT_DISCONNECTION_NONLOCAL));
1169     }
1170 
1171     /**
1172      * Check network stats after RSSI poll and disconnection, pass FW alert check
1173      */
1174     @Test
testNetworkRssiPollShortNonlocalDisconnectionPassFwAlertCheck()1175     public void testNetworkRssiPollShortNonlocalDisconnectionPassFwAlertCheck() throws Exception {
1176         when(mDeviceConfigFacade.getHealthMonitorFwAlertValidTimeMs()).thenReturn(2000);
1177         // 1st connection session
1178         makeShortConnectionExample(/*addFwAlert*/true);
1179         // 2nd connection session
1180         makeNormalConnectionExample();
1181 
1182         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1183         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1184         assertEquals(2, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
1185         assertEquals(0, dailyStats.getCount(CNT_CONNECTION_FAILURE));
1186         assertEquals(20, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
1187         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
1188         assertEquals(0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
1189         assertEquals(0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
1190         assertEquals(1, dailyStats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
1191         assertEquals(1, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL));
1192     }
1193 
1194     /**
1195      * Check network stats after RSSI poll and disconnection, fail FW alert check
1196      */
1197     @Test
testNetworkRssiPollShortNonlocalDisconnectionFailFwAlertCheck()1198     public void testNetworkRssiPollShortNonlocalDisconnectionFailFwAlertCheck() throws Exception {
1199         when(mDeviceConfigFacade.getHealthMonitorFwAlertValidTimeMs()).thenReturn(2000);
1200         // 1st connection session
1201         makeShortConnectionExample(/*addFwAlert*/false);
1202         // 2nd connection session
1203         makeNormalConnectionExample();
1204 
1205         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1206         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1207         assertEquals(0, dailyStats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
1208         assertEquals(0, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL));
1209     }
1210 
1211     /**
1212      * Check network stats after short connection with an old RSSI polling
1213      */
1214     @Test
testShortNonlocalDisconnectionOldRssiPolling()1215     public void testShortNonlocalDisconnectionOldRssiPolling() throws Exception {
1216         makeShortConnectionOldRssiPollingExample();
1217         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1218         checkShortConnectionOldPollingExample(perNetwork.getRecentStats());
1219     }
1220 
makeNormalConnectionExample()1221     private void makeNormalConnectionExample() {
1222         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1223         millisecondsPass(1000);
1224         mWifiInfo.setRssi(-55);
1225         millisecondsPass(7000);
1226         mWifiScoreCard.noteSignalPoll(mWifiInfo);
1227         millisecondsPass(3000);
1228         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1229         mWifiScoreCard.resetAllConnectionStates();
1230     }
1231 
makeUpdateLinkBandwidthExample()1232     private void makeUpdateLinkBandwidthExample() {
1233         mWifiInfo.setRssi(-79);
1234         mWifiInfo.setFrequency(2437);
1235         mNewLlStats.on_time = 1000;
1236         mNewLlStats.timeStampInMs = 5_000;
1237         long txBytes = 2_000_000L;
1238         long rxBytes = 4_000_000L;
1239         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1240         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR; i++) {
1241             addTotalBytes(txBytes, rxBytes);
1242             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1243                     mTotalRxBytes);
1244         }
1245         mWifiInfo.setFrequency(5210);
1246         txBytes = 5_000_000L;
1247         rxBytes = 1000L;
1248         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
1249             addTotalBytes(txBytes, rxBytes);
1250             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1251                     mTotalRxBytes);
1252         }
1253     }
1254 
checkSerializationUpdateLinkBandwidthExample(BandwidthStatsAll stats)1255     private void checkSerializationUpdateLinkBandwidthExample(BandwidthStatsAll stats) {
1256         assertEquals(2_000_000L * 8 / 1000 * BANDWIDTH_STATS_COUNT_THR,
1257                 stats.getStats2G().getTx().getLevel(1).getValue());
1258         assertEquals(4_000_000L * 8 / 1000 * BANDWIDTH_STATS_COUNT_THR,
1259                 stats.getStats2G().getRx().getLevel(1).getValue());
1260         assertEquals(BANDWIDTH_STATS_COUNT_THR,
1261                 stats.getStats2G().getTx().getLevel(1).getCount());
1262         assertEquals(BANDWIDTH_STATS_COUNT_THR,
1263                 stats.getStats2G().getRx().getLevel(1).getCount());
1264 
1265         assertEquals(5_000_000L * 8 / 1000 * (BANDWIDTH_STATS_COUNT_THR + 2),
1266                 stats.getStatsAbove2G().getTx().getLevel(1).getValue());
1267         assertEquals(0, stats.getStatsAbove2G().getRx().getLevel(1).getValue());
1268         assertEquals(BANDWIDTH_STATS_COUNT_THR + 2,
1269                 stats.getStatsAbove2G().getTx().getLevel(1).getCount());
1270         assertEquals(0, stats.getStatsAbove2G().getRx().getLevel(1).getCount());
1271     }
1272 
1273     /**
1274      * Constructs a protobuf form of Network example.
1275      */
makeSerializedNetworkExample()1276     private byte[] makeSerializedNetworkExample() {
1277         makeDisconnectionConnectingExample(true);
1278         makeShortConnectionExample(true);
1279         makeUpdateLinkBandwidthExample();
1280         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1281         checkSerializationNetworkExample("before serialization", perNetwork);
1282         // Now convert to protobuf form
1283         byte[] serialized = perNetwork.toNetworkStats().toByteArray();
1284         return serialized;
1285     }
1286 
1287     /**
1288      * Checks that the fields of the network serialization example are as expected.
1289      */
checkSerializationNetworkExample(String diag, PerNetwork perNetwork)1290     private void checkSerializationNetworkExample(String diag, PerNetwork perNetwork) {
1291         NetworkConnectionStats dailyStats = perNetwork.getRecentStats();
1292 
1293         assertEquals(diag, 2, dailyStats.getCount(CNT_CONNECTION_ATTEMPT));
1294         assertEquals(diag, 1, dailyStats.getCount(CNT_CONNECTION_FAILURE));
1295         assertEquals(diag, 1, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL_CONNECTING));
1296         assertEquals(diag, 9, dailyStats.getCount(CNT_CONNECTION_DURATION_SEC));
1297         assertEquals(diag, 1, dailyStats.getCount(CNT_SHORT_CONNECTION_NONLOCAL));
1298         assertEquals(diag, 1, dailyStats.getCount(CNT_DISCONNECTION_NONLOCAL));
1299         assertEquals(diag, 0, dailyStats.getCount(CNT_ASSOCIATION_REJECTION));
1300         assertEquals(diag, 0, dailyStats.getCount(CNT_ASSOCIATION_TIMEOUT));
1301         assertEquals(diag, 0, dailyStats.getCount(CNT_AUTHENTICATION_FAILURE));
1302         assertEquals(diag, 0, dailyStats.getCount(CNT_CONSECUTIVE_WRONG_PASSWORD_FAILURE));
1303     }
1304 
1305     /**
1306      * Test NetworkStats serialization.
1307      */
1308     @Test
testNetworkStatsSerialization()1309     public void testNetworkStatsSerialization() throws Exception {
1310         byte[] serialized = makeSerializedNetworkExample();
1311 
1312         // Verify by parsing it and checking that we see the expected results
1313         NetworkStats ns = NetworkStats.parseFrom(serialized);
1314         ConnectionStats dailyStats = ns.getRecentStats();
1315         assertEquals(2, dailyStats.getNumConnectionAttempt());
1316         assertEquals(1, dailyStats.getNumConnectionFailure());
1317         assertEquals(1, dailyStats.getNumDisconnectionNonlocalConnecting());
1318         assertEquals(9, dailyStats.getConnectionDurationSec());
1319         assertEquals(1, dailyStats.getNumDisconnectionNonlocal());
1320         assertEquals(1, dailyStats.getNumShortConnectionNonlocal());
1321         assertEquals(0, dailyStats.getNumAssociationRejection());
1322         assertEquals(0, dailyStats.getNumAssociationTimeout());
1323         assertEquals(0, dailyStats.getNumAuthenticationFailure());
1324 
1325         checkSerializationUpdateLinkBandwidthExample(ns.getBandwidthStatsAll());
1326     }
1327 
1328     /**
1329      * Test NetworkStats Deserialization.
1330      */
1331     @Test
testNetworkStatsDeserialization()1332     public void testNetworkStatsDeserialization() throws Exception {
1333         byte[] serialized = makeSerializedNetworkExample();
1334         setUp(); // Get back to the initial state
1335 
1336         PerNetwork perNetwork = mWifiScoreCard.perNetworkFromNetworkStats(mWifiInfo.getSSID(),
1337                 NetworkStats.parseFrom(serialized));
1338 
1339         // Now verify
1340         String diag = hexStringFromByteArray(serialized);
1341         checkSerializationNetworkExample(diag, perNetwork);
1342     }
1343 
1344     /**
1345      * Check network stats after network connection and then removeNetWork().
1346      */
1347     @Test
testRemoveNetwork()1348     public void testRemoveNetwork() throws Exception {
1349         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1350         millisecondsPass(1000);
1351         mWifiScoreCard.noteConnectionFailure(mWifiInfo, -53, mWifiInfo.getSSID(),
1352                 WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION);
1353         mWifiScoreCard.removeNetwork(mWifiInfo.getSSID());
1354 
1355         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1356         assertNull(perNetwork);
1357     }
1358 
1359     @Test
testUpdateAfterDailyDetection()1360     public void testUpdateAfterDailyDetection() throws Exception {
1361         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1362             makeShortConnectionExample(/*addFwAlert*/false);
1363         }
1364 
1365         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1366         perNetwork.updateAfterDailyDetection();
1367 
1368         checkShortConnectionExample(perNetwork.getRecentStats(), 0);
1369         checkShortConnectionExample(perNetwork.getStatsCurrBuild(),
1370                 DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT);
1371         checkShortConnectionExample(perNetwork.getStatsPrevBuild(), 0);
1372     }
1373 
1374     @Test
testUpdateAfterSwBuildChange()1375     public void testUpdateAfterSwBuildChange() throws Exception {
1376         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1377             makeShortConnectionExample(/*addFwAlert*/false);
1378         }
1379         PerNetwork perNetwork = mWifiScoreCard.fetchByNetwork(mWifiInfo.getSSID());
1380         perNetwork.updateAfterDailyDetection();
1381         perNetwork.updateAfterSwBuildChange();
1382 
1383         checkShortConnectionExample(perNetwork.getRecentStats(), 0);
1384         checkShortConnectionExample(perNetwork.getStatsCurrBuild(), 0);
1385         checkShortConnectionExample(perNetwork.getStatsPrevBuild(),
1386                 DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT);
1387     }
1388 
makeRecentStatsWithGoodConnection()1389     private void makeRecentStatsWithGoodConnection() {
1390         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1391             makeNormalConnectionExample();
1392         }
1393     }
1394 
makeRecentStatsWithShortConnection()1395     private void makeRecentStatsWithShortConnection() {
1396         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1397             makeShortConnectionExample(/*addFwAlert*/false);
1398         }
1399     }
1400 
makeRecentStatsWithAssocTimeOut()1401     private void makeRecentStatsWithAssocTimeOut() {
1402         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1403             makeAssocTimeOutExample();
1404         }
1405     }
1406 
makeRecentStatsWithAuthFailure()1407     private void makeRecentStatsWithAuthFailure() {
1408         for (int i = 0; i < DEFAULT_HEALTH_MONITOR_MIN_NUM_CONNECTION_ATTEMPT; i++) {
1409             makeAuthFailureExample();
1410         }
1411     }
1412 
checkStatsDeltaExample(FailureStats stats, int scale)1413     private void checkStatsDeltaExample(FailureStats stats, int scale) {
1414         assertEquals(0, stats.getCount(REASON_ASSOC_REJECTION));
1415         assertEquals(1 * scale, stats.getCount(REASON_ASSOC_TIMEOUT));
1416         assertEquals(1 * scale, stats.getCount(REASON_AUTH_FAILURE));
1417         assertEquals(1 * scale, stats.getCount(REASON_CONNECTION_FAILURE));
1418         assertEquals(1 * scale, stats.getCount(REASON_DISCONNECTION_NONLOCAL));
1419         assertEquals(1 * scale, stats.getCount(REASON_SHORT_CONNECTION_NONLOCAL));
1420     }
1421 
1422     /**
1423      * Check if daily detection is skipped with insufficient daily stats.
1424      */
1425     @Test
testDailyDetectionWithInsufficientRecentStats()1426     public void testDailyDetectionWithInsufficientRecentStats() throws Exception {
1427         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1428         makeShortConnectionExample(/*addFwAlert*/false);
1429 
1430         FailureStats statsDec = new FailureStats();
1431         FailureStats statsInc = new FailureStats();
1432         FailureStats statsHigh = new FailureStats();
1433         int detectionFlag = perNetwork.dailyDetection(statsDec, statsInc, statsHigh);
1434         assertEquals(WifiScoreCard.INSUFFICIENT_RECENT_STATS, detectionFlag);
1435         checkStatsDeltaExample(statsDec, 0);
1436         checkStatsDeltaExample(statsInc, 0);
1437         checkStatsDeltaExample(statsHigh, 0);
1438         perNetwork.updateAfterDailyDetection();
1439         checkShortConnectionExample(perNetwork.getRecentStats(), 1);
1440         checkShortConnectionExample(perNetwork.getStatsPrevBuild(), 0);
1441         assertEquals(WifiHealthMonitor.REASON_NO_FAILURE,
1442                 mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID()));
1443     }
1444 
1445     /**
1446      * Run a few days with mostly good connection and some failures,
1447      * followed by a SW build change which results
1448      * in performance regression. Check if the regression is detected properly.
1449      */
1450     @Test
testRegressionAfterSwBuildChange()1451     public void testRegressionAfterSwBuildChange() throws Exception {
1452         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1453         int numGoodConnectionDays = 4;
1454         for (int i = 0; i < numGoodConnectionDays; i++) {
1455             makeRecentStatsWithGoodConnection();
1456             perNetwork.updateAfterDailyDetection();
1457         }
1458         // Extra day with mixed failures
1459         makeRecentStatsWithShortConnection();
1460         makeRecentStatsWithAssocTimeOut();
1461         makeRecentStatsWithAuthFailure();
1462         perNetwork.updateAfterDailyDetection();
1463 
1464         perNetwork.updateAfterSwBuildChange();
1465         // Add >2x failures after the SW build change
1466         int numBadConnectionDays = 4;
1467         for (int i = 0; i < numBadConnectionDays; i++) {
1468             makeRecentStatsWithAssocTimeOut();
1469             makeRecentStatsWithAuthFailure();
1470             makeRecentStatsWithShortConnection();
1471         }
1472 
1473         assertEquals(WifiHealthMonitor.REASON_SHORT_CONNECTION_NONLOCAL,
1474                 mWifiScoreCard.detectAbnormalDisconnection(WIFI_IFACE_NAME));
1475         FailureStats statsDec = new FailureStats();
1476         FailureStats statsInc = new FailureStats();
1477         FailureStats statsHigh = new FailureStats();
1478         int detectionFlag = perNetwork.dailyDetection(statsDec, statsInc, statsHigh);
1479         assertEquals(WifiScoreCard.SUFFICIENT_RECENT_PREV_STATS, detectionFlag);
1480         checkStatsDeltaExample(statsDec, 0);
1481         checkStatsDeltaExample(statsInc, 1);
1482         checkStatsDeltaExample(statsHigh, 0);
1483     }
1484 
1485     /**
1486      * Check regression detection is missed due to low failure count
1487      */
1488     @Test
testMissRegressionDetectionDuetoLowFailureCnt()1489     public void testMissRegressionDetectionDuetoLowFailureCnt() throws Exception {
1490         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1491         int numGoodConnectionDays = 1;
1492         for (int i = 0; i < numGoodConnectionDays; i++) {
1493             makeRecentStatsWithGoodConnection();
1494             perNetwork.updateAfterDailyDetection();
1495         }
1496 
1497         perNetwork.updateAfterSwBuildChange();
1498         makeRecentStatsWithGoodConnection();
1499         // Add a small number of failures for each failure type after the SW build change
1500         for (int i = 0; i < mDeviceConfigFacade.getAuthFailureCountMin() - 1; i++) {
1501             makeShortConnectionExample(/*addFwAlert*/false);
1502             makeAssocTimeOutExample();
1503             makeAuthFailureExample();
1504         }
1505 
1506         FailureStats statsDec = new FailureStats();
1507         FailureStats statsInc = new FailureStats();
1508         FailureStats statsHigh = new FailureStats();
1509         int detectionFlag = perNetwork.dailyDetection(statsDec, statsInc, statsHigh);
1510         assertEquals(WifiScoreCard.SUFFICIENT_RECENT_PREV_STATS, detectionFlag);
1511         checkStatsDeltaExample(statsDec, 0);
1512         checkStatsDeltaExample(statsInc, 0);
1513         checkStatsDeltaExample(statsHigh, 0);
1514         assertEquals(WifiHealthMonitor.REASON_NO_FAILURE,
1515                 mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID()));
1516     }
1517 
1518     /**
1519      * Run a few days with bad connections, followed by a SW build change which results
1520      * in performance improvement. Check if the improvement is detected properly.
1521      */
1522     @Test
testImprovementAfterSwBuildChange()1523     public void testImprovementAfterSwBuildChange() throws Exception {
1524         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1525         for (int i = 0; i < 2; i++) {
1526             makeRecentStatsWithShortConnection();
1527             makeRecentStatsWithAssocTimeOut();
1528             makeRecentStatsWithAuthFailure();
1529             perNetwork.updateAfterDailyDetection();
1530         }
1531 
1532         perNetwork.updateAfterSwBuildChange();
1533         // Add <50% failures after the SW build change
1534         int numGoodConnectionDays = 4;
1535         for (int i = 0; i < numGoodConnectionDays; i++) {
1536             makeRecentStatsWithGoodConnection();
1537         }
1538         makeRecentStatsWithAssocTimeOut();
1539         makeRecentStatsWithAuthFailure();
1540         makeRecentStatsWithShortConnection();
1541 
1542         assertEquals(WifiHealthMonitor.REASON_NO_FAILURE,
1543                 mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID()));
1544         FailureStats statsDec = new FailureStats();
1545         FailureStats statsInc = new FailureStats();
1546         FailureStats statsHigh = new FailureStats();
1547         perNetwork.dailyDetection(statsDec, statsInc, statsHigh);
1548         checkStatsDeltaExample(statsDec, 1);
1549         checkStatsDeltaExample(statsInc, 0);
1550         checkStatsDeltaExample(statsHigh, 0);
1551     }
1552 
1553     @Test
testPoorConnectionWithoutHistory()1554     public void testPoorConnectionWithoutHistory() throws Exception {
1555         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1556 
1557         makeRecentStatsWithShortConnection(); // Day 1
1558         makeRecentStatsWithAuthFailure();
1559         makeRecentStatsWithAssocTimeOut();
1560 
1561         assertEquals(WifiHealthMonitor.REASON_ASSOC_TIMEOUT,
1562                 mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID()));
1563         FailureStats statsDec = new FailureStats();
1564         FailureStats statsInc = new FailureStats();
1565         FailureStats statsHigh = new FailureStats();
1566         int detectionFlag = perNetwork.dailyDetection(statsDec, statsInc, statsHigh);
1567         assertEquals(WifiScoreCard.SUFFICIENT_RECENT_STATS_ONLY, detectionFlag);
1568         checkStatsDeltaExample(statsDec, 0);
1569         checkStatsDeltaExample(statsInc, 0);
1570         checkStatsDeltaExample(statsHigh, 1);
1571     }
1572 
1573     @Test
testHighAuthFailureRate()1574     public void testHighAuthFailureRate() throws Exception {
1575         makeRecentStatsWithGoodConnection();
1576         makeRecentStatsWithAuthFailure();
1577         assertEquals(WifiHealthMonitor.REASON_AUTH_FAILURE,
1578                 mWifiScoreCard.detectAbnormalConnectionFailure(mWifiInfo.getSSID()));
1579     }
1580 
1581     @Test
testAddGetFrequencies()1582     public void testAddGetFrequencies() {
1583         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1584         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1585         millisecondsPass(100);
1586         perNetwork.addFrequency(5805);
1587         millisecondsPass(1000);
1588         perNetwork.addFrequency(2432);
1589         assertEquals(2, perNetwork.getFrequencies(Long.MAX_VALUE).size());
1590         assertEquals(2432, (int) perNetwork.getFrequencies(Long.MAX_VALUE).get(0));
1591         assertEquals(5805, (int) perNetwork.getFrequencies(Long.MAX_VALUE).get(1));
1592         // Check over aged channel will not return.
1593         assertEquals(1, perNetwork.getFrequencies(900L).size());
1594         assertEquals(2432, (int) perNetwork.getFrequencies(Long.MAX_VALUE).get(0));
1595     }
1596 
addTotalBytes(long txBytes, long rxBytes)1597     private void addTotalBytes(long txBytes, long rxBytes) {
1598         mTotalTxBytes += txBytes;
1599         mTotalRxBytes += rxBytes;
1600     }
1601 
subtractTotalBytes(long txBytes, long rxBytes)1602     private void subtractTotalBytes(long txBytes, long rxBytes) {
1603         mTotalTxBytes -= txBytes;
1604         mTotalRxBytes -= rxBytes;
1605     }
1606 
1607     @Test
testLinkBandwidthTwoRadioStatsVariousTxTraffic()1608     public void testLinkBandwidthTwoRadioStatsVariousTxTraffic() {
1609         mWifiInfo.setRssi(-70);
1610         mWifiInfo.setFrequency(2437);
1611         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1612         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1613         mNewLlStats.on_time = 3000;
1614         mOldLlStats.radioStats = new WifiLinkLayerStats.RadioStat[2];
1615         mOldLlStats.radioStats[0] = new WifiLinkLayerStats.RadioStat();
1616         mOldLlStats.radioStats[1] = new WifiLinkLayerStats.RadioStat();
1617         mNewLlStats.radioStats = new WifiLinkLayerStats.RadioStat[2];
1618         mNewLlStats.radioStats[0] = new WifiLinkLayerStats.RadioStat();
1619         mNewLlStats.radioStats[1] = new WifiLinkLayerStats.RadioStat();
1620         mNewLlStats.radioStats[0].on_time = 500;
1621         mNewLlStats.radioStats[1].on_time = 500;
1622         mOldLlStats.timeStampInMs = 7_000;
1623         mNewLlStats.timeStampInMs = 10_000;
1624         long txBytes = 350_000L;
1625         long rxBytes = 4_000_000L;
1626         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR - 1; i++) {
1627             addTotalBytes(txBytes, rxBytes);
1628             millisecondsPass(3_000);
1629             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1630                     mTotalRxBytes);
1631         }
1632 
1633         assertEquals(10_000, perNetwork.getTxLinkBandwidthKbps());
1634         assertEquals(32_000, perNetwork.getRxLinkBandwidthKbps());
1635 
1636         txBytes = 400_000L;
1637         rxBytes = 200_000L;
1638         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR - 1; i++) {
1639             addTotalBytes(txBytes, rxBytes);
1640             millisecondsPass(3_000);
1641             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1642                     mTotalRxBytes);
1643         }
1644 
1645         assertEquals(3_200, perNetwork.getTxLinkBandwidthKbps());
1646     }
1647 
1648     @Test
testLinkBandwidthTwoBssidThreeSignalLevelOneBand()1649     public void testLinkBandwidthTwoBssidThreeSignalLevelOneBand() {
1650         mWifiInfo.setRssi(-70);
1651         mWifiInfo.setFrequency(2437);
1652         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1653         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1654         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1655         mNewLlStats.on_time = 1000;
1656         mOldLlStats.timeStampInMs = 7_000;
1657         mNewLlStats.timeStampInMs = 10_000;
1658         long txBytes = 2_000_000L;
1659         long rxBytes = 4_000_000L;
1660         // Add BANDWIDTH_STATS_COUNT_THR - 2 polls at BSSID 1 at 1st level
1661         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR - 2; i++) {
1662             addTotalBytes(txBytes, rxBytes);
1663             millisecondsPass(3_000);
1664             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1665                     mTotalRxBytes);
1666         }
1667         // Add BANDWIDTH_STATS_COUNT_THR - 2 polls at BSSID 2 at 2nd level
1668         mWifiInfo.setBSSID(TEST_BSSID_2.toString());
1669         mNewLlStats.on_time = 2000;
1670         mWifiInfo.setRssi(-54);
1671         txBytes = 6_000_000L;
1672         rxBytes = 100_000L;
1673         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR - 2; i++) {
1674             addTotalBytes(txBytes, rxBytes);
1675             millisecondsPass(3_000);
1676             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1677                     mTotalRxBytes);
1678         }
1679 
1680         // Add BANDWIDTH_STATS_COUNT_THR - 2 polls at BSSID 2 at 3rd level
1681         rxBytes = 4_000_000L;
1682         mWifiInfo.setRssi(-65);
1683         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR - 2; i++) {
1684             addTotalBytes(txBytes, rxBytes);
1685             millisecondsPass(3_000);
1686             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1687                     mTotalRxBytes);
1688         }
1689 
1690         assertEquals(23_619, perNetwork.getTxLinkBandwidthKbps());
1691         assertEquals(16_677, perNetwork.getRxLinkBandwidthKbps());
1692     }
1693 
1694 
1695     @Test
testLinkBandwidthAfterLongTimeGap()1696     public void testLinkBandwidthAfterLongTimeGap() {
1697         mWifiInfo.setRssi(-70);
1698         mWifiInfo.setFrequency(2437);
1699         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1700         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1701         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1702         mNewLlStats.on_time = 1000;
1703         mOldLlStats.timeStampInMs = 7_000;
1704         mNewLlStats.timeStampInMs = 10_000;
1705         long txBytes = 2_000_000L;
1706         long rxBytes = 4_000_000L;
1707         // Add BANDWIDTH_STATS_COUNT_THR polls with regular interval
1708         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR * 2; i++) {
1709             addTotalBytes(txBytes * i, rxBytes * i);
1710             millisecondsPass(3_000);
1711             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1712                     mTotalRxBytes);
1713         }
1714         // One update with a very large time interval
1715         mWifiInfo.setRssi(-64);
1716         addTotalBytes(txBytes, rxBytes);
1717         millisecondsPass(26 * 24 * 3_600_000L);
1718         perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1719                 mTotalRxBytes);
1720         assertEquals(16_000, perNetwork.getTxLinkBandwidthKbps());
1721         assertEquals(32_000, perNetwork.getRxLinkBandwidthKbps());
1722     }
1723 
1724     @Test
testLinkBandwidthInvalidTrafficStats()1725     public void testLinkBandwidthInvalidTrafficStats() {
1726         mWifiInfo.setRssi(-70);
1727         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1728         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1729         mWifiInfo.setFrequency(5210);
1730         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1731         mNewLlStats.on_time = 1000;
1732         mOldLlStats.timeStampInMs = 7_000;
1733         mNewLlStats.timeStampInMs = 10_000;
1734         long txBytes = 2_000_000L;
1735         long rxBytes = 100_000L;
1736         int[] reportedKbps = new int[]{400_000, 300_000};
1737         int[] l2Kbps = new int[]{800_000, 700_000};
1738         // Add BANDWIDTH_STATS_COUNT_THR polls with one of them has invalid traffic stats
1739         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR; i++) {
1740             if (i == 1) {
1741                 subtractTotalBytes(txBytes, rxBytes);
1742             } else {
1743                 addTotalBytes(txBytes, rxBytes);
1744             }
1745             millisecondsPass(3_000);
1746             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1747                     mTotalRxBytes);
1748             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1749         }
1750 
1751         assertEquals(16_000, perNetwork.getTxLinkBandwidthKbps());
1752         assertEquals(LINK_BANDWIDTH_INIT_KBPS[1][LINK_RX][2], perNetwork.getRxLinkBandwidthKbps());
1753         BandwidthEstimatorStats stats = mWifiScoreCard.dumpBandwidthEstimatorStats();
1754         assertEquals(0, stats.stats2G.tx.level.length);
1755         assertEquals(0, stats.stats2G.rx.level.length);
1756     }
1757 
1758     @Test
testLinkBandwidthOneBssidTwoSignalLevelTwoBand()1759     public void testLinkBandwidthOneBssidTwoSignalLevelTwoBand() {
1760         mWifiInfo.setRssi(-70);
1761         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1762         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1763         mWifiInfo.setFrequency(5210);
1764         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1765         mNewLlStats.on_time = 1000;
1766         mOldLlStats.timeStampInMs = 7_000;
1767         mNewLlStats.timeStampInMs = 10_000;
1768         long txBytes = 2_000_000L;
1769         long rxBytes = 100_000L;
1770         int [] reportedKbps = new int[]{40_000, 30_000};
1771         int [] l2Kbps = new int[]{80_000, 70_000};
1772         // Add BANDWIDTH_STATS_COUNT_THR polls at 1st level and 1st band
1773         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR; i++) {
1774             addTotalBytes(txBytes, rxBytes);
1775             millisecondsPass(3_000);
1776             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1777                     mTotalRxBytes);
1778             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1779         }
1780         // Add BANDWIDTH_STATS_COUNT_THR polls at 2nd level and 1st band
1781         mWifiInfo.setRssi(-65);
1782         rxBytes = 7_000_000L;
1783         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR; i++) {
1784             addTotalBytes(txBytes, rxBytes);
1785             millisecondsPass(3_000);
1786             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1787                     mTotalRxBytes);
1788             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1789         }
1790 
1791         // Add BANDWIDTH_STATS_COUNT_THR * 2 polls at 1st level and 2nd band
1792         mWifiInfo.setRssi(-70);
1793         mWifiInfo.setFrequency(2437);
1794         txBytes = 6_000_000L;
1795         mNewLlStats.on_time = 2000;
1796         for (int i = 0; i < (2 * BANDWIDTH_STATS_COUNT_THR); i++) {
1797             addTotalBytes(txBytes, rxBytes);
1798             millisecondsPass(3_000);
1799             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1800                     mTotalRxBytes);
1801             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1802         }
1803 
1804         // Expect stats of 1st level and 2nd band are used
1805         assertEquals(23_949, perNetwork.getTxLinkBandwidthKbps());
1806         assertEquals(28_173, perNetwork.getRxLinkBandwidthKbps());
1807 
1808         BandwidthEstimatorStats stats = mWifiScoreCard.dumpBandwidthEstimatorStats();
1809         assertEquals(1, stats.stats2G.tx.level.length);
1810         assertEquals(1, stats.stats2G.rx.level.length);
1811 
1812         assertEquals(2, stats.stats2G.rx.level[0].signalLevel);
1813         assertEquals(BANDWIDTH_STATS_COUNT_THR - 1, stats.stats2G.rx.level[0].count);
1814         assertEquals(28_000, stats.stats2G.rx.level[0].avgBandwidthKbps);
1815         assertEquals(150, stats.stats2G.rx.level[0].l2ErrorPercent);
1816         assertEquals(7, stats.stats2G.rx.level[0].bandwidthEstErrorPercent);
1817 
1818         assertEquals(2, stats.stats2G.tx.level[0].signalLevel);
1819         assertEquals(BANDWIDTH_STATS_COUNT_THR - 1, stats.stats2G.tx.level[0].count);
1820         assertEquals(24_000, stats.stats2G.tx.level[0].avgBandwidthKbps);
1821         assertEquals(233, stats.stats2G.tx.level[0].l2ErrorPercent);
1822         assertEquals(66, stats.stats2G.tx.level[0].bandwidthEstErrorPercent);
1823 
1824         assertEquals(0, stats.statsAbove2G.tx.level.length);
1825         assertEquals(0, stats.statsAbove2G.rx.level.length);
1826     }
1827 
1828     @Test
testLinkBandwidthLargeByteCountReturnNonNegativeValue()1829     public void testLinkBandwidthLargeByteCountReturnNonNegativeValue() {
1830         mWifiInfo.setRssi(-70);
1831         mWifiInfo.setRxLinkSpeedMbps(200_000);
1832         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1833         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1834         mWifiInfo.setFrequency(5210);
1835         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1836         mOldLlStats.timeStampInMs = 7_000;
1837         mNewLlStats.timeStampInMs = 10_000;
1838         long txBytes = 8_000_000_000L;
1839         long rxBytes = 16_000_000_000L;
1840         int [] reportedKbps = new int[]{400_000, 300_000};
1841         int [] l2Kbps = new int[]{800_000, 700_000};
1842 
1843         // Report a small on_time so that the calculated BW overflows at 5G
1844         mNewLlStats.on_time = 10;
1845         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
1846             addTotalBytes(txBytes, rxBytes);
1847             millisecondsPass(3_000);
1848             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1849                     mTotalRxBytes);
1850             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1851         }
1852         // Report a larger on_time so that the calculated BW won't overflows at 2G
1853         mWifiInfo.setFrequency(2412);
1854         mNewLlStats.on_time = 1000;
1855         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
1856             addTotalBytes(txBytes, rxBytes);
1857             millisecondsPass(3_000);
1858             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1859                     mTotalRxBytes);
1860             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1861         }
1862 
1863         // Report cold start BW for Tx because the calculated value is higher than
1864         // txLinkSpeedMbps.
1865         assertEquals(10_000, perNetwork.getTxLinkBandwidthKbps());
1866         assertEquals(128_000_000, perNetwork.getRxLinkBandwidthKbps());
1867 
1868         BandwidthEstimatorStats stats = mWifiScoreCard.dumpBandwidthEstimatorStats();
1869         assertEquals(0, stats.statsAbove2G.tx.level.length);
1870         assertEquals(0, stats.statsAbove2G.rx.level.length);
1871         assertEquals(0, stats.stats2G.tx.level.length);
1872         assertEquals(1, stats.stats2G.rx.level.length);
1873         assertEquals(128_000_000, stats.stats2G.rx.level[0].avgBandwidthKbps);
1874         assertEquals(1, stats.stats2G.rx.level[0].count);
1875 
1876         mNewLlStats.on_time = 2000;
1877         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
1878             addTotalBytes(txBytes, rxBytes);
1879             millisecondsPass(3_000);
1880             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1881                     mTotalRxBytes);
1882             perNetwork.updateBwMetrics(reportedKbps, l2Kbps);
1883         }
1884         stats = mWifiScoreCard.dumpBandwidthEstimatorStats();
1885         assertEquals(64_000_000, stats.stats2G.rx.level[0].avgBandwidthKbps);
1886         assertEquals(BANDWIDTH_STATS_COUNT_THR + 2, stats.stats2G.rx.level[0].count);
1887     }
1888 
1889     @Test
testLinkBandwidthInvalidBytes()1890     public void testLinkBandwidthInvalidBytes() {
1891         mWifiInfo.setRssi(-70);
1892         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1893         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1894         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1895         mOldLlStats.timeStampInMs = 7_000;
1896         mNewLlStats.timeStampInMs = 10_000;
1897         long txBytes = 8_000_000_000L;
1898         long rxBytes = 16_000_000_000L;
1899         mWifiInfo.setFrequency(2412);
1900         mNewLlStats.on_time = 1000;
1901         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR + 2; i++) {
1902             addTotalBytes(txBytes, rxBytes);
1903             millisecondsPass(3_000);
1904             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1905                     mTotalRxBytes);
1906         }
1907         assertEquals(10_000, perNetwork.getTxLinkBandwidthKbps());
1908         assertEquals(10_000, perNetwork.getRxLinkBandwidthKbps());
1909     }
1910 
1911     @Test
testLinkBandwidthLowOnTimeHighSignalLevel()1912     public void testLinkBandwidthLowOnTimeHighSignalLevel() {
1913         // Add polls with zero on_time and high signal level
1914         mWifiInfo.setRssi(-53);
1915         int signalLevel = RssiUtil.calculateSignalLevel(mContext, mWifiInfo.getRssi());
1916         mWifiInfo.setFrequency(5210);
1917         mWifiScoreCard.noteConnectionAttempt(mWifiInfo, -53, mWifiInfo.getSSID());
1918         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1919         mWifiInfo.setFrequency(5210);
1920         mWifiScoreCard.noteIpConfiguration(mWifiInfo);
1921         mNewLlStats.on_time = 5;
1922         mOldLlStats.timeStampInMs = 7_000;
1923         mNewLlStats.timeStampInMs = 10_000;
1924         long txBytes = 2_000_000L;
1925         long rxBytes = 100_000L;
1926         for (int i = 0; i < BANDWIDTH_STATS_COUNT_THR; i++) {
1927             addTotalBytes(txBytes, rxBytes);
1928             millisecondsPass(3_000);
1929             perNetwork.updateLinkBandwidth(mOldLlStats, mNewLlStats, mWifiInfo, mTotalTxBytes,
1930                     mTotalRxBytes);
1931         }
1932 
1933         // Expect cold-start value
1934         assertEquals(LINK_BANDWIDTH_INIT_KBPS[1][LINK_TX][signalLevel],
1935                 perNetwork.getTxLinkBandwidthKbps());
1936         assertEquals(LINK_BANDWIDTH_INIT_KBPS[1][LINK_RX][signalLevel],
1937                 perNetwork.getRxLinkBandwidthKbps());
1938     }
1939 
1940     @Test
testGetLinkBandwidthWithoutUpdateReturnLevel0Band0Value()1941     public void testGetLinkBandwidthWithoutUpdateReturnLevel0Band0Value() {
1942         PerNetwork perNetwork = mWifiScoreCard.lookupNetwork(mWifiInfo.getSSID());
1943 
1944         // Call getLinkBandwidth() without updateLinkBandwidth()
1945         // Expect cold-start value at level 0 and band 0
1946         assertEquals(LINK_BANDWIDTH_INIT_KBPS[0][LINK_TX][0],
1947                 perNetwork.getTxLinkBandwidthKbps());
1948         assertEquals(LINK_BANDWIDTH_INIT_KBPS[0][LINK_RX][0],
1949                 perNetwork.getRxLinkBandwidthKbps());
1950     }
1951 }
1952