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