WifiMetricsTest.java revision 031cdffdaf223772d4ea52569ec7a08d00013208
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 */
16package com.android.server.wifi;
17
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertTrue;
20import static org.mockito.Mockito.*;
21
22import android.net.NetworkAgent;
23import android.net.wifi.ScanResult;
24import android.net.wifi.SupplicantState;
25import android.net.wifi.WifiConfiguration;
26import android.net.wifi.WifiManager;
27import android.net.wifi.WifiSsid;
28import android.os.Handler;
29import android.os.test.TestLooper;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.util.Base64;
32
33
34import com.android.server.wifi.hotspot2.NetworkDetail;
35import com.android.server.wifi.nano.WifiMetricsProto;
36import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
37
38import org.junit.Before;
39import org.junit.Test;
40import org.mockito.Mock;
41import org.mockito.MockitoAnnotations;
42
43import java.io.ByteArrayOutputStream;
44import java.io.FileDescriptor;
45import java.io.PrintWriter;
46import java.io.StringWriter;
47import java.util.ArrayList;
48import java.util.BitSet;
49import java.util.List;
50import java.util.regex.Matcher;
51import java.util.regex.Pattern;
52
53/**
54 * Unit tests for {@link com.android.server.wifi.WifiMetrics}.
55 */
56@SmallTest
57public class WifiMetricsTest {
58
59    WifiMetrics mWifiMetrics;
60    WifiMetricsProto.WifiLog mDeserializedWifiMetrics;
61    TestLooper mTestLooper;
62    @Mock Clock mClock;
63
64    @Before
65    public void setUp() throws Exception {
66        MockitoAnnotations.initMocks(this);
67        mDeserializedWifiMetrics = null;
68        when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 0);
69        mTestLooper = new TestLooper();
70        mWifiMetrics = new WifiMetrics(mClock, mTestLooper.getLooper());
71    }
72
73    /**
74     * Test that startConnectionEvent and endConnectionEvent can be called repeatedly and out of
75     * order. Only tests no exception occurs. Creates 3 ConnectionEvents.
76     */
77    @Test
78    public void startAndEndConnectionEventSucceeds() throws Exception {
79        //Start and end Connection event
80        mWifiMetrics.startConnectionEvent(null, "RED",
81                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
82        mWifiMetrics.endConnectionEvent(
83                WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
84                WifiMetricsProto.ConnectionEvent.HLF_DHCP);
85        //end Connection event without starting one
86        mWifiMetrics.endConnectionEvent(
87                WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
88                WifiMetricsProto.ConnectionEvent.HLF_DHCP);
89        //start two ConnectionEvents in a row
90        mWifiMetrics.startConnectionEvent(null, "BLUE",
91                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
92        mWifiMetrics.startConnectionEvent(null, "GREEN",
93                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
94    }
95
96    private static final long TEST_RECORD_DURATION_SEC = 12 * 60 * 60;
97    private static final long TEST_RECORD_DURATION_MILLIS = TEST_RECORD_DURATION_SEC * 1000;
98
99    /**
100     * Simulate how dumpsys gets the proto from mWifiMetrics, filter the proto bytes out and
101     * deserialize them into mDeserializedWifiMetrics
102     */
103    public void dumpProtoAndDeserialize() throws Exception {
104        ByteArrayOutputStream stream = new ByteArrayOutputStream();
105        PrintWriter writer = new PrintWriter(stream);
106        String[] args = new String[0];
107
108        when(mClock.getElapsedSinceBootMillis()).thenReturn(TEST_RECORD_DURATION_MILLIS);
109        //Test proto dump, by passing in proto arg option
110        args = new String[]{WifiMetrics.PROTO_DUMP_ARG};
111        mWifiMetrics.dump(null, writer, args);
112        writer.flush();
113        Pattern pattern = Pattern.compile(
114                "(?<=WifiMetrics:\\n)([\\s\\S]*)(?=EndWifiMetrics)");
115        Matcher matcher = pattern.matcher(stream.toString());
116        assertTrue("Proto Byte string found in WifiMetrics.dump():\n" + stream.toString(),
117                matcher.find());
118        String protoByteString = matcher.group(1);
119        byte[] protoBytes = Base64.decode(protoByteString, Base64.DEFAULT);
120        mDeserializedWifiMetrics = WifiMetricsProto.WifiLog.parseFrom(protoBytes);
121    }
122
123    /**
124     * Gets the 'clean dump' proto bytes from mWifiMetrics & deserializes it into
125     * mDeserializedWifiMetrics
126     */
127    public void cleanDumpProtoAndDeserialize() throws Exception {
128        ByteArrayOutputStream stream = new ByteArrayOutputStream();
129        PrintWriter writer = new PrintWriter(stream);
130        String[] args = new String[0];
131
132        when(mClock.getElapsedSinceBootMillis()).thenReturn(TEST_RECORD_DURATION_MILLIS);
133        //Test proto dump, by passing in proto arg option
134        args = new String[]{WifiMetrics.PROTO_DUMP_ARG, WifiMetrics.CLEAN_DUMP_ARG};
135        mWifiMetrics.dump(null, writer, args);
136        writer.flush();
137        String protoByteString = stream.toString();
138        byte[] protoBytes = Base64.decode(protoByteString, Base64.DEFAULT);
139        mDeserializedWifiMetrics = WifiMetricsProto.WifiLog.parseFrom(protoBytes);
140    }
141
142    /** Verifies that dump() includes the expected header */
143    @Test
144    public void stateDumpIncludesHeader() throws Exception {
145        assertStringContains(getStateDump(), "WifiMetrics");
146    }
147
148    /** Verifies that dump() includes correct alert count when there are no alerts. */
149    @Test
150    public void stateDumpAlertCountIsCorrectWithNoAlerts() throws Exception {
151        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=()");
152    }
153
154    /** Verifies that dump() includes correct alert count when there is one alert. */
155    @Test
156    public void stateDumpAlertCountIsCorrectWithOneAlert() throws Exception {
157        mWifiMetrics.incrementAlertReasonCount(1);
158        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,1)");
159    }
160
161    /** Verifies that dump() includes correct alert count when there are multiple alerts. */
162    @Test
163    public void stateDumpAlertCountIsCorrectWithMultipleAlerts() throws Exception {
164        mWifiMetrics.incrementAlertReasonCount(1);
165        mWifiMetrics.incrementAlertReasonCount(1);
166        mWifiMetrics.incrementAlertReasonCount(16);
167        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,2),(16,1)");
168    }
169
170    @Test
171    public void testDumpProtoAndDeserialize() throws Exception {
172        setAndIncrementMetrics();
173        dumpProtoAndDeserialize();
174        assertDeserializedMetricsCorrect();
175    }
176
177    private static final int NUM_OPEN_NETWORKS = 2;
178    private static final int NUM_PERSONAL_NETWORKS = 3;
179    private static final int NUM_ENTERPRISE_NETWORKS = 5;
180    private static final int NUM_SAVED_NETWORKS = NUM_OPEN_NETWORKS + NUM_PERSONAL_NETWORKS
181            + NUM_ENTERPRISE_NETWORKS;
182    private static final int NUM_HIDDEN_NETWORKS = NUM_OPEN_NETWORKS;
183    private static final int NUM_PASSPOINT_NETWORKS = NUM_ENTERPRISE_NETWORKS;
184    private static final int NUM_NETWORKS_ADDED_BY_USER = 1;
185    private static final int NUM_NETWORKS_ADDED_BY_APPS = NUM_SAVED_NETWORKS
186            - NUM_NETWORKS_ADDED_BY_USER;
187    private static final boolean TEST_VAL_IS_LOCATION_ENABLED = true;
188    private static final boolean IS_SCANNING_ALWAYS_ENABLED = true;
189    private static final int NUM_EMPTY_SCAN_RESULTS = 19;
190    private static final int NUM_NON_EMPTY_SCAN_RESULTS = 23;
191    private static final int NUM_SCAN_UNKNOWN = 1;
192    private static final int NUM_SCAN_SUCCESS = 2;
193    private static final int NUM_SCAN_FAILURE_INTERRUPTED = 3;
194    private static final int NUM_SCAN_FAILURE_INVALID_CONFIGURATION = 5;
195    private static final int NUM_WIFI_UNKNOWN_SCREEN_OFF = 3;
196    private static final int NUM_WIFI_UNKNOWN_SCREEN_ON = 5;
197    private static final int NUM_WIFI_ASSOCIATED_SCREEN_OFF = 7;
198    private static final int NUM_WIFI_ASSOCIATED_SCREEN_ON = 11;
199    private static final int NUM_CONNECTIVITY_WATCHDOG_PNO_GOOD = 11;
200    private static final int NUM_CONNECTIVITY_WATCHDOG_PNO_BAD = 12;
201    private static final int NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_GOOD = 13;
202    private static final int NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_BAD = 14;
203    private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS = 1;
204    private static final int NUM_LAST_RESORT_WATCHDOG_BAD_ASSOCIATION_NETWORKS_TOTAL = 2;
205    private static final int NUM_LAST_RESORT_WATCHDOG_BAD_AUTHENTICATION_NETWORKS_TOTAL = 3;
206    private static final int NUM_LAST_RESORT_WATCHDOG_BAD_DHCP_NETWORKS_TOTAL = 4;
207    private static final int NUM_LAST_RESORT_WATCHDOG_BAD_OTHER_NETWORKS_TOTAL = 5;
208    private static final int NUM_LAST_RESORT_WATCHDOG_AVAILABLE_NETWORKS_TOTAL = 6;
209    private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_ASSOCIATION = 7;
210    private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_AUTHENTICATION = 8;
211    private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_DHCP = 9;
212    private static final int NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER = 10;
213    private static final int NUM_LAST_RESORT_WATCHDOG_SUCCESSES = 5;
214    private static final int NUM_RSSI_LEVELS_TO_INCREMENT = 20;
215    private static final int FIRST_RSSI_LEVEL = -80;
216    private static final int NUM_OPEN_NETWORK_SCAN_RESULTS = 1;
217    private static final int NUM_PERSONAL_NETWORK_SCAN_RESULTS = 4;
218    private static final int NUM_ENTERPRISE_NETWORK_SCAN_RESULTS = 3;
219    private static final int NUM_HIDDEN_NETWORK_SCAN_RESULTS = 1;
220    private static final int NUM_HOTSPOT2_R1_NETWORK_SCAN_RESULTS = 1;
221    private static final int NUM_HOTSPOT2_R2_NETWORK_SCAN_RESULTS = 2;
222    private static final int NUM_SCANS = 5;
223    private static final int NUM_TOTAL_SCAN_RESULTS = 8;
224    private static final int MIN_RSSI_LEVEL = -127;
225    private static final int MAX_RSSI_LEVEL = 0;
226    private static final int WIFI_SCORE_RANGE_MIN = 0;
227    private static final int NUM_WIFI_SCORES_TO_INCREMENT = 20;
228    private static final int WIFI_SCORE_RANGE_MAX = 60;
229    private static final int NUM_OUT_OF_BOUND_ENTRIES = 10;
230    private static final int MAX_NUM_SOFTAP_RETURN_CODES = 3;
231    private static final int NUM_SOFTAP_START_SUCCESS = 3;
232    private static final int NUM_SOFTAP_FAILED_GENERAL_ERROR = 2;
233    private static final int NUM_SOFTAP_FAILED_NO_CHANNEL = 1;
234
235    private ScanDetail buildMockScanDetail(boolean hidden, NetworkDetail.HSRelease hSRelease,
236            String capabilities) {
237        ScanDetail mockScanDetail = mock(ScanDetail.class);
238        NetworkDetail mockNetworkDetail = mock(NetworkDetail.class);
239        ScanResult mockScanResult = mock(ScanResult.class);
240        when(mockScanDetail.getNetworkDetail()).thenReturn(mockNetworkDetail);
241        when(mockScanDetail.getScanResult()).thenReturn(mockScanResult);
242        when(mockNetworkDetail.isHiddenBeaconFrame()).thenReturn(hidden);
243        when(mockNetworkDetail.getHSRelease()).thenReturn(hSRelease);
244        mockScanResult.capabilities = capabilities;
245        return mockScanDetail;
246    }
247
248    private List<ScanDetail> buildMockScanDetailList() {
249        List<ScanDetail> mockScanDetails = new ArrayList<ScanDetail>();
250        mockScanDetails.add(buildMockScanDetail(true, null, "[ESS]"));
251        mockScanDetails.add(buildMockScanDetail(false, null, "[WPA2-PSK-CCMP][ESS]"));
252        mockScanDetails.add(buildMockScanDetail(false, null, "[WPA-PSK-CCMP]"));
253        mockScanDetails.add(buildMockScanDetail(false, null, "[WPA-PSK-CCMP]"));
254        mockScanDetails.add(buildMockScanDetail(false, null, "[WEP]"));
255        mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R2,
256                "[WPA-EAP-CCMP]"));
257        mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R2,
258                "[WPA2-EAP+FT/EAP-CCMP]"));
259        mockScanDetails.add(buildMockScanDetail(false, NetworkDetail.HSRelease.R1,
260                "[WPA-EAP-CCMP]"));
261        return mockScanDetails;
262    }
263
264    private List<WifiConfiguration> buildSavedNetworkList() {
265        List<WifiConfiguration> testSavedNetworks = new ArrayList<WifiConfiguration>();
266        for (int i = 0; i < NUM_OPEN_NETWORKS; i++) {
267            testSavedNetworks.add(WifiConfigurationTestUtil.createOpenHiddenNetwork());
268        }
269        for (int i = 0; i < NUM_PERSONAL_NETWORKS; i++) {
270            testSavedNetworks.add(WifiConfigurationTestUtil.createPskNetwork());
271        }
272        for (int i = 0; i < NUM_ENTERPRISE_NETWORKS; i++) {
273            // Passpoint networks are counted in both Passpoint and Enterprise counters
274            testSavedNetworks.add(WifiConfigurationTestUtil.createPasspointNetwork());
275        }
276        testSavedNetworks.get(0).selfAdded = true;
277        return testSavedNetworks;
278    }
279
280    /**
281     * Set simple metrics, increment others
282     */
283    public void setAndIncrementMetrics() throws Exception {
284        mWifiMetrics.updateSavedNetworks(buildSavedNetworkList());
285        mWifiMetrics.setIsLocationEnabled(TEST_VAL_IS_LOCATION_ENABLED);
286        mWifiMetrics.setIsScanningAlwaysEnabled(IS_SCANNING_ALWAYS_ENABLED);
287
288        for (int i = 0; i < NUM_EMPTY_SCAN_RESULTS; i++) {
289            mWifiMetrics.incrementEmptyScanResultCount();
290        }
291        for (int i = 0; i < NUM_NON_EMPTY_SCAN_RESULTS; i++) {
292            mWifiMetrics.incrementNonEmptyScanResultCount();
293        }
294        mWifiMetrics.incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN,
295                NUM_SCAN_UNKNOWN);
296        mWifiMetrics.incrementScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS,
297                NUM_SCAN_SUCCESS);
298        mWifiMetrics.incrementScanReturnEntry(
299                WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED,
300                NUM_SCAN_FAILURE_INTERRUPTED);
301        mWifiMetrics.incrementScanReturnEntry(
302                WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION,
303                NUM_SCAN_FAILURE_INVALID_CONFIGURATION);
304        for (int i = 0; i < NUM_WIFI_UNKNOWN_SCREEN_OFF; i++) {
305            mWifiMetrics.incrementWifiSystemScanStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN,
306                    false);
307        }
308        for (int i = 0; i < NUM_WIFI_UNKNOWN_SCREEN_ON; i++) {
309            mWifiMetrics.incrementWifiSystemScanStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN,
310                    true);
311        }
312        for (int i = 0; i < NUM_WIFI_ASSOCIATED_SCREEN_OFF; i++) {
313            mWifiMetrics.incrementWifiSystemScanStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED,
314                    false);
315        }
316        for (int i = 0; i < NUM_WIFI_ASSOCIATED_SCREEN_ON; i++) {
317            mWifiMetrics.incrementWifiSystemScanStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED,
318                    true);
319        }
320        for (int i = 0; i < NUM_CONNECTIVITY_WATCHDOG_PNO_GOOD; i++) {
321            mWifiMetrics.incrementNumConnectivityWatchdogPnoGood();
322        }
323        for (int i = 0; i < NUM_CONNECTIVITY_WATCHDOG_PNO_BAD; i++) {
324            mWifiMetrics.incrementNumConnectivityWatchdogPnoBad();
325        }
326        for (int i = 0; i < NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_GOOD; i++) {
327            mWifiMetrics.incrementNumConnectivityWatchdogBackgroundGood();
328        }
329        for (int i = 0; i < NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_BAD; i++) {
330            mWifiMetrics.incrementNumConnectivityWatchdogBackgroundBad();
331        }
332        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS; i++) {
333            mWifiMetrics.incrementNumLastResortWatchdogTriggers();
334        }
335        mWifiMetrics.addCountToNumLastResortWatchdogBadAssociationNetworksTotal(
336                NUM_LAST_RESORT_WATCHDOG_BAD_ASSOCIATION_NETWORKS_TOTAL);
337        mWifiMetrics.addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(
338                NUM_LAST_RESORT_WATCHDOG_BAD_AUTHENTICATION_NETWORKS_TOTAL);
339        mWifiMetrics.addCountToNumLastResortWatchdogBadDhcpNetworksTotal(
340                NUM_LAST_RESORT_WATCHDOG_BAD_DHCP_NETWORKS_TOTAL);
341        mWifiMetrics.addCountToNumLastResortWatchdogBadOtherNetworksTotal(
342                NUM_LAST_RESORT_WATCHDOG_BAD_OTHER_NETWORKS_TOTAL);
343        mWifiMetrics.addCountToNumLastResortWatchdogAvailableNetworksTotal(
344                NUM_LAST_RESORT_WATCHDOG_AVAILABLE_NETWORKS_TOTAL);
345        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_ASSOCIATION; i++) {
346            mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadAssociation();
347        }
348        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_AUTHENTICATION; i++) {
349            mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadAuthentication();
350        }
351        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_DHCP; i++) {
352            mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadDhcp();
353        }
354        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER; i++) {
355            mWifiMetrics.incrementNumLastResortWatchdogTriggersWithBadOther();
356        }
357        for (int i = 0; i < NUM_LAST_RESORT_WATCHDOG_SUCCESSES; i++) {
358            mWifiMetrics.incrementNumLastResortWatchdogSuccesses();
359        }
360        for (int i = 0; i < NUM_RSSI_LEVELS_TO_INCREMENT; i++) {
361            for (int j = 0; j <= i; j++) {
362                mWifiMetrics.incrementRssiPollRssiCount(MIN_RSSI_LEVEL + i);
363            }
364        }
365        for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) {
366            mWifiMetrics.incrementRssiPollRssiCount(MIN_RSSI_LEVEL - i);
367        }
368        for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) {
369            mWifiMetrics.incrementRssiPollRssiCount(MAX_RSSI_LEVEL + i);
370        }
371        // Test alert-reason clamping.
372        mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MIN - 1);
373        mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MAX + 1);
374        // Simple cases for alert reason.
375        mWifiMetrics.incrementAlertReasonCount(1);
376        mWifiMetrics.incrementAlertReasonCount(1);
377        mWifiMetrics.incrementAlertReasonCount(1);
378        mWifiMetrics.incrementAlertReasonCount(2);
379        List<ScanDetail> mockScanDetails = buildMockScanDetailList();
380        for (int i = 0; i < NUM_SCANS; i++) {
381            mWifiMetrics.countScanResults(mockScanDetails);
382        }
383        for (int score = WIFI_SCORE_RANGE_MIN; score < NUM_WIFI_SCORES_TO_INCREMENT; score++) {
384            for (int offset = 0; offset <= score; offset++) {
385                mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MIN + score);
386            }
387        }
388        for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) {
389            mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MIN - i);
390        }
391        for (int i = 1; i < NUM_OUT_OF_BOUND_ENTRIES; i++) {
392            mWifiMetrics.incrementWifiScoreCount(WIFI_SCORE_RANGE_MAX + i);
393        }
394
395        // increment soft ap start return codes
396        for (int i = 0; i < NUM_SOFTAP_START_SUCCESS; i++) {
397            mWifiMetrics.incrementSoftApStartResult(true, 0);
398        }
399        for (int i = 0; i < NUM_SOFTAP_FAILED_GENERAL_ERROR; i++) {
400            mWifiMetrics.incrementSoftApStartResult(false, WifiManager.SAP_START_FAILURE_GENERAL);
401        }
402        for (int i = 0; i < NUM_SOFTAP_FAILED_NO_CHANNEL; i++) {
403            mWifiMetrics.incrementSoftApStartResult(false,
404                    WifiManager.SAP_START_FAILURE_NO_CHANNEL);
405        }
406    }
407
408    /**
409     * Assert that values in deserializedWifiMetrics match those set in 'setAndIncrementMetrics'
410     */
411    public void assertDeserializedMetricsCorrect() throws Exception {
412        assertEquals("mDeserializedWifiMetrics.numSavedNetworks == NUM_SAVED_NETWORKS",
413                mDeserializedWifiMetrics.numSavedNetworks, NUM_SAVED_NETWORKS);
414        assertEquals("mDeserializedWifiMetrics.numOpenNetworks == NUM_OPEN_NETWORKS",
415                mDeserializedWifiMetrics.numOpenNetworks, NUM_OPEN_NETWORKS);
416        assertEquals("mDeserializedWifiMetrics.numPersonalNetworks == NUM_PERSONAL_NETWORKS",
417                mDeserializedWifiMetrics.numPersonalNetworks, NUM_PERSONAL_NETWORKS);
418        assertEquals("mDeserializedWifiMetrics.numEnterpriseNetworks "
419                        + "== NUM_ENTERPRISE_NETWORKS",
420                mDeserializedWifiMetrics.numEnterpriseNetworks, NUM_ENTERPRISE_NETWORKS);
421        assertEquals("mDeserializedWifiMetrics.numNetworksAddedByUser "
422                        + "== NUM_NETWORKS_ADDED_BY_USER",
423                mDeserializedWifiMetrics.numNetworksAddedByUser, NUM_NETWORKS_ADDED_BY_USER);
424        assertEquals(NUM_HIDDEN_NETWORKS, mDeserializedWifiMetrics.numHiddenNetworks);
425        assertEquals(NUM_PASSPOINT_NETWORKS, mDeserializedWifiMetrics.numPasspointNetworks);
426        assertEquals("mDeserializedWifiMetrics.numNetworksAddedByApps "
427                        + "== NUM_NETWORKS_ADDED_BY_APPS",
428                mDeserializedWifiMetrics.numNetworksAddedByApps, NUM_NETWORKS_ADDED_BY_APPS);
429        assertEquals("mDeserializedWifiMetrics.isLocationEnabled == TEST_VAL_IS_LOCATION_ENABLED",
430                mDeserializedWifiMetrics.isLocationEnabled, TEST_VAL_IS_LOCATION_ENABLED);
431        assertEquals("mDeserializedWifiMetrics.isScanningAlwaysEnabled "
432                        + "== IS_SCANNING_ALWAYS_ENABLED",
433                mDeserializedWifiMetrics.isScanningAlwaysEnabled, IS_SCANNING_ALWAYS_ENABLED);
434        assertEquals("mDeserializedWifiMetrics.numEmptyScanResults == NUM_EMPTY_SCAN_RESULTS",
435                mDeserializedWifiMetrics.numEmptyScanResults, NUM_EMPTY_SCAN_RESULTS);
436        assertEquals("mDeserializedWifiMetrics.numNonEmptyScanResults == "
437                        + "NUM_NON_EMPTY_SCAN_RESULTS",
438                mDeserializedWifiMetrics.numNonEmptyScanResults, NUM_NON_EMPTY_SCAN_RESULTS);
439        assertScanReturnEntryEquals(WifiMetricsProto.WifiLog.SCAN_UNKNOWN,
440                NUM_SCAN_UNKNOWN);
441        assertScanReturnEntryEquals(WifiMetricsProto.WifiLog.SCAN_SUCCESS,
442                NUM_SCAN_SUCCESS);
443        assertScanReturnEntryEquals(WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED,
444                NUM_SCAN_FAILURE_INTERRUPTED);
445        assertScanReturnEntryEquals(WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION,
446                NUM_SCAN_FAILURE_INVALID_CONFIGURATION);
447        assertSystemStateEntryEquals(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false,
448                NUM_WIFI_UNKNOWN_SCREEN_OFF);
449        assertSystemStateEntryEquals(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true,
450                NUM_WIFI_UNKNOWN_SCREEN_ON);
451        assertSystemStateEntryEquals(
452                WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false, NUM_WIFI_ASSOCIATED_SCREEN_OFF);
453        assertSystemStateEntryEquals(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true,
454                NUM_WIFI_ASSOCIATED_SCREEN_ON);
455        assertEquals(mDeserializedWifiMetrics.numConnectivityWatchdogPnoGood,
456                NUM_CONNECTIVITY_WATCHDOG_PNO_GOOD);
457        assertEquals(mDeserializedWifiMetrics.numConnectivityWatchdogPnoBad,
458                NUM_CONNECTIVITY_WATCHDOG_PNO_BAD);
459        assertEquals(mDeserializedWifiMetrics.numConnectivityWatchdogBackgroundGood,
460                NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_GOOD);
461        assertEquals(mDeserializedWifiMetrics.numConnectivityWatchdogBackgroundBad,
462                NUM_CONNECTIVITY_WATCHDOG_BACKGROUND_BAD);
463        assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS,
464                mDeserializedWifiMetrics.numLastResortWatchdogTriggers);
465        assertEquals(NUM_LAST_RESORT_WATCHDOG_BAD_ASSOCIATION_NETWORKS_TOTAL,
466                mDeserializedWifiMetrics.numLastResortWatchdogBadAssociationNetworksTotal);
467        assertEquals(NUM_LAST_RESORT_WATCHDOG_BAD_AUTHENTICATION_NETWORKS_TOTAL,
468                mDeserializedWifiMetrics.numLastResortWatchdogBadAuthenticationNetworksTotal);
469        assertEquals(NUM_LAST_RESORT_WATCHDOG_BAD_DHCP_NETWORKS_TOTAL,
470                mDeserializedWifiMetrics.numLastResortWatchdogBadDhcpNetworksTotal);
471        assertEquals(NUM_LAST_RESORT_WATCHDOG_BAD_OTHER_NETWORKS_TOTAL,
472                mDeserializedWifiMetrics.numLastResortWatchdogBadOtherNetworksTotal);
473        assertEquals(NUM_LAST_RESORT_WATCHDOG_AVAILABLE_NETWORKS_TOTAL,
474                mDeserializedWifiMetrics.numLastResortWatchdogAvailableNetworksTotal);
475        assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_ASSOCIATION,
476                mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadAssociation);
477        assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_AUTHENTICATION,
478                mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadAuthentication);
479        assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_DHCP,
480                mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadDhcp);
481        assertEquals(NUM_LAST_RESORT_WATCHDOG_TRIGGERS_WITH_BAD_OTHER,
482                mDeserializedWifiMetrics.numLastResortWatchdogTriggersWithBadOther);
483        assertEquals(NUM_LAST_RESORT_WATCHDOG_SUCCESSES,
484                mDeserializedWifiMetrics.numLastResortWatchdogSuccesses);
485        assertEquals(TEST_RECORD_DURATION_SEC,
486                mDeserializedWifiMetrics.recordDurationSec);
487        for (int i = 0; i < NUM_RSSI_LEVELS_TO_INCREMENT; i++) {
488            assertEquals(MIN_RSSI_LEVEL + i, mDeserializedWifiMetrics.rssiPollRssiCount[i].rssi);
489            assertEquals(i + 1, mDeserializedWifiMetrics.rssiPollRssiCount[i].count);
490        }
491        StringBuilder sb_rssi = new StringBuilder();
492        sb_rssi.append("Number of RSSIs = " + mDeserializedWifiMetrics.rssiPollRssiCount.length);
493        assertTrue(sb_rssi.toString(), (mDeserializedWifiMetrics.rssiPollRssiCount.length
494                     <= (MAX_RSSI_LEVEL - MIN_RSSI_LEVEL + 1)));
495        assertEquals(2, mDeserializedWifiMetrics.alertReasonCount[0].count);  // Clamped reasons.
496        assertEquals(3, mDeserializedWifiMetrics.alertReasonCount[1].count);
497        assertEquals(1, mDeserializedWifiMetrics.alertReasonCount[2].count);
498        assertEquals(3, mDeserializedWifiMetrics.alertReasonCount.length);
499        assertEquals(NUM_TOTAL_SCAN_RESULTS * NUM_SCANS,
500                mDeserializedWifiMetrics.numTotalScanResults);
501        assertEquals(NUM_OPEN_NETWORK_SCAN_RESULTS * NUM_SCANS,
502                mDeserializedWifiMetrics.numOpenNetworkScanResults);
503        assertEquals(NUM_PERSONAL_NETWORK_SCAN_RESULTS * NUM_SCANS,
504                mDeserializedWifiMetrics.numPersonalNetworkScanResults);
505        assertEquals(NUM_ENTERPRISE_NETWORK_SCAN_RESULTS * NUM_SCANS,
506                mDeserializedWifiMetrics.numEnterpriseNetworkScanResults);
507        assertEquals(NUM_HIDDEN_NETWORK_SCAN_RESULTS * NUM_SCANS,
508                mDeserializedWifiMetrics.numHiddenNetworkScanResults);
509        assertEquals(NUM_HOTSPOT2_R1_NETWORK_SCAN_RESULTS * NUM_SCANS,
510                mDeserializedWifiMetrics.numHotspot2R1NetworkScanResults);
511        assertEquals(NUM_HOTSPOT2_R2_NETWORK_SCAN_RESULTS * NUM_SCANS,
512                mDeserializedWifiMetrics.numHotspot2R2NetworkScanResults);
513        assertEquals(NUM_SCANS,
514                mDeserializedWifiMetrics.numScans);
515        for (int score_index = 0; score_index < NUM_WIFI_SCORES_TO_INCREMENT; score_index++) {
516            assertEquals(WIFI_SCORE_RANGE_MIN + score_index,
517                    mDeserializedWifiMetrics.wifiScoreCount[score_index].score);
518            assertEquals(score_index + 1,
519                    mDeserializedWifiMetrics.wifiScoreCount[score_index].count);
520        }
521        StringBuilder sb_wifi_score = new StringBuilder();
522        sb_wifi_score.append("Number of wifi_scores = "
523                + mDeserializedWifiMetrics.wifiScoreCount.length);
524        assertTrue(sb_wifi_score.toString(), (mDeserializedWifiMetrics.wifiScoreCount.length
525                <= (WIFI_SCORE_RANGE_MAX - WIFI_SCORE_RANGE_MIN + 1)));
526        StringBuilder sb_wifi_limits = new StringBuilder();
527        sb_wifi_limits.append("Wifi Score limit is " +  NetworkAgent.WIFI_BASE_SCORE
528                + ">= " + WIFI_SCORE_RANGE_MAX);
529        assertTrue(sb_wifi_limits.toString(), NetworkAgent.WIFI_BASE_SCORE <= WIFI_SCORE_RANGE_MAX);
530        assertEquals(MAX_NUM_SOFTAP_RETURN_CODES, mDeserializedWifiMetrics.softApReturnCode.length);
531        assertEquals(WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY,
532                     mDeserializedWifiMetrics.softApReturnCode[0].startResult);
533        assertEquals(NUM_SOFTAP_START_SUCCESS, mDeserializedWifiMetrics.softApReturnCode[0].count);
534        assertEquals(WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR,
535                     mDeserializedWifiMetrics.softApReturnCode[1].startResult);
536        assertEquals(NUM_SOFTAP_FAILED_GENERAL_ERROR,
537                     mDeserializedWifiMetrics.softApReturnCode[1].count);
538        assertEquals(WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL,
539                     mDeserializedWifiMetrics.softApReturnCode[2].startResult);
540        assertEquals(NUM_SOFTAP_FAILED_NO_CHANNEL,
541                     mDeserializedWifiMetrics.softApReturnCode[2].count);
542    }
543
544    /**
545     *  Assert deserialized metrics Scan Return Entry equals count
546     */
547    public void assertScanReturnEntryEquals(int returnCode, int count) {
548        for (int i = 0; i < mDeserializedWifiMetrics.scanReturnEntries.length; i++) {
549            if (mDeserializedWifiMetrics.scanReturnEntries[i].scanReturnCode == returnCode) {
550                assertEquals(mDeserializedWifiMetrics.scanReturnEntries[i].scanResultsCount, count);
551                return;
552            }
553        }
554        assertEquals(null, count);
555    }
556
557    /**
558     *  Assert deserialized metrics SystemState entry equals count
559     */
560    public void assertSystemStateEntryEquals(int state, boolean screenOn, int count) {
561        for (int i = 0; i < mDeserializedWifiMetrics.wifiSystemStateEntries.length; i++) {
562            if (mDeserializedWifiMetrics.wifiSystemStateEntries[i].wifiState == state
563                    && mDeserializedWifiMetrics.wifiSystemStateEntries[i].isScreenOn == screenOn) {
564                assertEquals(mDeserializedWifiMetrics.wifiSystemStateEntries[i].wifiStateCount,
565                        count);
566                return;
567            }
568        }
569        assertEquals(null, count);
570    }
571    /**
572     * Combination of all other WifiMetrics unit tests, an internal-integration test, or functional
573     * test
574     */
575    @Test
576    public void setMetricsSerializeDeserializeAssertMetricsSame() throws Exception {
577        setAndIncrementMetrics();
578        startAndEndConnectionEventSucceeds();
579        dumpProtoAndDeserialize();
580        assertDeserializedMetricsCorrect();
581        assertEquals("mDeserializedWifiMetrics.connectionEvent.length",
582                2, mDeserializedWifiMetrics.connectionEvent.length);
583        //<TODO> test individual connectionEvents for correctness,
584        // check scanReturnEntries & wifiSystemStateEntries counts and individual elements
585        // pending their implementation</TODO>
586    }
587
588    private static final String SSID = "red";
589    private static final int CONFIG_DTIM = 3;
590    private static final int NETWORK_DETAIL_WIFIMODE = 5;
591    private static final int NETWORK_DETAIL_DTIM = 7;
592    private static final int SCAN_RESULT_LEVEL = -30;
593    /**
594     * Test that WifiMetrics is correctly getting data from ScanDetail and WifiConfiguration
595     */
596    @Test
597    public void testScanDetailAndWifiConfigurationUsage() throws Exception {
598        //Setup mock configs and scan details
599        NetworkDetail networkDetail = mock(NetworkDetail.class);
600        when(networkDetail.getWifiMode()).thenReturn(NETWORK_DETAIL_WIFIMODE);
601        when(networkDetail.getSSID()).thenReturn(SSID);
602        when(networkDetail.getDtimInterval()).thenReturn(NETWORK_DETAIL_DTIM);
603        ScanResult scanResult = mock(ScanResult.class);
604        scanResult.level = SCAN_RESULT_LEVEL;
605        WifiConfiguration config = mock(WifiConfiguration.class);
606        config.SSID = "\"" + SSID + "\"";
607        config.dtimInterval = CONFIG_DTIM;
608        WifiConfiguration.NetworkSelectionStatus networkSelectionStat =
609                mock(WifiConfiguration.NetworkSelectionStatus.class);
610        when(networkSelectionStat.getCandidate()).thenReturn(scanResult);
611        when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStat);
612        ScanDetail scanDetail = mock(ScanDetail.class);
613        when(scanDetail.getNetworkDetail()).thenReturn(networkDetail);
614        when(scanDetail.getScanResult()).thenReturn(scanResult);
615
616        //Create a connection event using only the config
617        mWifiMetrics.startConnectionEvent(config, "Red",
618                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
619        mWifiMetrics.endConnectionEvent(
620                WifiMetrics.ConnectionEvent.FAILURE_NONE,
621                WifiMetricsProto.ConnectionEvent.HLF_NONE);
622
623        //Create a connection event using the config and a scan detail
624        mWifiMetrics.startConnectionEvent(config, "Green",
625                WifiMetricsProto.ConnectionEvent.ROAM_NONE);
626        mWifiMetrics.setConnectionScanDetail(scanDetail);
627        mWifiMetrics.endConnectionEvent(
628                WifiMetrics.ConnectionEvent.FAILURE_NONE,
629                WifiMetricsProto.ConnectionEvent.HLF_NONE);
630
631        //Dump proto from mWifiMetrics and deserialize it to mDeserializedWifiMetrics
632        dumpProtoAndDeserialize();
633
634        //Check that the correct values are being flowed through
635        assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 2);
636        assertEquals(mDeserializedWifiMetrics.connectionEvent[0].routerFingerprint.dtim,
637                CONFIG_DTIM);
638        assertEquals(mDeserializedWifiMetrics.connectionEvent[0].signalStrength, SCAN_RESULT_LEVEL);
639        assertEquals(mDeserializedWifiMetrics.connectionEvent[1].routerFingerprint.dtim,
640                NETWORK_DETAIL_DTIM);
641        assertEquals(mDeserializedWifiMetrics.connectionEvent[1].signalStrength,
642                SCAN_RESULT_LEVEL);
643        assertEquals(mDeserializedWifiMetrics.connectionEvent[1].routerFingerprint.routerTechnology,
644                NETWORK_DETAIL_WIFIMODE);
645    }
646
647    /**
648     * Test that WifiMetrics is being cleared after dumping via proto
649     */
650    @Test
651    public void testMetricsClearedAfterProtoRequested() throws Exception {
652        // Create 3 ConnectionEvents
653        mWifiMetrics.startConnectionEvent(null, "RED",
654                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
655        mWifiMetrics.endConnectionEvent(
656                WifiMetrics.ConnectionEvent.FAILURE_NONE,
657                WifiMetricsProto.ConnectionEvent.HLF_NONE);
658        mWifiMetrics.startConnectionEvent(null, "YELLOW",
659                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
660        mWifiMetrics.endConnectionEvent(
661                WifiMetrics.ConnectionEvent.FAILURE_NONE,
662                WifiMetricsProto.ConnectionEvent.HLF_NONE);
663        mWifiMetrics.startConnectionEvent(null, "GREEN",
664                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
665        mWifiMetrics.endConnectionEvent(
666                WifiMetrics.ConnectionEvent.FAILURE_NONE,
667                WifiMetricsProto.ConnectionEvent.HLF_NONE);
668        mWifiMetrics.startConnectionEvent(null, "ORANGE",
669                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
670        mWifiMetrics.endConnectionEvent(
671                WifiMetrics.ConnectionEvent.FAILURE_NONE,
672                WifiMetricsProto.ConnectionEvent.HLF_NONE);
673
674        //Dump proto and deserialize
675        //This should clear all the metrics in mWifiMetrics,
676        dumpProtoAndDeserialize();
677        //Check there are only 3 connection events
678        assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 4);
679        assertEquals(mDeserializedWifiMetrics.rssiPollRssiCount.length, 0);
680        assertEquals(mDeserializedWifiMetrics.alertReasonCount.length, 0);
681
682        // Create 2 ConnectionEvents
683        mWifiMetrics.startConnectionEvent(null,  "BLUE",
684                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
685        mWifiMetrics.endConnectionEvent(
686                WifiMetrics.ConnectionEvent.FAILURE_NONE,
687                WifiMetricsProto.ConnectionEvent.HLF_NONE);
688        mWifiMetrics.startConnectionEvent(null, "RED",
689                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
690        mWifiMetrics.endConnectionEvent(
691                WifiMetrics.ConnectionEvent.FAILURE_NONE,
692                WifiMetricsProto.ConnectionEvent.HLF_NONE);
693
694        //Dump proto and deserialize
695        dumpProtoAndDeserialize();
696        //Check there are only 2 connection events
697        assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 2);
698    }
699
700    /**
701     * Tests that after setting metrics values they can be serialized and deserialized with the
702     *   $ adb shell dumpsys wifi wifiMetricsProto clean
703     */
704    @Test
705    public void testClearMetricsDump() throws Exception {
706        setAndIncrementMetrics();
707        startAndEndConnectionEventSucceeds();
708        cleanDumpProtoAndDeserialize();
709        assertDeserializedMetricsCorrect();
710        assertEquals("mDeserializedWifiMetrics.connectionEvent.length",
711                2, mDeserializedWifiMetrics.connectionEvent.length);
712    }
713
714    private static final int NUM_REPEATED_DELTAS = 7;
715    private static final int REPEATED_DELTA = 0;
716    private static final int SINGLE_GOOD_DELTA = 1;
717    private static final int SINGLE_TIMEOUT_DELTA = 2;
718    private static final int NUM_REPEATED_BOUND_DELTAS = 2;
719    private static final int MAX_DELTA_LEVEL = 127;
720    private static final int MIN_DELTA_LEVEL = -127;
721    private static final int ARBITRARY_DELTA_LEVEL = 20;
722
723    /**
724     * Sunny day RSSI delta logging scenario.
725     * Logs one rssi delta value multiple times
726     * Logs a different delta value a single time
727     */
728    @Test
729    public void testRssiDeltasSuccessfulLogging() throws Exception {
730        // Generate some repeated deltas
731        for (int i = 0; i < NUM_REPEATED_DELTAS; i++) {
732            generateRssiDelta(MIN_RSSI_LEVEL, REPEATED_DELTA,
733                    WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
734        }
735        // Generate a single delta
736        generateRssiDelta(MIN_RSSI_LEVEL, SINGLE_GOOD_DELTA,
737                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
738        dumpProtoAndDeserialize();
739        assertEquals(2, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
740        // Check the repeated deltas
741        assertEquals(NUM_REPEATED_DELTAS, mDeserializedWifiMetrics.rssiPollDeltaCount[0].count);
742        assertEquals(REPEATED_DELTA, mDeserializedWifiMetrics.rssiPollDeltaCount[0].rssi);
743        // Check the single delta
744        assertEquals(1, mDeserializedWifiMetrics.rssiPollDeltaCount[1].count);
745        assertEquals(SINGLE_GOOD_DELTA, mDeserializedWifiMetrics.rssiPollDeltaCount[1].rssi);
746    }
747
748    /**
749     * Tests that Rssi Delta events whose scanResult and Rssi Poll come too far apart, timeout,
750     * and are not logged.
751     */
752    @Test
753    public void testRssiDeltasTimeout() throws Exception {
754        // Create timed out rssi deltas
755        generateRssiDelta(MIN_RSSI_LEVEL, REPEATED_DELTA,
756                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS + 1);
757        generateRssiDelta(MIN_RSSI_LEVEL, SINGLE_TIMEOUT_DELTA,
758                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS + 1);
759        dumpProtoAndDeserialize();
760        assertEquals(0, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
761    }
762
763    /**
764     * Tests the exact inclusive boundaries of RSSI delta logging.
765     */
766    @Test
767    public void testRssiDeltaSuccessfulLoggingExactBounds() throws Exception {
768        generateRssiDelta(MIN_RSSI_LEVEL, MAX_DELTA_LEVEL,
769                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
770        generateRssiDelta(MAX_RSSI_LEVEL, MIN_DELTA_LEVEL,
771                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
772        dumpProtoAndDeserialize();
773        assertEquals(2, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
774        assertEquals(MIN_DELTA_LEVEL, mDeserializedWifiMetrics.rssiPollDeltaCount[0].rssi);
775        assertEquals(1, mDeserializedWifiMetrics.rssiPollDeltaCount[0].count);
776        assertEquals(MAX_DELTA_LEVEL, mDeserializedWifiMetrics.rssiPollDeltaCount[1].rssi);
777        assertEquals(1, mDeserializedWifiMetrics.rssiPollDeltaCount[1].count);
778    }
779
780    /**
781     * Tests the exact exclusive boundaries of RSSI delta logging.
782     * This test ensures that too much data is not generated.
783     */
784    @Test
785    public void testRssiDeltaOutOfBounds() throws Exception {
786        generateRssiDelta(MIN_RSSI_LEVEL, MAX_DELTA_LEVEL + 1,
787                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
788        generateRssiDelta(MAX_RSSI_LEVEL, MIN_DELTA_LEVEL - 1,
789                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS);
790        dumpProtoAndDeserialize();
791        assertEquals(0, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
792    }
793
794    /**
795     * This test ensures no rssi Delta is logged after an unsuccessful ConnectionEvent
796     */
797    @Test
798    public void testUnsuccesfulConnectionEventRssiDeltaIsNotLogged() throws Exception {
799        generateRssiDelta(MIN_RSSI_LEVEL, ARBITRARY_DELTA_LEVEL,
800                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS,
801                false, // successfulConnectionEvent
802                true, // completeConnectionEvent
803                true, // useValidScanResult
804                true // dontDeserializeBeforePoll
805        );
806
807        dumpProtoAndDeserialize();
808        assertEquals(0, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
809    }
810
811    /**
812     * This test ensures rssi Deltas can be logged during a ConnectionEvent
813     */
814    @Test
815    public void testIncompleteConnectionEventRssiDeltaIsLogged() throws Exception {
816        generateRssiDelta(MIN_RSSI_LEVEL, ARBITRARY_DELTA_LEVEL,
817                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS,
818                true, // successfulConnectionEvent
819                false, // completeConnectionEvent
820                true, // useValidScanResult
821                true // dontDeserializeBeforePoll
822        );
823        dumpProtoAndDeserialize();
824        assertEquals(1, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
825        assertEquals(ARBITRARY_DELTA_LEVEL, mDeserializedWifiMetrics.rssiPollDeltaCount[0].rssi);
826        assertEquals(1, mDeserializedWifiMetrics.rssiPollDeltaCount[0].count);
827    }
828
829    /**
830     * This test ensures that no delta is logged for a null ScanResult Candidate
831     */
832    @Test
833    public void testRssiDeltaNotLoggedForNullCandidateScanResult() throws Exception {
834        generateRssiDelta(MIN_RSSI_LEVEL, ARBITRARY_DELTA_LEVEL,
835                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS,
836                true, // successfulConnectionEvent
837                true, // completeConnectionEvent
838                false, // useValidScanResult
839                true // dontDeserializeBeforePoll
840        );
841        dumpProtoAndDeserialize();
842        assertEquals(0, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
843    }
844
845    /**
846     * This test ensures that Rssi Deltas are not logged over a 'clear()' call (Metrics Serialized)
847     */
848    @Test
849    public void testMetricsSerializedDuringRssiDeltaEventLogsNothing() throws Exception {
850        generateRssiDelta(MIN_RSSI_LEVEL, ARBITRARY_DELTA_LEVEL,
851                WifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS,
852                true, // successfulConnectionEvent
853                true, // completeConnectionEvent
854                true, // useValidScanResult
855                false // dontDeserializeBeforePoll
856        );
857        dumpProtoAndDeserialize();
858        assertEquals(0, mDeserializedWifiMetrics.rssiPollDeltaCount.length);
859    }
860
861    private static final int DEAUTH_REASON = 7;
862    private static final int ASSOC_STATUS = 11;
863    private static final int ASSOC_TIMEOUT = 1;
864    private static final int LOCAL_GEN = 1;
865    private static final int AUTH_FAILURE_REASON = WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD;
866    private static final int NUM_TEST_STA_EVENTS = 14;
867    private static final String   sSSID = "\"SomeTestSsid\"";
868    private static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
869    private static final String   sBSSID = "01:02:03:04:05:06";
870
871    private final StateChangeResult mStateDisconnected =
872            new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED);
873    private final StateChangeResult mStateCompleted =
874            new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED);
875    // Test bitmasks of supplicant state changes
876    private final int mSupBm1 = WifiMetrics.supplicantStateToBit(mStateDisconnected.state);
877    private final int mSupBm2 = WifiMetrics.supplicantStateToBit(mStateDisconnected.state)
878            | WifiMetrics.supplicantStateToBit(mStateCompleted.state);
879    // An invalid but interesting wifiConfiguration that exercises the StaEvent.ConfigInfo encoding
880    private final WifiConfiguration mTestWifiConfig = createComplexWifiConfig();
881    // <msg.what> <msg.arg1> <msg.arg2>
882    private int[][] mTestStaMessageInts = {
883        {WifiMonitor.ASSOCIATION_REJECTION_EVENT,   ASSOC_TIMEOUT,      ASSOC_STATUS},
884        {WifiMonitor.AUTHENTICATION_FAILURE_EVENT,  0,                  AUTH_FAILURE_REASON},
885        {WifiMonitor.NETWORK_CONNECTION_EVENT,      0,                  0},
886        {WifiMonitor.NETWORK_DISCONNECTION_EVENT,   LOCAL_GEN,          DEAUTH_REASON},
887        {WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0,                  0},
888        {WifiStateMachine.CMD_ASSOCIATED_BSSID,     0,                  0},
889        {WifiStateMachine.CMD_TARGET_BSSID,         0,                  0},
890        {WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0,                  0},
891        {WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0,                  0}
892    };
893    private Object[] mTestStaMessageObjs = {
894        null,
895        null,
896        null,
897        null,
898        mStateDisconnected,
899        null,
900        null,
901        mStateDisconnected,
902        mStateCompleted
903    };
904    // Values used to generate the StaEvent log calls from WifiStateMachine
905    // <StaEvent.Type>, <StaEvent.FrameworkDisconnectReason>, <1|0>(testWifiConfiguration, null)
906    private int[][] mTestStaLogInts = {
907        {StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL, 0,                          0},
908        {StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST,       0,                          0},
909        {StaEvent.TYPE_CMD_IP_REACHABILITY_LOST,        0,                          0},
910        {StaEvent.TYPE_CMD_START_CONNECT,               0,                          1},
911        {StaEvent.TYPE_CMD_START_ROAM,                  0,                          1},
912        {StaEvent.TYPE_CONNECT_NETWORK,                 0,                          1},
913        {StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK,     0,                          0},
914        {StaEvent.TYPE_FRAMEWORK_DISCONNECT,            StaEvent.DISCONNECT_API,    0}
915    };
916    // Values used to generate the StaEvent log calls from WifiMonitor
917    // <type>, <reason>, <status>, <local_gen>,
918    // <auth_fail_reason>, <assoc_timed_out> <supplicantStateChangeBitmask> <1|0>(has ConfigInfo)
919    private int[][] mExpectedValues = {
920        {StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT,     -1,  ASSOC_STATUS,         0,
921            /**/                               0, ASSOC_TIMEOUT,        0, 0},    /**/
922        {StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT,    -1,            -1,         0,
923            /**/StaEvent.AUTH_FAILURE_WRONG_PSWD,             0,        0, 0},    /**/
924        {StaEvent.TYPE_NETWORK_CONNECTION_EVENT,        -1,            -1,         0,
925            /**/                               0,             0,        0, 0},    /**/
926        {StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT, DEAUTH_REASON,     -1, LOCAL_GEN,
927            /**/                               0,             0,        0, 0},    /**/
928        {StaEvent.TYPE_CMD_ASSOCIATED_BSSID,            -1,            -1,         0,
929            /**/                               0,             0,  mSupBm1, 0},    /**/
930        {StaEvent.TYPE_CMD_TARGET_BSSID,                -1,            -1,         0,
931            /**/                               0,             0,        0, 0},    /**/
932        {StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL, -1,            -1,         0,
933            /**/                               0,             0,  mSupBm2, 0},    /**/
934        {StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST,       -1,            -1,         0,
935            /**/                               0,             0,        0, 0},    /**/
936        {StaEvent.TYPE_CMD_IP_REACHABILITY_LOST,        -1,            -1,         0,
937            /**/                               0,             0,        0, 0},    /**/
938        {StaEvent.TYPE_CMD_START_CONNECT,               -1,            -1,         0,
939            /**/                               0,             0,        0, 1},    /**/
940        {StaEvent.TYPE_CMD_START_ROAM,                  -1,            -1,         0,
941            /**/                               0,             0,        0, 1},    /**/
942        {StaEvent.TYPE_CONNECT_NETWORK,                 -1,            -1,         0,
943            /**/                               0,             0,        0, 1},    /**/
944        {StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK,     -1,            -1,         0,
945            /**/                               0,             0,        0, 0},    /**/
946        {StaEvent.TYPE_FRAMEWORK_DISCONNECT,            -1,            -1,         0,
947            /**/                               0,             0,        0, 0}     /**/
948    };
949
950    /**
951     * Generates events from all the rows in mTestStaMessageInts, and then mTestStaLogInts
952     */
953    private void generateStaEvents(WifiMetrics wifiMetrics) {
954        Handler handler = wifiMetrics.getHandler();
955        for (int i = 0; i < mTestStaMessageInts.length; i++) {
956            int[] mia = mTestStaMessageInts[i];
957            handler.sendMessage(
958                    handler.obtainMessage(mia[0], mia[1], mia[2], mTestStaMessageObjs[i]));
959        }
960        mTestLooper.dispatchAll();
961        for (int i = 0; i < mTestStaLogInts.length; i++) {
962            int[] lia = mTestStaLogInts[i];
963            wifiMetrics.logStaEvent(lia[0], lia[1], lia[2] == 1 ? mTestWifiConfig : null);
964        }
965    }
966    private void verifyDeserializedStaEvents(WifiMetricsProto.WifiLog wifiLog) {
967        assertEquals(NUM_TEST_STA_EVENTS, wifiLog.staEventList.length);
968        int j = 0; // De-serialized event index
969        for (int i = 0; i < mTestStaMessageInts.length; i++) {
970            StaEvent event = wifiLog.staEventList[j];
971            int[] mia = mTestStaMessageInts[i];
972            int[] evs = mExpectedValues[j];
973            if (mia[0] != WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT) {
974                assertEquals(evs[0], event.type);
975                assertEquals(evs[1], event.reason);
976                assertEquals(evs[2], event.status);
977                assertEquals(evs[3] == 1 ? true : false, event.localGen);
978                assertEquals(evs[4], event.authFailureReason);
979                assertEquals(evs[5] == 1 ? true : false, event.associationTimedOut);
980                assertEquals(evs[6], event.supplicantStateChangesBitmask);
981                assertConfigInfoEqualsWifiConfig(
982                        evs[7] == 1 ? mTestWifiConfig : null, event.configInfo);
983                j++;
984            }
985        }
986    }
987
988    /**
989     * Generate StaEvents of each type, ensure all the different values are logged correctly,
990     * and that they survive serialization & de-serialization
991     */
992    @Test
993    public void testStaEventsLogSerializeDeserialize() throws Exception {
994        generateStaEvents(mWifiMetrics);
995        dumpProtoAndDeserialize();
996        verifyDeserializedStaEvents(mDeserializedWifiMetrics);
997    }
998
999    /**
1000     * Ensure the number of StaEvents does not exceed MAX_STA_EVENTS by generating lots of events
1001     * and checking how many are deserialized
1002     */
1003    @Test
1004    public void testStaEventBounding() throws Exception {
1005        for (int i = 0; i < (WifiMetrics.MAX_STA_EVENTS + 10); i++) {
1006            mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT);
1007        }
1008        dumpProtoAndDeserialize();
1009        assertEquals(WifiMetrics.MAX_STA_EVENTS, mDeserializedWifiMetrics.staEventList.length);
1010    }
1011
1012    /**
1013     * Ensure WifiMetrics doesn't cause a null pointer exception when called with null args
1014     */
1015    @Test
1016    public void testDumpNullArg() {
1017        mWifiMetrics.dump(new FileDescriptor(), new PrintWriter(new StringWriter()), null);
1018    }
1019
1020    /**
1021     * Generate an RSSI delta event by creating a connection event and an RSSI poll within
1022     * 'interArrivalTime' milliseconds of each other.
1023     * Event will not be logged if interArrivalTime > mWifiMetrics.TIMEOUT_RSSI_DELTA_MILLIS
1024     * successfulConnectionEvent, completeConnectionEvent, useValidScanResult and
1025     * dontDeserializeBeforePoll
1026     * each create an anomalous condition when set to false.
1027     */
1028    private void generateRssiDelta(int scanRssi, int rssiDelta,
1029            long interArrivalTime, boolean successfulConnectionEvent,
1030            boolean completeConnectionEvent, boolean useValidScanResult,
1031            boolean dontDeserializeBeforePoll) throws Exception {
1032        when(mClock.getElapsedSinceBootMillis()).thenReturn((long) 0);
1033        ScanResult scanResult = null;
1034        if (useValidScanResult) {
1035            scanResult = mock(ScanResult.class);
1036            scanResult.level = scanRssi;
1037        }
1038        WifiConfiguration config = mock(WifiConfiguration.class);
1039        WifiConfiguration.NetworkSelectionStatus networkSelectionStat =
1040                mock(WifiConfiguration.NetworkSelectionStatus.class);
1041        when(networkSelectionStat.getCandidate()).thenReturn(scanResult);
1042        when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStat);
1043        mWifiMetrics.startConnectionEvent(config, "TestNetwork",
1044                WifiMetricsProto.ConnectionEvent.ROAM_ENTERPRISE);
1045        if (completeConnectionEvent) {
1046            if (successfulConnectionEvent) {
1047                mWifiMetrics.endConnectionEvent(
1048                        WifiMetrics.ConnectionEvent.FAILURE_NONE,
1049                        WifiMetricsProto.ConnectionEvent.HLF_NONE);
1050            } else {
1051                mWifiMetrics.endConnectionEvent(
1052                        WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
1053                        WifiMetricsProto.ConnectionEvent.HLF_NONE);
1054            }
1055        }
1056        when(mClock.getElapsedSinceBootMillis()).thenReturn(interArrivalTime);
1057        if (!dontDeserializeBeforePoll) {
1058            dumpProtoAndDeserialize();
1059        }
1060        mWifiMetrics.incrementRssiPollRssiCount(scanRssi + rssiDelta);
1061    }
1062    /**
1063     * Generate an RSSI delta event, with all extra conditions set to true.
1064     */
1065    private void generateRssiDelta(int scanRssi, int rssiDelta,
1066            long interArrivalTime) throws Exception {
1067        generateRssiDelta(scanRssi, rssiDelta, interArrivalTime, true, true, true, true);
1068    }
1069
1070    private void assertStringContains(
1071            String actualString, String expectedSubstring) {
1072        assertTrue("Expected text not found in: " + actualString,
1073                actualString.contains(expectedSubstring));
1074    }
1075
1076    private String getStateDump() {
1077        ByteArrayOutputStream stream = new ByteArrayOutputStream();
1078        PrintWriter writer = new PrintWriter(stream);
1079        String[] args = new String[0];
1080        mWifiMetrics.dump(null, writer, args);
1081        writer.flush();
1082        return stream.toString();
1083    }
1084
1085    private static final int TEST_ALLOWED_KEY_MANAGEMENT = 83;
1086    private static final int TEST_ALLOWED_PROTOCOLS = 22;
1087    private static final int TEST_ALLOWED_AUTH_ALGORITHMS = 11;
1088    private static final int TEST_ALLOWED_PAIRWISE_CIPHERS = 67;
1089    private static final int TEST_ALLOWED_GROUP_CIPHERS = 231;
1090    private static final int TEST_CANDIDATE_LEVEL = -80;
1091    private static final int TEST_CANDIDATE_FREQ = 2345;
1092
1093    private WifiConfiguration createComplexWifiConfig() {
1094        WifiConfiguration config = new WifiConfiguration();
1095        config.allowedKeyManagement = intToBitSet(TEST_ALLOWED_KEY_MANAGEMENT);
1096        config.allowedProtocols = intToBitSet(TEST_ALLOWED_PROTOCOLS);
1097        config.allowedAuthAlgorithms = intToBitSet(TEST_ALLOWED_AUTH_ALGORITHMS);
1098        config.allowedPairwiseCiphers = intToBitSet(TEST_ALLOWED_PAIRWISE_CIPHERS);
1099        config.allowedGroupCiphers = intToBitSet(TEST_ALLOWED_GROUP_CIPHERS);
1100        config.hiddenSSID = true;
1101        config.ephemeral = true;
1102        config.getNetworkSelectionStatus().setHasEverConnected(true);
1103        ScanResult candidate = new ScanResult();
1104        candidate.level = TEST_CANDIDATE_LEVEL;
1105        candidate.frequency = TEST_CANDIDATE_FREQ;
1106        config.getNetworkSelectionStatus().setCandidate(candidate);
1107        return config;
1108    }
1109
1110    private void assertConfigInfoEqualsWifiConfig(WifiConfiguration config,
1111            StaEvent.ConfigInfo info) {
1112        if (config == null && info == null) return;
1113        assertEquals(config.allowedKeyManagement,   intToBitSet(info.allowedKeyManagement));
1114        assertEquals(config.allowedProtocols,       intToBitSet(info.allowedProtocols));
1115        assertEquals(config.allowedAuthAlgorithms,  intToBitSet(info.allowedAuthAlgorithms));
1116        assertEquals(config.allowedPairwiseCiphers, intToBitSet(info.allowedPairwiseCiphers));
1117        assertEquals(config.allowedGroupCiphers,    intToBitSet(info.allowedGroupCiphers));
1118        assertEquals(config.hiddenSSID, info.hiddenSsid);
1119        assertEquals(config.ephemeral, info.isEphemeral);
1120        assertEquals(config.getNetworkSelectionStatus().getHasEverConnected(),
1121                info.hasEverConnected);
1122        assertEquals(config.getNetworkSelectionStatus().getCandidate().level, info.scanRssi);
1123        assertEquals(config.getNetworkSelectionStatus().getCandidate().frequency, info.scanFreq);
1124    }
1125
1126    /**
1127     * Sets the values of bitSet to match an int mask
1128     */
1129    private static BitSet intToBitSet(int mask) {
1130        BitSet bitSet = new BitSet();
1131        for (int bitIndex = 0; mask > 0; mask >>>= 1, bitIndex++) {
1132            if ((mask & 1) != 0) bitSet.set(bitIndex);
1133        }
1134        return bitSet;
1135    }
1136}
1137