Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2016 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 org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertTrue;
     21 import static org.mockito.Mockito.*;
     22 import static org.mockito.MockitoAnnotations.*;
     23 
     24 import android.net.wifi.WifiConfiguration;
     25 import android.net.wifi.WifiSsid;
     26 import android.os.test.TestLooper;
     27 import android.support.test.filters.SmallTest;
     28 import android.util.Pair;
     29 
     30 import org.junit.Before;
     31 import org.junit.Test;
     32 import org.mockito.Mock;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.List;
     37 
     38 /**
     39  * Unit tests for {@link com.android.server.wifi.WifiLastResortWatchdog}.
     40  */
     41 @SmallTest
     42 public class WifiLastResortWatchdogTest {
     43     WifiLastResortWatchdog mLastResortWatchdog;
     44     @Mock WifiMetrics mWifiMetrics;
     45     @Mock SelfRecovery mSelfRecovery;
     46     @Mock WifiStateMachine mWifiStateMachine;
     47     @Mock Clock mClock;
     48 
     49     private String[] mSsids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
     50     private String[] mBssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
     51             "c0:ff:ee:ee:e3:ee"};
     52     private int[] mFrequencies = {2437, 5180, 5180, 2437};
     53     private String[] mCaps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
     54             "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
     55     private int[] mLevels = {-60, -86, -50, -62};
     56     private boolean[] mIsEphemeral = {false, false, false, false};
     57     private boolean[] mHasEverConnected = {false, false, false, false};
     58     private TestLooper mLooper;
     59 
     60     @Before
     61     public void setUp() throws Exception {
     62         initMocks(this);
     63         mLooper = new TestLooper();
     64         mLastResortWatchdog = new WifiLastResortWatchdog(mSelfRecovery, mClock, mWifiMetrics,
     65                 mWifiStateMachine, mLooper.getLooper());
     66         mLastResortWatchdog.setBugReportProbability(1);
     67     }
     68 
     69     private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids,
     70             String[] bssids, int[] frequencies, String[] caps, int[] levels,
     71             boolean[] isEphemeral) {
     72         List<Pair<ScanDetail, WifiConfiguration>> candidates = new ArrayList<>();
     73         long timeStamp = System.currentTimeMillis();
     74         for (int index = 0; index < ssids.length; index++) {
     75             String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", "");
     76             ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
     77                     bssids[index], caps[index], levels[index], frequencies[index], timeStamp,
     78                     0);
     79             WifiConfiguration config = null;
     80             if (!isEphemeral[index]) {
     81                 config = mock(WifiConfiguration.class);
     82                 WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
     83                         mock(WifiConfiguration.NetworkSelectionStatus.class);
     84                 when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus);
     85                 when(networkSelectionStatus.getHasEverConnected()).thenReturn(true);
     86             }
     87             candidates.add(Pair.create(scanDetail, config));
     88         }
     89         return candidates;
     90     }
     91 
     92     private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids,
     93             String[] bssids, int[] frequencies, String[] caps, int[] levels,
     94             boolean[] isEphemeral, boolean[] hasEverConnected) {
     95         List<Pair<ScanDetail, WifiConfiguration>> candidates =
     96                 new ArrayList<Pair<ScanDetail, WifiConfiguration>>();
     97         long timeStamp = System.currentTimeMillis();
     98         for (int index = 0; index < ssids.length; index++) {
     99             String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", "");
    100             ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
    101                     bssids[index], caps[index], levels[index], frequencies[index], timeStamp,
    102                     0);
    103             WifiConfiguration config = null;
    104             if (!isEphemeral[index]) {
    105                 config = mock(WifiConfiguration.class);
    106                 WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
    107                         mock(WifiConfiguration.NetworkSelectionStatus.class);
    108                 when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus);
    109                 when(networkSelectionStatus.getHasEverConnected())
    110                         .thenReturn(hasEverConnected[index]);
    111             }
    112             candidates.add(Pair.create(scanDetail, config));
    113         }
    114         return candidates;
    115     }
    116 
    117     private void assertFailureCountEquals(
    118             String bssid, int associationRejections, int authenticationFailures, int dhcpFailures) {
    119         assertEquals(associationRejections, mLastResortWatchdog.getFailureCount(bssid,
    120                 WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION));
    121         assertEquals(authenticationFailures, mLastResortWatchdog.getFailureCount(bssid,
    122                 WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION));
    123         assertEquals(dhcpFailures, mLastResortWatchdog.getFailureCount(bssid,
    124                 WifiLastResortWatchdog.FAILURE_CODE_DHCP));
    125     }
    126 
    127     /**
    128      * Case #1: Test aging works in available network buffering
    129      * This test simulates 4 networks appearing in a scan result, and then only the first 2
    130      * appearing in successive scans results.
    131      * Expected Behavior:
    132      * 4 networks appear in recentAvailalbeNetworks, after N=MAX_BSSID_AGE scans, only 2 remain
    133      */
    134     @Test
    135     public void testAvailableNetworkBuffering_ageCullingWorks() throws Exception {
    136         // Buffer potential candidates 1,2,3 & 4
    137         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    138                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral);
    139         mLastResortWatchdog.updateAvailableNetworks(candidates);
    140         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
    141 
    142         // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times
    143         candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2),
    144                 Arrays.copyOfRange(mBssids, 0, 2),
    145                 Arrays.copyOfRange(mFrequencies, 0, 2),
    146                 Arrays.copyOfRange(mCaps, 0, 2),
    147                 Arrays.copyOfRange(mLevels, 0, 2),
    148                 Arrays.copyOfRange(mIsEphemeral, 0, 2));
    149         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) {
    150             mLastResortWatchdog.updateAvailableNetworks(candidates);
    151             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0);
    152             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0);
    153             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age,
    154                     i + 1);
    155             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age,
    156                     i + 1);
    157         }
    158         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
    159 
    160         // One more buffering should age and cull candidates 2 & 3
    161         mLastResortWatchdog.updateAvailableNetworks(candidates);
    162         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 2);
    163     };
    164 
    165     /**
    166      * Case #2: Culling of old networks
    167      * Part 1:
    168      * This test starts with 4 networks seen, it then buffers N=MAX_BSSID_AGE empty scans
    169      * Expected behaviour: All networks are culled from recentAvailableNetworks
    170      *
    171      * Part 2:
    172      * Buffer some more empty scans just to make sure nothing breaks
    173      */
    174     @Test
    175     public void testAvailableNetworkBuffering_emptyBufferWithEmptyScanResults() throws Exception {
    176         // Buffer potential candidates 1,2,3 & 4
    177         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    178                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral);
    179         mLastResortWatchdog.updateAvailableNetworks(candidates);
    180         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
    181 
    182         // Repeatedly buffer with no candidates
    183         candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 0),
    184                 Arrays.copyOfRange(mBssids, 0, 0),
    185                 Arrays.copyOfRange(mFrequencies, 0, 0),
    186                 Arrays.copyOfRange(mCaps, 0, 0),
    187                 Arrays.copyOfRange(mLevels, 0, 0),
    188                 Arrays.copyOfRange(mIsEphemeral, 0, 0));
    189         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
    190             mLastResortWatchdog.updateAvailableNetworks(candidates);
    191         }
    192         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 0);
    193         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
    194             mLastResortWatchdog.updateAvailableNetworks(candidates);
    195         }
    196         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 0);
    197     };
    198 
    199     /**
    200      * Case 3: Adding more networks over time
    201      * In this test, each successive (4 total) scan result buffers one more network.
    202      * Expected behavior: recentAvailableNetworks grows with number of scan results
    203      */
    204     @Test
    205     public void testAvailableNetworkBuffering_addNewNetworksOverTime() throws Exception {
    206         List<Pair<ScanDetail, WifiConfiguration>> candidates;
    207         // Buffer (i) scan results with each successive scan result
    208         for (int i = 1; i <= mSsids.length; i++) {
    209             candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, i),
    210                     Arrays.copyOfRange(mBssids, 0, i),
    211                     Arrays.copyOfRange(mFrequencies, 0, i),
    212                     Arrays.copyOfRange(mCaps, 0, i),
    213                     Arrays.copyOfRange(mLevels, 0, i),
    214                     Arrays.copyOfRange(mIsEphemeral, 0, i));
    215             mLastResortWatchdog.updateAvailableNetworks(candidates);
    216             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), i);
    217             for (int j = 0; j < i; j++) {
    218                 assertEquals(
    219                         mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[j]).age, 0);
    220             }
    221         }
    222     };
    223 
    224     /**
    225      *  Case 4: Test buffering with ephemeral networks & toString()
    226      *  This test is the same as Case 1, but it also includes ephemeral networks. toString is also
    227      *  smoke tested at various places in this test
    228      *  Expected behaviour: 4 networks added initially (2 ephemeral). After MAX_BSSID_AGE more
    229      *  bufferings, 2 are culled (leaving 1 ephemeral, one normal). toString method should execute
    230      *  without breaking anything.
    231      */
    232     @Test
    233     public void testAvailableNetworkBuffering_multipleNetworksSomeEphemeral() throws Exception {
    234         boolean[] isEphemeral = {true, false, true, false};
    235 
    236         // Buffer potential candidates 1,2,3 & 4
    237         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    238                 mBssids, mFrequencies, mCaps, mLevels, isEphemeral);
    239         mLastResortWatchdog.updateAvailableNetworks(candidates);
    240         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
    241 
    242         // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times
    243         candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2),
    244                 Arrays.copyOfRange(mBssids, 0, 2),
    245                 Arrays.copyOfRange(mFrequencies, 0, 2),
    246                 Arrays.copyOfRange(mCaps, 0, 2),
    247                 Arrays.copyOfRange(mLevels, 0, 2),
    248                 Arrays.copyOfRange(isEphemeral, 0, 2));
    249         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) {
    250             mLastResortWatchdog.updateAvailableNetworks(candidates);
    251             mLastResortWatchdog.toString();
    252             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0);
    253             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0);
    254             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age,
    255                     i + 1);
    256             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age,
    257                     i + 1);
    258         }
    259         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
    260 
    261         // One more buffering should age and cull candidates 2 & 3
    262         mLastResortWatchdog.updateAvailableNetworks(candidates);
    263         assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 2);
    264         mLastResortWatchdog.toString();
    265     };
    266 
    267     /**
    268      * Case 5: Test failure counting, incrementing a specific BSSID
    269      * Test has 4 networks buffered, increment each different failure type on one of them
    270      * Expected behaviour: See failure counts for the specific failures rise to the appropriate
    271      * level for the specific network
    272      */
    273     @Test
    274     public void testFailureCounting_countFailuresForSingleBssid() throws Exception {
    275         int associationRejections = 5;
    276         int authenticationFailures = 9;
    277         int dhcpFailures = 11;
    278         // Buffer potential candidates 1,2,3 & 4
    279         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    280                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    281         mLastResortWatchdog.updateAvailableNetworks(candidates);
    282 
    283         // Ensure new networks have zero'ed failure counts
    284         for (int i = 0; i < mSsids.length; i++) {
    285             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    286         }
    287 
    288         //Increment failure count for each network and failure type
    289         int net = 0;
    290         for (int i = 0; i < associationRejections; i++) {
    291             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    292                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    293             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    294                     .get(mBssids[net]).associationRejection);
    295         }
    296         net = 1;
    297         for (int i = 0; i < authenticationFailures; i++) {
    298             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    299                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    300             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    301                     .get(mBssids[net]).authenticationFailure);
    302         }
    303         net = 2;
    304         for (int i = 0; i < dhcpFailures; i++) {
    305             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    306                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    307             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    308                     .get(mBssids[net]).dhcpFailure);
    309         }
    310         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    311         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    312         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    313         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    314     }
    315 
    316     /**
    317      * Case 6: Test failure counting, incrementing a specific BSSID, with some ephemeral networks
    318      * Almost identical to test case 5.
    319      * Test has 4 networks buffered (two are ephemeral), increment each different failure type on
    320      * one of them.
    321      * Expected behavior: See failure counts for the specific failures rise to the appropriate
    322      * level for the specific network
    323      */
    324     @Test
    325     public void testFailureCounting_countFailuresForSingleBssidWithEphemeral() throws Exception {
    326         int associationRejections = 5;
    327         int authenticationFailures = 9;
    328         int dhcpFailures = 11;
    329         boolean[] mIsEphemeral = {false, true, false, true};
    330         // Buffer potential candidates 1,2,3 & 4
    331         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    332                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    333         mLastResortWatchdog.updateAvailableNetworks(candidates);
    334 
    335         // Ensure new networks have zero'ed failure counts
    336         for (int i = 0; i < mSsids.length; i++) {
    337             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    338         }
    339 
    340         //Increment failure count for each network and failure type
    341         int net = 0;
    342         for (int i = 0; i < associationRejections; i++) {
    343             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    344                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    345             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
    346                     .get(mBssids[net]).associationRejection, i + 1);
    347         }
    348         net = 1;
    349         for (int i = 0; i < authenticationFailures; i++) {
    350             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    351                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    352             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
    353                     .get(mBssids[net]).authenticationFailure, i + 1);
    354         }
    355         net = 2;
    356         for (int i = 0; i < dhcpFailures; i++) {
    357             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    358                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    359             assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
    360                     .get(mBssids[net]).dhcpFailure, i + 1);
    361         }
    362         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    363         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    364         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    365         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    366     }
    367 
    368     /**
    369      * Case 7: Test failure counting, incrementing a specific BSSID but with the wrong SSID given
    370      * Test has 4 networks buffered, increment each different failure type on one of them but using
    371      * the wrong ssid.
    372      * Expected behavior: Failure counts will remain at zero for all networks
    373      */
    374     @Test
    375     public void testFailureCounting_countFailuresForSingleBssidWrongSsid() throws Exception {
    376         String badSsid = "ItHertzWhenIP";
    377         int associationRejections = 5;
    378         int authenticationFailures = 9;
    379         int dhcpFailures = 11;
    380         // Buffer potential candidates 1,2,3 & 4
    381         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    382                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    383         mLastResortWatchdog.updateAvailableNetworks(candidates);
    384 
    385         // Ensure new networks have zero'ed failure counts
    386         for (int i = 0; i < mSsids.length; i++) {
    387             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    388         }
    389 
    390         //Increment failure count for each network and failure type
    391         int net = 0;
    392         for (int i = 0; i < associationRejections; i++) {
    393             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
    394                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    395         }
    396         net = 1;
    397         for (int i = 0; i < authenticationFailures; i++) {
    398             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
    399                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    400         }
    401         net = 2;
    402         for (int i = 0; i < dhcpFailures; i++) {
    403             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
    404                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    405         }
    406 
    407         // Ensure all networks still have zero failure count
    408         for (int i = 0; i < mSsids.length; i++) {
    409             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    410         }
    411     }
    412 
    413     /**
    414      * Case 8: Test failure counting, increment a bssid that does not exist
    415      * Test has 4 networks buffered, increment each failure type, but using the wrong bssid
    416      * Expected behavior: Failure counts will remain at zero for all networks
    417      */
    418     @Test
    419     public void testFailureCounting_countFailuresForNonexistentBssid() throws Exception {
    420         String badBssid = "de:ad:be:ee:e3:ef";
    421         int associationRejections = 5;
    422         int authenticationFailures = 9;
    423         int dhcpFailures = 11;
    424         // Buffer potential candidates 1,2,3 & 4
    425         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    426                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    427         mLastResortWatchdog.updateAvailableNetworks(candidates);
    428 
    429         // Ensure new networks have zero'ed failure counts
    430         for (int i = 0; i < mSsids.length; i++) {
    431             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    432         }
    433 
    434         //Increment failure count for each network and failure type
    435         int net = 0;
    436         for (int i = 0; i < associationRejections; i++) {
    437             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
    438                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    439         }
    440         net = 1;
    441         for (int i = 0; i < authenticationFailures; i++) {
    442             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
    443                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    444         }
    445         net = 2;
    446         for (int i = 0; i < dhcpFailures; i++) {
    447             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
    448                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    449         }
    450 
    451         // Ensure all networks still have zero failure count
    452         for (int i = 0; i < mSsids.length; i++) {
    453             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    454         }
    455     }
    456 
    457     /**
    458      * Case 9: Test Failure Counting, using the "Any" BSSID
    459      * Test has 4 buffered networks, two of which share the same SSID (different mBssids)
    460      * Each failure type is incremented for the shared SSID, but with BSSID "any"
    461      * Expected Behavior: Both networks increment their counts in tandem
    462      */
    463     @Test
    464     public void testFailureCounting_countFailuresForAnyBssid() throws Exception {
    465         String[] ssids = {"\"test1\"", "\"test2\"", "\"test1\"", "\"test4\""};
    466         int associationRejections = 5;
    467         int authenticationFailures = 9;
    468         int dhcpFailures = 11;
    469         // Buffer potential candidates 1,2,3 & 4
    470         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
    471                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    472         mLastResortWatchdog.updateAvailableNetworks(candidates);
    473 
    474         // Ensure new networks have zero'ed failure counts
    475         for (int i = 0; i < ssids.length; i++) {
    476             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    477         }
    478 
    479         //Increment failure count for each network and failure type
    480         int net = 0;
    481         for (int i = 0; i < associationRejections; i++) {
    482             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    483                     ssids[0], WifiLastResortWatchdog.BSSID_ANY,
    484                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    485         }
    486         net = 1;
    487         for (int i = 0; i < authenticationFailures; i++) {
    488             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    489                     ssids[0], WifiLastResortWatchdog.BSSID_ANY,
    490                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    491         }
    492         net = 2;
    493         for (int i = 0; i < dhcpFailures; i++) {
    494             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    495                     ssids[0], WifiLastResortWatchdog.BSSID_ANY,
    496                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    497         }
    498         assertFailureCountEquals(mBssids[0], associationRejections, authenticationFailures,
    499                 dhcpFailures);
    500         assertFailureCountEquals(mBssids[1], 0, 0, 0);
    501         assertFailureCountEquals(mBssids[2], associationRejections, authenticationFailures,
    502                 dhcpFailures);
    503         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    504     }
    505 
    506     /**
    507      * Case 10: Test Failure Counting, using the "Any" BSSID for nonexistent SSID
    508      * Test has 4 buffered networks, two of which share the same SSID (different mBssids)
    509      * Each failure type is incremented for a bad SSID (doesn't exist), but with BSSID "any"
    510      * Expected Behavior: No Failures counted
    511      */
    512     @Test
    513     public void testFailureCounting_countFailuresForAnyBssidNonexistentSsid() throws Exception {
    514         int associationRejections = 5;
    515         int authenticationFailures = 9;
    516         int dhcpFailures = 11;
    517         String badSsid = "DropItLikeIt'sHotSpot";
    518         // Buffer potential candidates 1,2,3 & 4
    519         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    520                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    521         mLastResortWatchdog.updateAvailableNetworks(candidates);
    522 
    523         // Ensure new networks have zero'ed failure counts
    524         for (int i = 0; i < mSsids.length; i++) {
    525             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    526         }
    527 
    528         //Increment failure count for each network and failure type
    529         int net = 0;
    530         for (int i = 0; i < associationRejections; i++) {
    531             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    532                     badSsid, WifiLastResortWatchdog.BSSID_ANY,
    533                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    534         }
    535         net = 1;
    536         for (int i = 0; i < authenticationFailures; i++) {
    537             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    538                     badSsid, WifiLastResortWatchdog.BSSID_ANY,
    539                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    540         }
    541         net = 2;
    542         for (int i = 0; i < dhcpFailures; i++) {
    543             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    544                     badSsid, WifiLastResortWatchdog.BSSID_ANY,
    545                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    546         }
    547         // Check that all network failure counts are still zero
    548         for (int i = 0; i < mSsids.length; i++) {
    549             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    550         }
    551     }
    552 
    553     /**
    554      * Case 11: Test Failure Counting, over failure Threshold check
    555      * Test has 4 buffered networks, cause FAILURE_THRESHOLD failures for each failure type to one
    556      * of each network (leaving one unfailed).
    557      * Expected Behavior: 3 of the Available Networks report OverFailureThreshold
    558      */
    559     @Test
    560     public void testFailureCounting_failureOverThresholdCheck() throws Exception {
    561         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
    562         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD;
    563         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD;
    564         // Buffer potential candidates 1,2,3 & 4
    565         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    566                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    567         mLastResortWatchdog.updateAvailableNetworks(candidates);
    568 
    569         // Ensure new networks have zero'ed failure counts
    570         for (int i = 0; i < mSsids.length; i++) {
    571             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    572         }
    573 
    574         //Increment failure count for each network and failure type
    575         int net = 0;
    576         for (int i = 0; i < associationRejections; i++) {
    577             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    578                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    579         }
    580         net = 1;
    581         for (int i = 0; i < authenticationFailures; i++) {
    582             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    583                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    584         }
    585         net = 2;
    586         for (int i = 0; i < dhcpFailures; i++) {
    587             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    588                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    589         }
    590         assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[0]));
    591         assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[1]));
    592         assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[2]));
    593         assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3]));
    594     }
    595 
    596     /**
    597      * Case 12: Test Failure Counting, under failure Threshold check
    598      * Test has 4 buffered networks, cause FAILURE_THRESHOLD - 1 failures for each failure type to
    599      * one of each network (leaving one unfailed).
    600      * Expected Behavior: 0 of the Available Networks report OverFailureThreshold
    601      */
    602     @Test
    603     public void testFailureCounting_failureUnderThresholdCheck() throws Exception {
    604         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
    605         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
    606         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
    607         // Buffer potential candidates 1,2,3 & 4
    608         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    609                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    610         mLastResortWatchdog.updateAvailableNetworks(candidates);
    611 
    612         // Ensure new networks have zero'ed failure counts
    613         for (int i = 0; i < mSsids.length; i++) {
    614             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    615         }
    616 
    617         //Increment failure count for each network and failure type
    618         int net = 0;
    619         for (int i = 0; i < associationRejections; i++) {
    620             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    621                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    622         }
    623         net = 1;
    624         for (int i = 0; i < authenticationFailures; i++) {
    625             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    626                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    627         }
    628         net = 2;
    629         for (int i = 0; i < dhcpFailures; i++) {
    630             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    631                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    632         }
    633         assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[0]));
    634         assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[1]));
    635         assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[2]));
    636         assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3]));
    637     }
    638 
    639     /**
    640      * Case 13: Test Failure Counting, available network buffering does not affect counts
    641      * In this test:
    642      *   4 networks are buffered
    643      *   Some number of failures are counted
    644      *   networks are buffered again
    645      * Expected Behavior: Failure counts are not modified by buffering
    646      */
    647     @Test
    648     public void testAvailableNetworkBuffering_doesNotAffectFailureCounts() throws Exception {
    649         int associationRejections = 5;
    650         int authenticationFailures = 9;
    651         int dhcpFailures = 11;
    652         // Buffer potential candidates 1,2,3 & 4
    653         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    654                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    655         mLastResortWatchdog.updateAvailableNetworks(candidates);
    656 
    657         // Ensure new networks have zero'ed failure counts
    658         for (int i = 0; i < mSsids.length; i++) {
    659             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    660         }
    661 
    662         //Increment failure count for each network and failure type
    663         int net = 0;
    664         for (int i = 0; i < associationRejections; i++) {
    665             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    666                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    667             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    668                     .get(mBssids[net]).associationRejection);
    669         }
    670         net = 1;
    671         for (int i = 0; i < authenticationFailures; i++) {
    672             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    673                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    674             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    675                     .get(mBssids[net]).authenticationFailure);
    676         }
    677         net = 2;
    678         for (int i = 0; i < dhcpFailures; i++) {
    679             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    680                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    681             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    682                     .get(mBssids[net]).dhcpFailure);
    683         }
    684         // Check Each Network has appropriate failure count
    685         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    686         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    687         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    688         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    689 
    690         // Re-buffer all networks
    691         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
    692             mLastResortWatchdog.updateAvailableNetworks(candidates);
    693         }
    694 
    695         // Check Each Network still has appropriate failure count
    696         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    697         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    698         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    699         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    700     }
    701 
    702     /**
    703      * Case 14: Test Failure Counting, culling of an old network will remove its failure counts
    704      * In this test:
    705      *   4 networks are buffered
    706      *   Some number of failures are counted for all networks
    707      *   3 of the networks are buffered until the 4th dies of old age
    708      *   The 4th network is re-buffered
    709      * Expected Behavior: Failure counts for the 4th network are cleared after re-buffering
    710      */
    711     @Test
    712     public void testAvailableNetworkBuffering_rebufferWipesCounts() throws Exception {
    713         int associationRejections = 5;
    714         int authenticationFailures = 9;
    715         int dhcpFailures = 11;
    716         // Buffer potential candidates 1,2,3 & 4
    717         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    718                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    719         mLastResortWatchdog.updateAvailableNetworks(candidates);
    720 
    721         // Ensure new networks have zero'ed failure counts
    722         for (int i = 0; i < mSsids.length; i++) {
    723             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    724         }
    725 
    726         //Increment failure count for each network and failure type
    727         int net = 0;
    728         for (int i = 0; i < associationRejections; i++) {
    729             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    730                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    731             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    732                     .get(mBssids[net]).associationRejection);
    733         }
    734         net = 1;
    735         for (int i = 0; i < authenticationFailures; i++) {
    736             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    737                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    738             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    739                     .get(mBssids[net]).authenticationFailure);
    740         }
    741         net = 2;
    742         for (int i = 0; i < dhcpFailures; i++) {
    743             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    744                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    745             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    746                     .get(mBssids[net]).dhcpFailure);
    747         }
    748         // Check Each Network has appropriate failure count
    749         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    750         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    751         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    752         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    753 
    754         // Re-buffer all networks except 'test1' until it dies of old age
    755         candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 1, 4),
    756                 Arrays.copyOfRange(mBssids, 1, 4),
    757                 Arrays.copyOfRange(mFrequencies, 1, 4),
    758                 Arrays.copyOfRange(mCaps, 1, 4),
    759                 Arrays.copyOfRange(mLevels, 1, 4),
    760                 Arrays.copyOfRange(mIsEphemeral, 1, 4));
    761         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
    762             mLastResortWatchdog.updateAvailableNetworks(candidates);
    763         }
    764         assertEquals(3, mLastResortWatchdog.getRecentAvailableNetworks().size());
    765         // Re-buffer All networks, with 'test1' again
    766         candidates = createFilteredQnsCandidates(mSsids,
    767                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    768         mLastResortWatchdog.updateAvailableNetworks(candidates);
    769 
    770         // Check Each Network has appropriate failure count (network 1 should be zero'd)
    771         assertFailureCountEquals(mBssids[0], 0, 0, 0);
    772         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    773         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    774         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    775     }
    776 
    777     /**
    778      * Case 26: Test Failure Counting, null failure incrementation
    779      * In this test:
    780      *   4 networks are buffered
    781      *   Attempt to increment failures with null BSSID & SSID
    782      * Expected behavior: Nothing breaks, no counts incremented
    783      */
    784     @Test
    785     public void testFailureCounting_nullInputsNoBreaky() {
    786         int associationRejections = 5;
    787         int authenticationFailures = 9;
    788         int dhcpFailures = 11;
    789         // Buffer potential candidates 1,2,3 & 4
    790         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    791                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    792         mLastResortWatchdog.updateAvailableNetworks(candidates);
    793 
    794         // Ensure new networks have zero'ed failure counts
    795         for (int i = 0; i < mSsids.length; i++) {
    796             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    797         }
    798 
    799         //Increment failure count for each network and failure type
    800         int net = 0;
    801         for (int i = 0; i < associationRejections; i++) {
    802             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, mBssids[net],
    803                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    804         }
    805         net = 1;
    806         for (int i = 0; i < authenticationFailures; i++) {
    807             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], null,
    808                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    809         }
    810         net = 2;
    811         for (int i = 0; i < dhcpFailures; i++) {
    812             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, null,
    813                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    814         }
    815 
    816         // Ensure new networks have zero'ed failure counts
    817         for (int i = 0; i < mSsids.length; i++) {
    818             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    819         }
    820     }
    821 
    822     /**
    823      * Case 27: Test Failure Counting, test all failures are counted across SSID
    824      * In this test there are 8 networks,
    825      * the first 4 networks have unique SSIDs amongst themselves,
    826      * the last 4 networks share these SSIDs respectively, so there are 2 networks per SSID
    827      * In this test we increment failure counts for the 'test1' ssid for a specific BSSID, and for
    828      * the 'test2' ssid for BSSID_ANY.
    829      * Expected behaviour: Failure counts for both networks on the same SSID are mirrored via both
    830      * incrementation methods
    831      */
    832     @Test
    833     public void testFailureCounting_countFailuresAcrossSsids() throws Exception {
    834         String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\"",
    835                 "\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
    836         String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
    837                 "c0:ff:ee:ee:e3:ee", "6c:f3:7f:ae:3c:f3", "6c:f3:7f:ae:3c:f4", "d3:ad:ba:b1:35:55",
    838                 "c0:ff:ee:ee:33:ee"};
    839         int[] frequencies = {2437, 5180, 5180, 2437, 2437, 5180, 5180, 2437};
    840         String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
    841                 "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
    842                 "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
    843         int[] levels = {-60, -86, -50, -62, -60, -86, -50, -62};
    844         boolean[] isEphemeral = {false, false, false, false, false, false, false, false};
    845         boolean[] hasEverConnected = {false, false, false, false, false, false, false,
    846                 false};
    847         int firstNetFails = 13;
    848         int secondNetFails = 8;
    849         // Buffer potential candidates 1,2,3 & 4
    850         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
    851                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
    852         mLastResortWatchdog.updateAvailableNetworks(candidates);
    853 
    854         // Ensure new networks have zero'ed failure counts
    855         for (int i = 0; i < ssids.length; i++) {
    856             assertFailureCountEquals(bssids[i], 0, 0, 0);
    857         }
    858 
    859         //Increment failure count for the first test network ssid & bssid
    860         for (int i = 0; i < firstNetFails; i++) {
    861             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    862                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    863             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    864                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    865             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    866                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    867         }
    868         //Increment failure count for the first test network ssid & BSSID_ANY
    869         for (int i = 0; i < secondNetFails; i++) {
    870             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    871                     ssids[1], WifiLastResortWatchdog.BSSID_ANY,
    872                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    873             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    874                     ssids[1], WifiLastResortWatchdog.BSSID_ANY,
    875                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    876             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
    877                     ssids[1], WifiLastResortWatchdog.BSSID_ANY,
    878                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    879         }
    880         assertFailureCountEquals(bssids[0], firstNetFails, firstNetFails, firstNetFails);
    881         assertFailureCountEquals(bssids[1], secondNetFails, secondNetFails, secondNetFails);
    882         assertFailureCountEquals(bssids[2], 0, 0, 0);
    883         assertFailureCountEquals(bssids[3], 0, 0, 0);
    884         assertFailureCountEquals(bssids[4], firstNetFails, firstNetFails, firstNetFails);
    885         assertFailureCountEquals(bssids[5], secondNetFails, secondNetFails, secondNetFails);
    886         assertFailureCountEquals(bssids[6], 0, 0, 0);
    887         assertFailureCountEquals(bssids[7], 0, 0, 0);
    888     }
    889 
    890     /**
    891      * Case 15: Test failure counting, ensure failures still counted while connected
    892      * Although failures should not occur while wifi is connected, race conditions are a thing, and
    893      * I'd like the count to be incremented even while connected (Later test verifies that this
    894      * can't cause a trigger though)
    895      * Expected behavior: Failure counts increment like normal
    896      */
    897     @Test
    898     public void testFailureCounting_wifiIsConnectedDoesNotAffectCounting() throws Exception {
    899         int associationRejections = 5;
    900         int authenticationFailures = 9;
    901         int dhcpFailures = 11;
    902 
    903         // Set Watchdogs internal wifi state tracking to 'connected'
    904         mLastResortWatchdog.connectedStateTransition(true);
    905 
    906         // Buffer potential candidates 1,2,3 & 4
    907         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    908                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    909         mLastResortWatchdog.updateAvailableNetworks(candidates);
    910 
    911         // Ensure new networks have zero'ed failure counts
    912         for (int i = 0; i < mSsids.length; i++) {
    913             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    914         }
    915 
    916         //Increment failure count for each network and failure type
    917         int net = 0;
    918         for (int i = 0; i < associationRejections; i++) {
    919             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    920                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    921             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    922                     .get(mBssids[net]).associationRejection);
    923         }
    924         net = 1;
    925         for (int i = 0; i < authenticationFailures; i++) {
    926             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    927                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    928             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    929                     .get(mBssids[net]).authenticationFailure);
    930         }
    931         net = 2;
    932         for (int i = 0; i < dhcpFailures; i++) {
    933             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    934                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    935             assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
    936                     .get(mBssids[net]).dhcpFailure);
    937         }
    938         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    939         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    940         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    941         assertFailureCountEquals(mBssids[3], 0, 0, 0);
    942     }
    943 
    944     /**
    945      * Case 16: Test Failure Counting, entering ConnectedState clears all failure counts
    946      * 4 Networks are buffered, cause various failures to 3 of them. Transition to ConnectedState
    947      * Expected behavior: After transitioning, failure counts are reset to 0
    948      */
    949     @Test
    950     public void testFailureCounting_enteringWifiConnectedStateClearsCounts() throws Exception {
    951         int associationRejections = 5;
    952         int authenticationFailures = 9;
    953         int dhcpFailures = 11;
    954 
    955         // Buffer potential candidates 1,2,3 & 4
    956         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
    957                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
    958         mLastResortWatchdog.updateAvailableNetworks(candidates);
    959 
    960         //Increment failure count for each network and failure type
    961         int net = 0;
    962         for (int i = 0; i < associationRejections; i++) {
    963             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    964                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
    965         }
    966         net = 1;
    967         for (int i = 0; i < authenticationFailures; i++) {
    968             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    969                     WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
    970         }
    971         net = 2;
    972         for (int i = 0; i < dhcpFailures; i++) {
    973             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
    974                     WifiLastResortWatchdog.FAILURE_CODE_DHCP);
    975         }
    976 
    977         // Check that we have Failures
    978         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
    979         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
    980         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
    981 
    982         // Transition to 'ConnectedState'
    983         mLastResortWatchdog.connectedStateTransition(true);
    984 
    985         // Check that we have no failures
    986         for (int i = 0; i < mSsids.length; i++) {
    987             assertFailureCountEquals(mBssids[i], 0, 0, 0);
    988         }
    989     }
    990 
    991     /**
    992      * Case 17: Test Trigger Condition, only some networks over threshold
    993      * We have 4 buffered networks, increment failure counts on 3 of them, until all 3 are over
    994      * threshold.
    995      * Expected Behavior: Watchdog does not trigger
    996      */
    997     @Test
    998     public void testTriggerCondition_someNetworksOverFailureThreshold_allHaveEverConnected()
    999             throws Exception {
   1000         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1001         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1002         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1003         boolean[] hasEverConnected = {true, true, true, true};
   1004 
   1005         // Buffer potential candidates 1,2,3 & 4
   1006         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1007                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
   1008         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1009 
   1010         // Increment failure count for 3 networks and failure types, asserting each time that it
   1011         // does not trigger, with only 3 over threshold
   1012         boolean watchdogTriggered = false;
   1013         int net = 0;
   1014         for (int i = 0; i < associationRejections; i++) {
   1015             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1016                 mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1017             assertEquals(false, watchdogTriggered);
   1018         }
   1019         net = 1;
   1020         for (int i = 0; i < authenticationFailures; i++) {
   1021             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1022                 mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1023             assertEquals(false, watchdogTriggered);
   1024         }
   1025         net = 2;
   1026         for (int i = 0; i < dhcpFailures; i++) {
   1027             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1028                 mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1029             assertEquals(false, watchdogTriggered);
   1030         }
   1031 
   1032         // Check that we have Failures
   1033         assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
   1034         assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
   1035         assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
   1036 
   1037         // Add one more failure to one of the already over threshold networks, assert that it
   1038         // does not trigger
   1039         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1040                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1041         assertEquals(false, watchdogTriggered);
   1042     }
   1043 
   1044     /**
   1045      * Case 18: Test Trigger Condition, watchdog fires once, then deactivates
   1046      * In this test we have 4 networks, which we have connected to in the past. Failures are
   1047      * incremented until all networks but one are over failure threshold, and then a few more times.
   1048      *
   1049      * Expected behavior: The watchdog triggers once as soon as all failures are over threshold,
   1050      * but stops triggering for subsequent failures
   1051      */
   1052     @Test
   1053     public void testTriggerCondition_allNetworksOverFailureThreshold_allHaveEverConnected()
   1054             throws Exception {
   1055         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1056         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1057         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1058         boolean[] hasEverConnected = {true, true, true, true};
   1059 
   1060         // Buffer potential candidates 1,2,3 & 4
   1061         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1062                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
   1063         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1064 
   1065         // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
   1066         boolean watchdogTriggered = false;
   1067         int net = 0;
   1068         for (int i = 0; i < associationRejections; i++) {
   1069             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1070                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1071             assertEquals(false, watchdogTriggered);
   1072         }
   1073         net = 1;
   1074         for (int i = 0; i < authenticationFailures; i++) {
   1075             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1076                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1077             assertEquals(false, watchdogTriggered);
   1078         }
   1079         net = 2;
   1080         for (int i = 0; i < dhcpFailures; i++) {
   1081             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1082                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1083             assertEquals(false, watchdogTriggered);
   1084         }
   1085 
   1086         // Bring the remaining unfailed network upto 1 less than the failure threshold
   1087         net = 3;
   1088         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
   1089             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1090                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1091             assertEquals(false, watchdogTriggered);
   1092         }
   1093         // Increment failure count once more, check that watchdog triggered this time
   1094         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1095                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1096         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1097         assertEquals(true, watchdogTriggered);
   1098 
   1099         // Increment failure count 5 more times, watchdog should not trigger
   1100         for (int i = 0; i < 5; i++) {
   1101             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1102                         mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1103             assertEquals(false, watchdogTriggered);
   1104         }
   1105     }
   1106 
   1107     /**
   1108      * Case 19: Test Trigger Condition, all networks over failure threshold, one has ever connected
   1109      * In this test we have 4 networks, only one has connected in the past. Failures are
   1110      * incremented until all networks but one are over failure threshold, and then a few more times.
   1111      *
   1112      * Expected behavior: The watchdog triggers once as soon as all failures are over threshold,
   1113      * but stops triggering for subsequent failures
   1114      */
   1115     @Test
   1116     public void testTriggerCondition_allNetworksOverFailureThreshold_oneHaveEverConnected()
   1117             throws Exception {
   1118         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1119         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1120         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1121         boolean[] hasEverConnected = {false, true, false, false};
   1122 
   1123         // Buffer potential candidates 1,2,3 & 4
   1124         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1125                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
   1126         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1127 
   1128         // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
   1129         boolean watchdogTriggered = false;
   1130         int net = 0;
   1131         for (int i = 0; i < associationRejections; i++) {
   1132             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1133                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1134             assertEquals(false, watchdogTriggered);
   1135         }
   1136         net = 1;
   1137         for (int i = 0; i < authenticationFailures; i++) {
   1138             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1139                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1140             assertEquals(false, watchdogTriggered);
   1141         }
   1142         net = 2;
   1143         for (int i = 0; i < dhcpFailures; i++) {
   1144             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1145                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1146             assertEquals(false, watchdogTriggered);
   1147         }
   1148 
   1149         // Bring the remaining unfailed network upto 1 less than the failure threshold
   1150         net = 3;
   1151         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
   1152             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1153                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1154             assertEquals(false, watchdogTriggered);
   1155         }
   1156         // Increment failure count once more, check that watchdog triggered this time
   1157         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1158                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1159         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1160         assertEquals(true, watchdogTriggered);
   1161 
   1162         // Increment failure count 5 more times, watchdog should not trigger
   1163         for (int i = 0; i < 5; i++) {
   1164             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1165                         mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1166             assertEquals(false, watchdogTriggered);
   1167         }
   1168     }
   1169 
   1170     /**
   1171      * Case 20: Test Trigger Condition, all networks over failure threshold, 0 have ever connected
   1172      * In this test we have 4 networks, none have ever connected. Failures are
   1173      * incremented until all networks but one are over failure threshold, and then a few more times.
   1174      *
   1175      * Expected behavior: The watchdog does not trigger
   1176      */
   1177     @Test
   1178     public void testTriggerCondition_allNetworksOverFailureThreshold_zeroHaveEverConnected()
   1179             throws Exception {
   1180         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD + 1;
   1181         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1182         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1183 
   1184         // Buffer potential candidates 1,2,3 & 4
   1185         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1186                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
   1187         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1188 
   1189         // Count failures on all 4 networks until all of them are over the failure threshold
   1190         boolean watchdogTriggered = false;
   1191         int net = 0;
   1192         for (int i = 0; i < associationRejections; i++) {
   1193             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1194                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1195             assertEquals(false, watchdogTriggered);
   1196         }
   1197         net = 1;
   1198         for (int i = 0; i < authenticationFailures; i++) {
   1199             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1200                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1201             assertEquals(false, watchdogTriggered);
   1202         }
   1203         net = 2;
   1204         for (int i = 0; i < dhcpFailures; i++) {
   1205             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1206                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1207             assertEquals(false, watchdogTriggered);
   1208         }
   1209         net = 3;
   1210         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
   1211             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1212                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1213             assertEquals(false, watchdogTriggered);
   1214         }
   1215     }
   1216 
   1217     /**
   1218      * Case 21: Test Trigger Condition, Conditions right to trigger, but wifi is connected
   1219      * In this test we have 4 networks, all have connected in the past
   1220      * incremented until all networks but one are over failure threshold, and then a few more times.
   1221      *
   1222      * Expected behavior: The watchdog does not trigger
   1223      */
   1224     @Test
   1225     public void testTriggerCondition_allNetworksOverFailureThreshold_isConnected()
   1226         throws Exception {
   1227         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD + 1;
   1228         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1229         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1230 
   1231         // Buffer potential candidates 1,2,3 & 4
   1232         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1233                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
   1234         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1235 
   1236         // Set Watchdogs internal wifi state tracking to 'connected'
   1237         mLastResortWatchdog.connectedStateTransition(true);
   1238 
   1239         // Count failures on all 4 networks until all of them are over the failure threshold
   1240         boolean watchdogTriggered = false;
   1241         int net = 0;
   1242         for (int i = 0; i < associationRejections; i++) {
   1243             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1244                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1245             assertEquals(false, watchdogTriggered);
   1246         }
   1247         net = 1;
   1248         for (int i = 0; i < authenticationFailures; i++) {
   1249             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1250                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1251             assertEquals(false, watchdogTriggered);
   1252         }
   1253         net = 2;
   1254         for (int i = 0; i < dhcpFailures; i++) {
   1255             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1256                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1257             assertEquals(false, watchdogTriggered);
   1258         }
   1259         net = 3;
   1260         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
   1261             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1262                     mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1263             assertEquals(false, watchdogTriggered);
   1264         }
   1265     }
   1266 
   1267     private void incrementFailuresUntilTrigger(String[] ssids, String[] bssids) {
   1268         // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
   1269         boolean watchdogTriggered = false;
   1270         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1271             for (int j = 0; j < ssids.length - 1; j++) {
   1272                 watchdogTriggered = mLastResortWatchdog
   1273                         .noteConnectionFailureAndTriggerIfNeeded(ssids[j], bssids[j],
   1274                         WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1275                 assertEquals(false, watchdogTriggered);
   1276             }
   1277         }
   1278         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
   1279             watchdogTriggered = mLastResortWatchdog
   1280                     .noteConnectionFailureAndTriggerIfNeeded(ssids[ssids.length - 1],
   1281                     bssids[ssids.length - 1], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1282             assertEquals(false, watchdogTriggered);
   1283         }
   1284 
   1285         // Increment failure count once more, check that watchdog triggered this time
   1286         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1287                     ssids[ssids.length - 1], bssids[ssids.length - 1],
   1288                     WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1289         assertEquals(true, watchdogTriggered);
   1290         verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_LAST_RESORT_WATCHDOG));
   1291         reset(mSelfRecovery);
   1292     }
   1293 
   1294     /**
   1295      * Case 22: Test enabling/disabling of Watchdog Trigger, disabled after triggering
   1296      * In this test, we have 4 networks. Increment failures until Watchdog triggers. Increment some
   1297      * more failures.
   1298      * Expected behavior: Watchdog trigger gets deactivated after triggering, and stops triggering
   1299      */
   1300     @Test
   1301     public void testTriggerEnabling_disabledAfterTriggering() throws Exception {
   1302         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1303         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1304         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1305         boolean[] hasEverConnected = {false, true, false, false};
   1306 
   1307         // Buffer potential candidates 1,2,3 & 4
   1308         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1309                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
   1310         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1311 
   1312         incrementFailuresUntilTrigger(mSsids, mBssids);
   1313 
   1314         // Increment failure count 5 more times, watchdog should not trigger
   1315         for (int i = 0; i < 5; i++) {
   1316             boolean watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1317                         mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1318             assertEquals(false, watchdogTriggered);
   1319         }
   1320     }
   1321 
   1322     /**
   1323      * Case 23: Test enabling/disabling of Watchdog Trigger, trigger re-enabled after connecting
   1324      * In this test, we have 4 networks. Increment failures until Watchdog triggers and deactivates,
   1325      * transition wifi to connected state, then increment failures until all networks over threshold
   1326      * Expected behavior: Watchdog able to trigger again after transitioning to and from connected
   1327      * state
   1328      */
   1329     @Test
   1330     public void testTriggerEnabling_enabledAfterConnecting() throws Exception {
   1331         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1332         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1333         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1334         boolean[] hasEverConnected = {false, true, false, false};
   1335         boolean watchdogTriggered;
   1336         // Buffer potential candidates 1,2,3 & 4
   1337         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
   1338                 mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
   1339         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1340 
   1341         incrementFailuresUntilTrigger(mSsids, mBssids);
   1342 
   1343         // Increment failure count 5 more times, ensure trigger is deactivated
   1344         for (int i = 0; i < 5; i++) {
   1345             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1346                         mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1347             mLastResortWatchdog.updateAvailableNetworks(candidates);
   1348             assertEquals(false, watchdogTriggered);
   1349         }
   1350 
   1351         // transition Watchdog wifi state tracking to 'connected' then back to 'disconnected'
   1352         mLastResortWatchdog.connectedStateTransition(true);
   1353         mLastResortWatchdog.connectedStateTransition(false);
   1354 
   1355         // Fail 3/4 networks until they're over threshold
   1356         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
   1357             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1358                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1359             assertEquals(false, watchdogTriggered);
   1360             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1361                     mSsids[1], mBssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1362             assertEquals(false, watchdogTriggered);
   1363             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1364                     mSsids[2], mBssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1365             assertEquals(false, watchdogTriggered);
   1366         }
   1367 
   1368         // Bring the remaining unfailed network upto 1 less than the failure threshold
   1369         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
   1370             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1371                     mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1372             assertEquals(false, watchdogTriggered);
   1373         }
   1374         // Increment failure count once more, check that watchdog triggered this time
   1375         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1376                     mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1377         assertEquals(true, watchdogTriggered);
   1378     }
   1379 
   1380     /**
   1381      * Case 24: Test enabling/disabling of Watchdog Trigger, trigger re-enabled after new network
   1382      * In this test, we have 3 networks. Increment failures until Watchdog triggers and deactivates,
   1383      * we then buffer a new network (network 4), then increment failures until all networks over
   1384      * threshold Expected behavior: Watchdog able to trigger again after discovering a new network
   1385      */
   1386     @Test
   1387     public void testTriggerEnabling_enabledAfterNewNetwork() {
   1388         int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
   1389         int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
   1390         int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
   1391         boolean[] hasEverConnected = {false, true, false, false};
   1392         boolean watchdogTriggered;
   1393 
   1394         // Buffer potential candidates 1,2,3
   1395         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(
   1396                 Arrays.copyOfRange(mSsids, 0, 3),
   1397                 Arrays.copyOfRange(mBssids, 0, 3),
   1398                 Arrays.copyOfRange(mFrequencies, 0, 3),
   1399                 Arrays.copyOfRange(mCaps, 0, 3),
   1400                 Arrays.copyOfRange(mLevels, 0, 3),
   1401                 Arrays.copyOfRange(mIsEphemeral, 0, 3),
   1402                 Arrays.copyOfRange(hasEverConnected, 0, 3));
   1403         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1404 
   1405         incrementFailuresUntilTrigger(Arrays.copyOfRange(mSsids, 0, 3),
   1406                 Arrays.copyOfRange(mBssids, 0, 3));
   1407 
   1408         // Increment failure count 5 more times, ensure trigger is deactivated
   1409         for (int i = 0; i < 5; i++) {
   1410             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1411                         mSsids[2], mBssids[2], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1412             mLastResortWatchdog.updateAvailableNetworks(candidates);
   1413             assertEquals(false, watchdogTriggered);
   1414         }
   1415 
   1416         candidates = createFilteredQnsCandidates(mSsids, mBssids, mFrequencies, mCaps, mLevels,
   1417                 mIsEphemeral, hasEverConnected);
   1418         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1419 
   1420         incrementFailuresUntilTrigger(mSsids, mBssids);
   1421 
   1422     }
   1423 
   1424     /**
   1425      * Case 28: Test Metrics collection
   1426      * Setup 5 networks (unique SSIDs). Fail them until watchdog triggers, with 1 network failing
   1427      * association, 1 failing authentication, 2 failing dhcp and one failing both authentication and
   1428      * dhcp, (over threshold for all these failures)
   1429      * Expected behavior: Metrics are updated as follows
   1430      *  Triggers++
   1431      *  # of Networks += 5
   1432      *  Triggers with Bad association++
   1433      *  Triggers with Bad authentication++
   1434      *  Triggers with Bad dhcp++
   1435      *  Number of networks with bad association += 1
   1436      *  Number of networks with bad authentication += 2
   1437      *  Number of networks with bad dhcp += 3
   1438      */
   1439     @Test
   1440     public void testMetricsCollection() {
   1441         String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\"", "\"test5\""};
   1442         String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
   1443                 "c0:ff:ee:ee:e3:ee", "6c:f3:7f:ae:3c:f3"};
   1444         int[] frequencies = {2437, 5180, 5180, 2437, 2437};
   1445         String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
   1446                 "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
   1447         int[] levels = {-60, -86, -50, -62, -60};
   1448         boolean[] isEphemeral = {false, false, false, false, false};
   1449         boolean[] hasEverConnected = {true, false, false, false, false};
   1450         // Buffer potential candidates 1,2,3,4 & 5
   1451         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
   1452                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
   1453         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1454 
   1455         // Ensure new networks have zero'ed failure counts
   1456         for (int i = 0; i < ssids.length; i++) {
   1457             assertFailureCountEquals(bssids[i], 0, 0, 0);
   1458         }
   1459 
   1460         final long timeAtFailure = 100;
   1461         final long timeAtReconnect = 5000;
   1462         final long expectedDuration = timeAtReconnect - timeAtFailure;
   1463         when(mClock.getElapsedSinceBootMillis()).thenReturn(timeAtFailure, timeAtReconnect);
   1464 
   1465         //Increment failure counts
   1466         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1467             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1468                     ssids[1], bssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1469             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1470                     ssids[2], bssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1471             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1472                     ssids[3], bssids[3], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1473             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1474                     ssids[4], bssids[4], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1475             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1476                     ssids[4], bssids[4], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1477             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1478                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1479         }
   1480 
   1481         // Verify relevant WifiMetrics calls were made once with appropriate arguments
   1482         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggers();
   1483         verify(mWifiMetrics, times(1)).addCountToNumLastResortWatchdogAvailableNetworksTotal(5);
   1484         verify(mWifiMetrics, times(1))
   1485                 .addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(2);
   1486         verify(mWifiMetrics, times(1))
   1487                 .incrementNumLastResortWatchdogTriggersWithBadAuthentication();
   1488         verify(mWifiMetrics, times(1))
   1489                 .addCountToNumLastResortWatchdogBadAssociationNetworksTotal(1);
   1490         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadAssociation();
   1491         verify(mWifiMetrics, times(1)).addCountToNumLastResortWatchdogBadDhcpNetworksTotal(3);
   1492         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadDhcp();
   1493 
   1494         // Simulate wifi connecting after triggering
   1495         mLastResortWatchdog.connectedStateTransition(true);
   1496 
   1497         // Verify that WifiMetrics counted this as a Watchdog success
   1498         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses();
   1499         verify(mWifiMetrics, times(1)).setWatchdogSuccessTimeDurationMs(eq(expectedDuration));
   1500 
   1501         // Verify takeBugReport is called
   1502         mLooper.dispatchAll();
   1503         verify(mWifiStateMachine, times(1)).takeBugReport(anyString(), anyString());
   1504 
   1505         // Simulate wifi disconnecting
   1506         mLastResortWatchdog.connectedStateTransition(false);
   1507 
   1508         // Verify that WifiMetrics has still only counted one success
   1509         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses();
   1510         verify(mWifiMetrics, times(1)).setWatchdogSuccessTimeDurationMs(eq(expectedDuration));
   1511         // Verify takeBugReport not called again
   1512         mLooper.dispatchAll();
   1513         verify(mWifiStateMachine, times(1)).takeBugReport(anyString(), anyString());
   1514 
   1515         // Remove the fifth network from candidates
   1516         candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 4),
   1517             Arrays.copyOfRange(mBssids, 0, 4),
   1518             Arrays.copyOfRange(mFrequencies, 0, 4),
   1519             Arrays.copyOfRange(mCaps, 0, 4),
   1520             Arrays.copyOfRange(mLevels, 0, 4),
   1521             Arrays.copyOfRange(mIsEphemeral, 0, 4));
   1522 
   1523         // Age out the fifth network
   1524         for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
   1525             mLastResortWatchdog.updateAvailableNetworks(candidates);
   1526         }
   1527 
   1528         //Increment failure counts
   1529         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1530             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1531                     ssids[1], bssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1532             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1533                     ssids[2], bssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1534             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1535                     ssids[3], bssids[3], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
   1536             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1537                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1538         }
   1539 
   1540         // Add network #5 back into the candidates
   1541         candidates = createFilteredQnsCandidates(ssids,
   1542                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
   1543 
   1544         // LastResortWatchdog should reactivate because there is a new network (#5) available,
   1545         // Not because it was successful
   1546         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1547 
   1548         // Simulate wifi connecting
   1549         mLastResortWatchdog.connectedStateTransition(true);
   1550 
   1551         // Verify that WifiMetrics did not count another success, as the connection could be due
   1552         // to the newly available network #5
   1553         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses();
   1554         verify(mWifiMetrics, times(1)).setWatchdogSuccessTimeDurationMs(eq(expectedDuration));
   1555     }
   1556 
   1557     /**
   1558      * Case 21: Test config updates where new config is null.
   1559      * Create a scan result with an associated config and update the available networks list.
   1560      * Repeat this with a second scan result where the config is null.
   1561      * Expected behavior: The stored config should not be lost overwritten.
   1562      */
   1563     @Test
   1564     public void testUpdateNetworkWithNullConfig() {
   1565         List<Pair<ScanDetail, WifiConfiguration>> candidates =
   1566                 new ArrayList<Pair<ScanDetail, WifiConfiguration>>();
   1567         String ssid = mSsids[0].replaceAll("^\"+", "").replaceAll("\"+$", "");
   1568         ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
   1569                 mBssids[0], mCaps[0], mLevels[0], mFrequencies[0], System.currentTimeMillis(), 0);
   1570         WifiConfiguration config = mock(WifiConfiguration.class);
   1571         WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
   1572                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1573         when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus);
   1574         when(networkSelectionStatus.getHasEverConnected())
   1575                 .thenReturn(true);
   1576         candidates.add(Pair.create(scanDetail, config));
   1577         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1578 
   1579         candidates.clear();
   1580 
   1581         candidates.add(Pair.create(scanDetail, null));
   1582         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1583 
   1584         boolean watchdogTriggered = false;
   1585         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1586             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1587                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1588         }
   1589         assertEquals(true, watchdogTriggered);
   1590     }
   1591 
   1592     /**
   1593      * Case 22: Test config updates where hasEverConnected goes from false to true.
   1594      * Create a scan result with an associated config and update the available networks list.
   1595      * Repeat this with a second scan result where the config value for hasEverConnected
   1596      * is true.
   1597      * Expected behavior: The stored config should not be lost overwritten.
   1598      */
   1599     @Test
   1600     public void testUpdateNetworkWithHasEverConnectedTrue() {
   1601         List<Pair<ScanDetail, WifiConfiguration>> candidates =
   1602                 new ArrayList<Pair<ScanDetail, WifiConfiguration>>();
   1603         String ssid = mSsids[0].replaceAll("^\"+", "").replaceAll("\"+$", "");
   1604         ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
   1605                 mBssids[0], mCaps[0], mLevels[0], mFrequencies[0], System.currentTimeMillis(), 0);
   1606         WifiConfiguration configHasEverConnectedFalse = mock(WifiConfiguration.class);
   1607         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusFalse =
   1608                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1609         when(configHasEverConnectedFalse.getNetworkSelectionStatus())
   1610                 .thenReturn(networkSelectionStatusFalse);
   1611         when(networkSelectionStatusFalse.getHasEverConnected())
   1612                 .thenReturn(false);
   1613         candidates.add(Pair.create(scanDetail, configHasEverConnectedFalse));
   1614         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1615 
   1616         boolean watchdogTriggered = false;
   1617         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1618             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1619                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1620         }
   1621         assertEquals(false, watchdogTriggered);
   1622 
   1623         candidates.clear();
   1624 
   1625         WifiConfiguration configHasEverConnectedTrue = mock(WifiConfiguration.class);
   1626         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusTrue =
   1627                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1628         when(configHasEverConnectedTrue.getNetworkSelectionStatus())
   1629                 .thenReturn(networkSelectionStatusTrue);
   1630         when(networkSelectionStatusTrue.getHasEverConnected())
   1631                 .thenReturn(true);
   1632         candidates.add(Pair.create(scanDetail, configHasEverConnectedTrue));
   1633         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1634 
   1635         watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1636                 mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1637         assertEquals(true, watchdogTriggered);
   1638     }
   1639 
   1640     /**
   1641      * Case 23: Test config updates where hasEverConnected goes from true to false.
   1642      * Create a scan result with an associated config and update the available networks list.
   1643      * Repeat this with a second scan result where hasEverConnected is false.
   1644      * Expected behavior: The stored config should not be lost overwritten.
   1645      */
   1646     @Test
   1647     public void testUpdateNetworkWithHasEverConnectedFalse() {
   1648         List<Pair<ScanDetail, WifiConfiguration>> candidates =
   1649                 new ArrayList<Pair<ScanDetail, WifiConfiguration>>();
   1650         String ssid = mSsids[0].replaceAll("^\"+", "").replaceAll("\"+$", "");
   1651         ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
   1652                 mBssids[0], mCaps[0], mLevels[0], mFrequencies[0], System.currentTimeMillis(), 0);
   1653 
   1654         WifiConfiguration configHasEverConnectedTrue = mock(WifiConfiguration.class);
   1655         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusTrue =
   1656                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1657         when(configHasEverConnectedTrue.getNetworkSelectionStatus())
   1658                 .thenReturn(networkSelectionStatusTrue);
   1659         when(networkSelectionStatusTrue.getHasEverConnected())
   1660                 .thenReturn(true);
   1661         candidates.add(Pair.create(scanDetail, configHasEverConnectedTrue));
   1662         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1663 
   1664         boolean watchdogTriggered = false;
   1665         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1666             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1667                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1668         }
   1669         assertEquals(true, watchdogTriggered);
   1670 
   1671         candidates.clear();
   1672 
   1673         WifiConfiguration configHasEverConnectedFalse = mock(WifiConfiguration.class);
   1674         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusFalse =
   1675                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1676         when(configHasEverConnectedFalse.getNetworkSelectionStatus())
   1677                 .thenReturn(networkSelectionStatusFalse);
   1678         when(networkSelectionStatusFalse.getHasEverConnected())
   1679                 .thenReturn(false);
   1680         candidates.add(Pair.create(scanDetail, configHasEverConnectedFalse));
   1681         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1682 
   1683         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1684             watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1685                     mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
   1686         }
   1687         assertEquals(false, watchdogTriggered);
   1688     }
   1689 
   1690     /**
   1691      * Case 24: Check toString method for accurate hasEverConnected value in
   1692      * AvailableNetworkFailureCount objects.
   1693      * Create an AvailableNetworkFailureCount instance and check output of toString method.
   1694      * Expected behavior:  String contains HasEverConnected setting or null_config if there is not
   1695      * an associated config.
   1696      */
   1697     @Test
   1698     public void testHasEverConnectedValueInAvailableNetworkFailureCountToString() {
   1699         // Check with HasEverConnected true
   1700         WifiConfiguration configHasEverConnectedTrue = mock(WifiConfiguration.class);
   1701         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusTrue =
   1702                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1703         when(configHasEverConnectedTrue.getNetworkSelectionStatus())
   1704                 .thenReturn(networkSelectionStatusTrue);
   1705         when(networkSelectionStatusTrue.getHasEverConnected()).thenReturn(true);
   1706         WifiLastResortWatchdog.AvailableNetworkFailureCount withConfigHECTrue =
   1707                 new WifiLastResortWatchdog.AvailableNetworkFailureCount(configHasEverConnectedTrue);
   1708         String output = withConfigHECTrue.toString();
   1709         assertTrue(output.contains("HasEverConnected: true"));
   1710 
   1711         // check with HasEverConnected false
   1712         WifiConfiguration configHasEverConnectedFalse = mock(WifiConfiguration.class);
   1713         WifiConfiguration.NetworkSelectionStatus networkSelectionStatusFalse =
   1714                 mock(WifiConfiguration.NetworkSelectionStatus.class);
   1715         when(configHasEverConnectedFalse.getNetworkSelectionStatus())
   1716                 .thenReturn(networkSelectionStatusFalse);
   1717         when(networkSelectionStatusFalse.getHasEverConnected()).thenReturn(false);
   1718         WifiLastResortWatchdog.AvailableNetworkFailureCount withConfigHECFalse =
   1719                 new WifiLastResortWatchdog.AvailableNetworkFailureCount(
   1720                         configHasEverConnectedFalse);
   1721         output = withConfigHECFalse.toString();
   1722         assertTrue(output.contains("HasEverConnected: false"));
   1723 
   1724         // Check with a null config
   1725         WifiLastResortWatchdog.AvailableNetworkFailureCount withNullConfig =
   1726                 new WifiLastResortWatchdog.AvailableNetworkFailureCount(null);
   1727         output = withNullConfig.toString();
   1728         assertTrue(output.contains("HasEverConnected: null_config"));
   1729     }
   1730 
   1731     /**
   1732      * Test metrics incrementing connection failure count after watchdog has already been triggered
   1733      */
   1734     @Test
   1735     public void testIncrementingWatchdogConnectionFailuresAfterTrigger() {
   1736         String[] ssids = {"\"test1\""};
   1737         String[] bssids = {"6c:f3:7f:ae:8c:f3"};
   1738         int[] frequencies = {2437};
   1739         String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
   1740         int[] levels = {-60};
   1741         boolean[] isEphemeral = {false};
   1742         boolean[] hasEverConnected = {true};
   1743         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
   1744                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
   1745         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1746 
   1747         // Ensure new networks have zero'ed failure counts
   1748         for (int i = 0; i < ssids.length; i++) {
   1749             assertFailureCountEquals(bssids[i], 0, 0, 0);
   1750         }
   1751 
   1752         //Increment failure counts
   1753         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1754             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1755                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1756         }
   1757 
   1758         // Verify relevant WifiMetrics calls were made once with appropriate arguments
   1759         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggers();
   1760 
   1761         // Verify that failure count after trigger is not incremented yet
   1762         verify(mWifiMetrics, never()).incrementWatchdogTotalConnectionFailureCountAfterTrigger();
   1763 
   1764         // Fail 1 more time and verify this time it's counted
   1765         mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1766                 ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1767         verify(mWifiMetrics, times(1)).incrementWatchdogTotalConnectionFailureCountAfterTrigger();
   1768     }
   1769 
   1770     /**
   1771      * Test that LRWD success is only declared when the first connection after restarting wifi
   1772      * is successful.
   1773      *
   1774      * First tests the failure case: check success metric is not incremented when the first
   1775      * connection is a failure.
   1776      * Then test state transition and the success case: check success metric is incremented
   1777      * when the first connection is a success.
   1778      */
   1779     @Test
   1780     public void testWatchdogAssumesSuccessOnlyIfFirstConnectionAfterRestartSucceeds() {
   1781         String[] ssids = {"\"test1\""};
   1782         String[] bssids = {"6c:f3:7f:ae:8c:f3"};
   1783         int[] frequencies = {2437};
   1784         String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
   1785         int[] levels = {-60};
   1786         boolean[] isEphemeral = {false};
   1787         boolean[] hasEverConnected = {true};
   1788         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
   1789                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
   1790         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1791 
   1792         // Ensure new networks have zero'ed failure counts
   1793         for (int i = 0; i < ssids.length; i++) {
   1794             assertFailureCountEquals(bssids[i], 0, 0, 0);
   1795         }
   1796 
   1797         //Increment failure counts
   1798         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1799             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1800                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1801         }
   1802 
   1803         // Verify watchdog has triggered a restart
   1804         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggers();
   1805 
   1806         // Fail 1 more time and verify this time it's counted
   1807         mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1808                 ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1809 
   1810         // Simulate wifi connecting after triggering
   1811         mLastResortWatchdog.connectedStateTransition(true);
   1812         // Verify takeBugReport is not called again
   1813         mLooper.dispatchAll();
   1814         verify(mWifiStateMachine, never()).takeBugReport(anyString(), anyString());
   1815         verify(mWifiMetrics, never()).incrementNumLastResortWatchdogSuccesses();
   1816 
   1817         // Simulate wifi disconnecting
   1818         mLastResortWatchdog.connectedStateTransition(false);
   1819 
   1820         // Test another round, and this time successfully connect after restart trigger
   1821         for (int i = 0; i < ssids.length; i++) {
   1822             assertFailureCountEquals(bssids[i], 0, 0, 0);
   1823         }
   1824         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1825             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1826                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1827         }
   1828 
   1829         // Verify watchdog has triggered a restart
   1830         verify(mWifiMetrics, times(2)).incrementNumLastResortWatchdogTriggers();
   1831         // Simulate wifi connecting after triggering
   1832         mLastResortWatchdog.connectedStateTransition(true);
   1833         // Verify takeBugReport is not called again
   1834         mLooper.dispatchAll();
   1835         verify(mWifiStateMachine, times(1)).takeBugReport(anyString(), anyString());
   1836         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogSuccesses();
   1837     }
   1838 
   1839     /**
   1840      * If the user changes the configuration and then we have a successful connection, don't
   1841      * trigger bugreport.
   1842      * Tests this specific path:
   1843      * 1. watchdog triggers restart
   1844      * 2. wifi configuration changes
   1845      * 3. wifi successfully connects immedietly after
   1846      * Expected result: bugreport should not trigger
   1847      */
   1848     @Test
   1849     public void testWatchdogVerifiesAtLeastOneNetworkIsConnectedBeforeTriggeringBugreport() {
   1850         String[] ssids = {"\"test1\""};
   1851         String[] bssids = {"6c:f3:7f:ae:8c:f3"};
   1852         int[] frequencies = {2437};
   1853         String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
   1854         int[] levels = {-60};
   1855         boolean[] isEphemeral = {false};
   1856         boolean[] hasEverConnected = {true};
   1857         List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
   1858                 bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
   1859         mLastResortWatchdog.updateAvailableNetworks(candidates);
   1860 
   1861         // Ensure new networks have zero'ed failure counts
   1862         for (int i = 0; i < ssids.length; i++) {
   1863             assertFailureCountEquals(bssids[i], 0, 0, 0);
   1864         }
   1865 
   1866         //Increment failure counts
   1867         for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
   1868             mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
   1869                     ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
   1870         }
   1871 
   1872         // Verify watchdog has triggered a restart
   1873         verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggers();
   1874 
   1875         // Simulate user changing the configuration
   1876         when(candidates.get(0).second.getNetworkSelectionStatus().getHasEverConnected())
   1877                 .thenReturn(false);
   1878 
   1879         mLastResortWatchdog.connectedStateTransition(true);
   1880         // Verify takeBugReport is not called again
   1881         mLooper.dispatchAll();
   1882         verify(mWifiStateMachine, never()).takeBugReport(anyString(), anyString());
   1883         verify(mWifiMetrics, never()).incrementNumLastResortWatchdogSuccesses();
   1884     }
   1885 }
   1886