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 17package com.android.server.wifi; 18 19import static org.junit.Assert.assertArrayEquals; 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertFalse; 22import static org.junit.Assert.assertTrue; 23import static org.mockito.Matchers.anyString; 24import static org.mockito.Matchers.contains; 25import static org.mockito.Mockito.anyInt; 26import static org.mockito.Mockito.anyObject; 27import static org.mockito.Mockito.eq; 28import static org.mockito.Mockito.never; 29import static org.mockito.Mockito.reset; 30import static org.mockito.Mockito.verify; 31import static org.mockito.Mockito.when; 32 33import android.app.test.MockAnswerUtil.AnswerWithArguments; 34import android.content.Context; 35import android.test.suitebuilder.annotation.SmallTest; 36 37import com.android.internal.R; 38 39import org.junit.Before; 40import org.junit.Test; 41import org.mockito.Mock; 42import org.mockito.MockitoAnnotations; 43import org.mockito.Spy; 44 45import java.io.ByteArrayInputStream; 46import java.io.FileDescriptor; 47import java.io.PrintWriter; 48import java.io.StringWriter; 49import java.util.regex.Pattern; 50 51/** 52 * Unit tests for {@link WifiDiagnostics}. 53 */ 54@SmallTest 55public class WifiDiagnosticsTest { 56 @Mock WifiStateMachine mWsm; 57 @Mock WifiNative mWifiNative; 58 @Mock BuildProperties mBuildProperties; 59 @Mock Context mContext; 60 @Mock WifiInjector mWifiInjector; 61 @Spy FakeWifiLog mLog; 62 @Mock LastMileLogger mLastMileLogger; 63 @Mock Runtime mJavaRuntime; 64 @Mock Process mExternalProcess; 65 WifiDiagnostics mWifiDiagnostics; 66 67 private static final String FAKE_RING_BUFFER_NAME = "fake-ring-buffer"; 68 private static final int SMALL_RING_BUFFER_SIZE_KB = 32; 69 private static final int LARGE_RING_BUFFER_SIZE_KB = 1024; 70 private static final int BYTES_PER_KBYTE = 1024; 71 private static final long FAKE_CONNECTION_ID = 1; 72 73 private WifiNative.RingBufferStatus mFakeRbs; 74 /** 75 * Returns the data that we would dump in a bug report, for our ring buffer. 76 * @return a 2-D byte array, where the first dimension is the record number, and the second 77 * dimension is the byte index within that record. 78 */ 79 private final byte[][] getLoggerRingBufferData() throws Exception { 80 return mWifiDiagnostics.getBugReports().get(0).ringBuffers.get(FAKE_RING_BUFFER_NAME); 81 } 82 83 /** 84 * Initializes common state (e.g. mocks) needed by test cases. 85 */ 86 @Before 87 public void setUp() throws Exception { 88 MockitoAnnotations.initMocks(this); 89 90 mFakeRbs = new WifiNative.RingBufferStatus(); 91 mFakeRbs.name = FAKE_RING_BUFFER_NAME; 92 WifiNative.RingBufferStatus[] ringBufferStatuses = new WifiNative.RingBufferStatus[] { 93 mFakeRbs 94 }; 95 96 when(mWifiNative.getRingBufferStatus()).thenReturn(ringBufferStatuses); 97 when(mWifiNative.readKernelLog()).thenReturn(""); 98 when(mBuildProperties.isEngBuild()).thenReturn(false); 99 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 100 when(mBuildProperties.isUserBuild()).thenReturn(true); 101 when(mExternalProcess.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[0])); 102 when(mExternalProcess.getErrorStream()).thenReturn(new ByteArrayInputStream(new byte[0])); 103 when(mJavaRuntime.exec(anyString())).thenReturn(mExternalProcess); 104 105 MockResources resources = new MockResources(); 106 resources.setInteger(R.integer.config_wifi_logger_ring_buffer_default_size_limit_kb, 107 SMALL_RING_BUFFER_SIZE_KB); 108 resources.setInteger(R.integer.config_wifi_logger_ring_buffer_verbose_size_limit_kb, 109 LARGE_RING_BUFFER_SIZE_KB); 110 when(mContext.getResources()).thenReturn(resources); 111 when(mWifiInjector.makeLog(anyString())).thenReturn(mLog); 112 when(mWifiInjector.getJavaRuntime()).thenReturn(mJavaRuntime); 113 114 mWifiDiagnostics = new WifiDiagnostics( 115 mContext, mWifiInjector, mWsm, mWifiNative, mBuildProperties, mLastMileLogger); 116 mWifiNative.enableVerboseLogging(0); 117 } 118 119 /** Verifies that startLogging() registers a logging event handler. */ 120 @Test 121 public void startLoggingRegistersLogEventHandler() throws Exception { 122 final boolean verbosityToggle = false; // even default mode wants log events from HAL 123 mWifiDiagnostics.startLogging(verbosityToggle); 124 verify(mWifiNative).setLoggingEventHandler(anyObject()); 125 } 126 127 /** 128 * Verifies that a failure to set the logging event handler does not prevent a future 129 * startLogging() from setting the logging event handler. 130 */ 131 @Test 132 public void startLoggingRegistersLogEventHandlerIfPriorAttemptFailed() 133 throws Exception { 134 final boolean verbosityToggle = false; // even default mode wants log events from HAL 135 136 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(false); 137 mWifiDiagnostics.startLogging(verbosityToggle); 138 verify(mWifiNative).setLoggingEventHandler(anyObject()); 139 reset(mWifiNative); 140 141 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 142 mWifiDiagnostics.startLogging(verbosityToggle); 143 verify(mWifiNative).setLoggingEventHandler(anyObject()); 144 } 145 146 /** Verifies that startLogging() does not make redundant calls to setLoggingEventHandler(). */ 147 @Test 148 public void startLoggingDoesNotRegisterLogEventHandlerIfPriorAttemptSucceeded() 149 throws Exception { 150 final boolean verbosityToggle = false; // even default mode wants log events from HAL 151 152 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 153 mWifiDiagnostics.startLogging(verbosityToggle); 154 verify(mWifiNative).setLoggingEventHandler(anyObject()); 155 reset(mWifiNative); 156 157 mWifiDiagnostics.startLogging(verbosityToggle); 158 verify(mWifiNative, never()).setLoggingEventHandler(anyObject()); 159 } 160 161 /** 162 * Verifies that startLogging() restarts HAL ringbuffers. 163 * 164 * Specifically: verifies that startLogging() 165 * a) stops any ring buffer logging that might be already running, 166 * b) instructs WifiNative to enable ring buffers of the appropriate log level. 167 */ 168 @Test 169 public void startLoggingStopsAndRestartsRingBufferLogging() throws Exception { 170 final boolean verbosityToggle = false; 171 setBuildPropertiesToEnableRingBuffers(); 172 mWifiDiagnostics.startLogging(verbosityToggle); 173 verify(mWifiNative).startLoggingRingBuffer( 174 eq(WifiDiagnostics.VERBOSE_NO_LOG), anyInt(), anyInt(), anyInt(), 175 eq(FAKE_RING_BUFFER_NAME)); 176 verify(mWifiNative).startLoggingRingBuffer( 177 eq(WifiDiagnostics.VERBOSE_NORMAL_LOG), anyInt(), anyInt(), anyInt(), 178 eq(FAKE_RING_BUFFER_NAME)); 179 } 180 181 @Test 182 public void startLoggingDoesNotStartRingBuffersOnUserBuilds() throws Exception { 183 final boolean verbosityToggle = true; 184 mWifiDiagnostics.startLogging(verbosityToggle); 185 verify(mWifiNative, never()).startLoggingRingBuffer( 186 anyInt(), anyInt(), anyInt(), anyInt(), anyString()); 187 } 188 189 /** Verifies that, if a log handler was registered, then stopLogging() resets it. */ 190 @Test 191 public void stopLoggingResetsLogHandlerIfHandlerWasRegistered() throws Exception { 192 final boolean verbosityToggle = false; // even default mode wants log events from HAL 193 194 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 195 mWifiDiagnostics.startLogging(verbosityToggle); 196 reset(mWifiNative); 197 198 mWifiDiagnostics.stopLogging(); 199 verify(mWifiNative).resetLogHandler(); 200 } 201 202 /** Verifies that, if a log handler is not registered, stopLogging() skips resetLogHandler(). */ 203 @Test 204 public void stopLoggingOnlyResetsLogHandlerIfHandlerWasRegistered() throws Exception { 205 final boolean verbosityToggle = false; // even default mode wants log events from HAL 206 mWifiDiagnostics.stopLogging(); 207 verify(mWifiNative, never()).resetLogHandler(); 208 } 209 210 /** Verifies that stopLogging() remembers that we've reset the log handler. */ 211 @Test 212 public void multipleStopLoggingCallsOnlyResetLogHandlerOnce() throws Exception { 213 final boolean verbosityToggle = false; // even default mode wants log events from HAL 214 215 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 216 mWifiDiagnostics.startLogging(verbosityToggle); 217 reset(mWifiNative); 218 219 when(mWifiNative.resetLogHandler()).thenReturn(true); 220 mWifiDiagnostics.stopLogging(); 221 verify(mWifiNative).resetLogHandler(); 222 reset(mWifiNative); 223 224 mWifiDiagnostics.stopLogging(); 225 verify(mWifiNative, never()).resetLogHandler(); 226 } 227 228 /** 229 * Verifies that we capture ring-buffer data. 230 */ 231 @Test 232 public void canCaptureAndStoreRingBufferData() throws Exception { 233 final boolean verbosityToggle = false; 234 setBuildPropertiesToEnableRingBuffers(); 235 mWifiDiagnostics.startLogging(verbosityToggle); 236 237 final byte[] data = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]; 238 mWifiDiagnostics.onRingBufferData(mFakeRbs, data); 239 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 240 241 byte[][] ringBufferData = getLoggerRingBufferData(); 242 assertEquals(1, ringBufferData.length); 243 assertArrayEquals(data, ringBufferData[0]); 244 } 245 246 /** 247 * Verifies that we discard extraneous ring-buffer data. 248 */ 249 @Test 250 public void loggerDiscardsExtraneousData() throws Exception { 251 final boolean verbosityToggle = false; 252 setBuildPropertiesToEnableRingBuffers(); 253 mWifiDiagnostics.startLogging(verbosityToggle); 254 255 final byte[] data1 = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]; 256 final byte[] data2 = {1, 2, 3}; 257 mWifiDiagnostics.onRingBufferData(mFakeRbs, data1); 258 mWifiDiagnostics.onRingBufferData(mFakeRbs, data2); 259 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 260 261 byte[][] ringBufferData = getLoggerRingBufferData(); 262 assertEquals(1, ringBufferData.length); 263 assertArrayEquals(data2, ringBufferData[0]); 264 } 265 266 /** 267 * Verifies that, when verbose mode is not enabled, startLogging() calls 268 * startPktFateMonitoring(). 269 */ 270 @Test 271 public void startLoggingStartsPacketFateWithoutVerboseMode() { 272 final boolean verbosityToggle = false; 273 mWifiDiagnostics.startLogging(verbosityToggle); 274 verify(mWifiNative).startPktFateMonitoring(); 275 } 276 277 /** 278 * Verifies that, when verbose mode is enabled, startLogging() calls 279 * startPktFateMonitoring(). 280 */ 281 @Test 282 public void startLoggingStartsPacketFateInVerboseMode() { 283 final boolean verbosityToggle = true; 284 mWifiDiagnostics.startLogging(verbosityToggle); 285 verify(mWifiNative).startPktFateMonitoring(); 286 } 287 288 // Verifies that startLogging() reports failure of startPktFateMonitoring(). 289 @Test 290 public void startLoggingReportsFailureOfStartPktFateMonitoring() { 291 final boolean verbosityToggle = true; 292 when(mWifiNative.startPktFateMonitoring()).thenReturn(false); 293 mWifiDiagnostics.startLogging(verbosityToggle); 294 verify(mLog).wC(contains("Failed")); 295 } 296 297 /** 298 * Verifies that, when verbose mode is not enabled, 299 * reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_FAILED) still fetches packet fates. 300 */ 301 @Test 302 public void reportConnectionFailureIsIgnoredWithoutVerboseMode() { 303 final boolean verbosityToggle = false; 304 mWifiDiagnostics.startLogging(verbosityToggle); 305 mWifiDiagnostics.reportConnectionEvent( 306 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 307 verify(mWifiNative).getTxPktFates(anyObject()); 308 verify(mWifiNative).getRxPktFates(anyObject()); 309 } 310 311 /** 312 * Verifies that, when verbose mode is enabled, reportConnectionFailure() fetches packet fates. 313 */ 314 @Test 315 public void reportConnectionFailureFetchesFatesInVerboseMode() { 316 final boolean verbosityToggle = true; 317 mWifiDiagnostics.startLogging(verbosityToggle); 318 mWifiDiagnostics.reportConnectionEvent( 319 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 320 verify(mWifiNative).getTxPktFates(anyObject()); 321 verify(mWifiNative).getRxPktFates(anyObject()); 322 } 323 324 @Test 325 public void reportConnectionEventPropagatesStartToLastMileLogger() { 326 final boolean verbosityToggle = false; 327 mWifiDiagnostics.startLogging(verbosityToggle); 328 mWifiDiagnostics.reportConnectionEvent( 329 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_STARTED); 330 verify(mLastMileLogger).reportConnectionEvent( 331 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_STARTED); 332 } 333 334 @Test 335 public void reportConnectionEventPropagatesSuccessToLastMileLogger() { 336 final boolean verbosityToggle = false; 337 mWifiDiagnostics.startLogging(verbosityToggle); 338 mWifiDiagnostics.reportConnectionEvent( 339 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED); 340 verify(mLastMileLogger).reportConnectionEvent( 341 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED); 342 } 343 344 @Test 345 public void reportConnectionEventPropagatesFailureToLastMileLogger() { 346 final boolean verbosityToggle = false; 347 mWifiDiagnostics.startLogging(verbosityToggle); 348 mWifiDiagnostics.reportConnectionEvent( 349 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 350 verify(mLastMileLogger).reportConnectionEvent( 351 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 352 } 353 354 /** 355 * Verifies that we try to fetch TX fates, even if fetching RX fates failed. 356 */ 357 @Test 358 public void loggerFetchesTxFatesEvenIfFetchingRxFatesFails() { 359 final boolean verbosityToggle = true; 360 when(mWifiNative.getRxPktFates(anyObject())).thenReturn(false); 361 mWifiDiagnostics.startLogging(verbosityToggle); 362 mWifiDiagnostics.reportConnectionEvent( 363 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 364 verify(mWifiNative).getTxPktFates(anyObject()); 365 verify(mWifiNative).getRxPktFates(anyObject()); 366 } 367 368 /** 369 * Verifies that we try to fetch RX fates, even if fetching TX fates failed. 370 */ 371 @Test 372 public void loggerFetchesRxFatesEvenIfFetchingTxFatesFails() { 373 final boolean verbosityToggle = true; 374 when(mWifiNative.getTxPktFates(anyObject())).thenReturn(false); 375 mWifiDiagnostics.startLogging(verbosityToggle); 376 mWifiDiagnostics.reportConnectionEvent( 377 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 378 verify(mWifiNative).getTxPktFates(anyObject()); 379 verify(mWifiNative).getRxPktFates(anyObject()); 380 } 381 382 /** Verifies that dump() fetches the latest fates. */ 383 @Test 384 public void dumpFetchesFates() { 385 final boolean verbosityToggle = false; 386 StringWriter sw = new StringWriter(); 387 PrintWriter pw = new PrintWriter(sw); 388 mWifiDiagnostics.startLogging(verbosityToggle); 389 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 390 verify(mWifiNative).getTxPktFates(anyObject()); 391 verify(mWifiNative).getRxPktFates(anyObject()); 392 } 393 394 /** 395 * Verifies that dump() doesn't crash, or generate garbage, in the case where we haven't fetched 396 * any fates. 397 */ 398 @Test 399 public void dumpSucceedsWhenNoFatesHaveNotBeenFetched() { 400 StringWriter sw = new StringWriter(); 401 PrintWriter pw = new PrintWriter(sw); 402 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 403 404 String fateDumpString = sw.toString(); 405 assertTrue(fateDumpString.contains("Last failed")); 406 // Verify dump terminator is present 407 assertTrue(fateDumpString.contains( 408 "--------------------------------------------------------------------")); 409 } 410 411 /** 412 * Verifies that dump() doesn't crash, or generate garbage, in the case where the fates that 413 * the HAL-provided fates are empty. 414 */ 415 @Test 416 public void dumpSucceedsWhenFatesHaveBeenFetchedButAreEmpty() { 417 final boolean verbosityToggle = true; 418 mWifiDiagnostics.startLogging(verbosityToggle); 419 mWifiDiagnostics.reportConnectionEvent( 420 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 421 verify(mWifiNative).getTxPktFates(anyObject()); 422 verify(mWifiNative).getRxPktFates(anyObject()); 423 424 StringWriter sw = new StringWriter(); 425 PrintWriter pw = new PrintWriter(sw); 426 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 427 428 String fateDumpString = sw.toString(); 429 assertTrue(fateDumpString.contains("Last failed")); 430 // Verify dump terminator is present 431 assertTrue(fateDumpString.contains( 432 "--------------------------------------------------------------------")); 433 } 434 435 private String getDumpString(boolean verbose) { 436 mWifiDiagnostics.startLogging(verbose); 437 mWifiNative.enableVerboseLogging(verbose ? 1 : 0); 438 when(mWifiNative.getTxPktFates(anyObject())).then(new AnswerWithArguments() { 439 public boolean answer(WifiNative.TxFateReport[] fates) { 440 fates[0] = new WifiNative.TxFateReport( 441 WifiLoggerHal.TX_PKT_FATE_ACKED, 2, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 442 new byte[0] 443 ); 444 fates[1] = new WifiNative.TxFateReport( 445 WifiLoggerHal.TX_PKT_FATE_ACKED, 0, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 446 new byte[0] 447 ); 448 return true; 449 } 450 }); 451 when(mWifiNative.getRxPktFates(anyObject())).then(new AnswerWithArguments() { 452 public boolean answer(WifiNative.RxFateReport[] fates) { 453 fates[0] = new WifiNative.RxFateReport( 454 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 3, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 455 new byte[0] 456 ); 457 fates[1] = new WifiNative.RxFateReport( 458 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 1, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 459 new byte[0] 460 ); 461 return true; 462 } 463 }); 464 mWifiDiagnostics.reportConnectionEvent( 465 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 466 467 StringWriter sw = new StringWriter(); 468 PrintWriter pw = new PrintWriter(sw); 469 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 470 return sw.toString(); 471 } 472 473 /** 474 * Verifies that dump() shows both TX, and RX fates in only table form, when verbose 475 * logging is not enabled. 476 */ 477 @Test 478 public void dumpShowsTxAndRxFates() { 479 final boolean verbosityToggle = false; 480 String dumpString = getDumpString(verbosityToggle); 481 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 482 assertTrue(Pattern.compile("0 .* TX ").matcher(dumpString).find()); 483 assertTrue(Pattern.compile("1 .* RX ").matcher(dumpString).find()); 484 assertTrue(Pattern.compile("2 .* TX ").matcher(dumpString).find()); 485 assertTrue(Pattern.compile("3 .* RX ").matcher(dumpString).find()); 486 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 487 assertFalse(dumpString.contains("Frame bytes")); 488 } 489 490 /** 491 * Verifies that dump() shows both TX, and RX fates in table and verbose forms, when verbose 492 * logging is enabled. 493 */ 494 @Test 495 public void dumpShowsTxAndRxFatesVerbose() { 496 final boolean verbosityToggle = true; 497 String dumpString = getDumpString(verbosityToggle); 498 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 499 assertTrue(Pattern.compile("0 .* TX ").matcher(dumpString).find()); 500 assertTrue(Pattern.compile("1 .* RX ").matcher(dumpString).find()); 501 assertTrue(Pattern.compile("2 .* TX ").matcher(dumpString).find()); 502 assertTrue(Pattern.compile("3 .* RX ").matcher(dumpString).find()); 503 assertTrue(dumpString.contains("VERBOSE PACKET FATE DUMP")); 504 assertTrue(dumpString.contains("Frame bytes")); 505 } 506 507 /** 508 * Verifies that dump() outputs frames in timestamp order, even though the HAL provided the 509 * data out-of-order (order is specified in getDumpString()). 510 */ 511 @Test 512 public void dumpIsSortedByTimestamp() { 513 final boolean verbosityToggle = true; 514 String dumpString = getDumpString(verbosityToggle); 515 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 516 assertTrue(Pattern.compile( 517 "0 .* TX .*\n" + 518 "1 .* RX .*\n" + 519 "2 .* TX .*\n" + 520 "3 .* RX " 521 ).matcher(dumpString).find()); 522 523 int expected_index_of_verbose_frame_0 = dumpString.indexOf( 524 "Frame direction: TX\nFrame timestamp: 0\n"); 525 int expected_index_of_verbose_frame_1 = dumpString.indexOf( 526 "Frame direction: RX\nFrame timestamp: 1\n"); 527 int expected_index_of_verbose_frame_2 = dumpString.indexOf( 528 "Frame direction: TX\nFrame timestamp: 2\n"); 529 int expected_index_of_verbose_frame_3 = dumpString.indexOf( 530 "Frame direction: RX\nFrame timestamp: 3\n"); 531 assertFalse(-1 == expected_index_of_verbose_frame_0); 532 assertFalse(-1 == expected_index_of_verbose_frame_1); 533 assertFalse(-1 == expected_index_of_verbose_frame_2); 534 assertFalse(-1 == expected_index_of_verbose_frame_3); 535 assertTrue(expected_index_of_verbose_frame_0 < expected_index_of_verbose_frame_1); 536 assertTrue(expected_index_of_verbose_frame_1 < expected_index_of_verbose_frame_2); 537 assertTrue(expected_index_of_verbose_frame_2 < expected_index_of_verbose_frame_3); 538 } 539 540 /** Verifies that eng builds do not show fate detail outside of verbose mode. */ 541 @Test 542 public void dumpOmitsFateDetailInEngBuildsOutsideOfVerboseMode() throws Exception { 543 final boolean verbosityToggle = false; 544 when(mBuildProperties.isEngBuild()).thenReturn(true); 545 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 546 when(mBuildProperties.isUserBuild()).thenReturn(false); 547 String dumpString = getDumpString(verbosityToggle); 548 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 549 assertFalse(dumpString.contains("Frame bytes")); 550 } 551 552 /** Verifies that userdebug builds do not show fate detail outside of verbose mode. */ 553 @Test 554 public void dumpOmitsFateDetailInUserdebugBuildsOutsideOfVerboseMode() throws Exception { 555 final boolean verbosityToggle = false; 556 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 557 when(mBuildProperties.isEngBuild()).thenReturn(false); 558 when(mBuildProperties.isUserBuild()).thenReturn(false); 559 String dumpString = getDumpString(verbosityToggle); 560 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 561 assertFalse(dumpString.contains("Frame bytes")); 562 } 563 564 /** 565 * Verifies that, if verbose is disabled after fetching fates, the dump does not include 566 * verbose fate logs. 567 */ 568 @Test 569 public void dumpOmitsFatesIfVerboseIsDisabledAfterFetch() { 570 final boolean verbosityToggle = true; 571 mWifiDiagnostics.startLogging(verbosityToggle); 572 when(mWifiNative.getTxPktFates(anyObject())).then(new AnswerWithArguments() { 573 public boolean answer(WifiNative.TxFateReport[] fates) { 574 fates[0] = new WifiNative.TxFateReport( 575 WifiLoggerHal.TX_PKT_FATE_ACKED, 0, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 576 new byte[0] 577 ); 578 return true; 579 } 580 }); 581 when(mWifiNative.getRxPktFates(anyObject())).then(new AnswerWithArguments() { 582 public boolean answer(WifiNative.RxFateReport[] fates) { 583 fates[0] = new WifiNative.RxFateReport( 584 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 1, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 585 new byte[0] 586 ); 587 return true; 588 } 589 }); 590 mWifiDiagnostics.reportConnectionEvent( 591 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 592 verify(mWifiNative).getTxPktFates(anyObject()); 593 verify(mWifiNative).getRxPktFates(anyObject()); 594 595 final boolean newVerbosityToggle = false; 596 mWifiDiagnostics.startLogging(newVerbosityToggle); 597 598 StringWriter sw = new StringWriter(); 599 PrintWriter pw = new PrintWriter(sw); 600 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 601 602 String fateDumpString = sw.toString(); 603 assertFalse(fateDumpString.contains("VERBOSE PACKET FATE DUMP")); 604 assertFalse(fateDumpString.contains("Frame bytes")); 605 } 606 607 @Test 608 public void dumpSucceedsEvenIfRingBuffersAreDisabled() { 609 final boolean verbosityToggle = true; 610 mWifiDiagnostics.startLogging(verbosityToggle); 611 verify(mWifiNative, never()).startLoggingRingBuffer( 612 anyInt(), anyInt(), anyInt(), anyInt(), anyString()); 613 614 StringWriter sw = new StringWriter(); 615 PrintWriter pw = new PrintWriter(sw); 616 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 617 } 618 619 /** Verifies that we use small ring buffers by default, on userdebug builds. */ 620 @Test 621 public void ringBufferSizeIsSmallByDefaultOnUserdebugBuilds() throws Exception { 622 final boolean verbosityToggle = false; 623 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 624 when(mBuildProperties.isEngBuild()).thenReturn(false); 625 when(mBuildProperties.isUserBuild()).thenReturn(false); 626 mWifiDiagnostics.startLogging(verbosityToggle); 627 mWifiDiagnostics.onRingBufferData( 628 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 629 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 630 assertEquals(0, getLoggerRingBufferData().length); 631 } 632 633 /** Verifies that we use small ring buffers by default, on eng builds. */ 634 @Test 635 public void ringBufferSizeIsSmallByDefaultOnEngBuilds() throws Exception { 636 final boolean verbosityToggle = false; 637 when(mBuildProperties.isEngBuild()).thenReturn(true); 638 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 639 when(mBuildProperties.isUserBuild()).thenReturn(false); 640 mWifiDiagnostics.startLogging(verbosityToggle); 641 mWifiDiagnostics.onRingBufferData( 642 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 643 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 644 assertEquals(0, getLoggerRingBufferData().length); 645 } 646 647 /** Verifies that we use large ring buffers when initially started in verbose mode. */ 648 @Test 649 public void ringBufferSizeIsLargeInVerboseMode() throws Exception { 650 final boolean verbosityToggle = true; 651 setBuildPropertiesToEnableRingBuffers(); 652 653 mWifiDiagnostics.startLogging(verbosityToggle); 654 mWifiDiagnostics.onRingBufferData( 655 mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]); 656 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 657 assertEquals(1, getLoggerRingBufferData().length); 658 } 659 660 /** Verifies that we use large ring buffers when switched from normal to verbose mode. */ 661 @Test 662 public void startLoggingGrowsRingBuffersIfNeeded() throws Exception { 663 setBuildPropertiesToEnableRingBuffers(); 664 665 mWifiDiagnostics.startLogging(false /* verbose disabled */); 666 mWifiDiagnostics.startLogging(true /* verbose enabled */); 667 mWifiDiagnostics.onRingBufferData( 668 mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]); 669 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 670 assertEquals(1, getLoggerRingBufferData().length); 671 } 672 673 /** Verifies that we use small ring buffers when switched from verbose to normal mode. */ 674 @Test 675 public void startLoggingShrinksRingBuffersIfNeeded() throws Exception { 676 setBuildPropertiesToEnableRingBuffers(); 677 678 mWifiDiagnostics.startLogging(true /* verbose enabled */); 679 mWifiDiagnostics.onRingBufferData( 680 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 681 682 // Existing data is nuked (too large). 683 mWifiDiagnostics.startLogging(false /* verbose disabled */); 684 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 685 assertEquals(0, getLoggerRingBufferData().length); 686 687 // New data must obey limit as well. 688 mWifiDiagnostics.onRingBufferData( 689 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 690 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 691 assertEquals(0, getLoggerRingBufferData().length); 692 } 693 694 /** Verifies that we skip the firmware and driver dumps if verbose is not enabled. */ 695 @Test 696 public void captureBugReportSkipsFirmwareAndDriverDumpsByDefault() { 697 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 698 verify(mWifiNative, never()).getFwMemoryDump(); 699 verify(mWifiNative, never()).getDriverStateDump(); 700 } 701 702 /** Verifies that we capture the firmware and driver dumps if verbose is enabled. */ 703 @Test 704 public void captureBugReportTakesFirmwareAndDriverDumpsInVerboseMode() { 705 mWifiDiagnostics.startLogging(true /* verbose enabled */); 706 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 707 verify(mWifiNative).getFwMemoryDump(); 708 verify(mWifiNative).getDriverStateDump(); 709 } 710 711 /** Verifies that the dump includes driver state, if driver state was provided by HAL. */ 712 @Test 713 public void dumpIncludesDriverStateDumpIfAvailable() { 714 when(mWifiNative.getDriverStateDump()).thenReturn(new byte[]{0, 1, 2}); 715 716 mWifiDiagnostics.startLogging(true /* verbose enabled */); 717 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 718 verify(mWifiNative).getDriverStateDump(); 719 720 StringWriter sw = new StringWriter(); 721 PrintWriter pw = new PrintWriter(sw); 722 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 723 assertTrue(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 724 } 725 726 /** Verifies that the dump skips driver state, if driver state was not provided by HAL. */ 727 @Test 728 public void dumpOmitsDriverStateDumpIfUnavailable() { 729 mWifiDiagnostics.startLogging(true /* verbose enabled */); 730 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 731 verify(mWifiNative).getDriverStateDump(); 732 733 StringWriter sw = new StringWriter(); 734 PrintWriter pw = new PrintWriter(sw); 735 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 736 assertFalse(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 737 } 738 739 /** Verifies that the dump omits driver state, if verbose was disabled after capture. */ 740 @Test 741 public void dumpOmitsDriverStateDumpIfVerboseDisabledAfterCapture() { 742 when(mWifiNative.getDriverStateDump()).thenReturn(new byte[]{0, 1, 2}); 743 744 mWifiDiagnostics.startLogging(true /* verbose enabled */); 745 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 746 verify(mWifiNative).getDriverStateDump(); 747 748 mWifiDiagnostics.startLogging(false /* verbose no longer enabled */); 749 750 StringWriter sw = new StringWriter(); 751 PrintWriter pw = new PrintWriter(sw); 752 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 753 assertFalse(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 754 } 755 756 /** Verifies that the dump includes firmware dump, if firmware dump was provided by HAL. */ 757 @Test 758 public void dumpIncludesFirmwareMemoryDumpIfAvailable() { 759 when(mWifiNative.getFwMemoryDump()).thenReturn(new byte[]{0, 1, 2}); 760 761 mWifiDiagnostics.startLogging(true /* verbose enabled */); 762 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 763 verify(mWifiNative).getFwMemoryDump(); 764 765 StringWriter sw = new StringWriter(); 766 PrintWriter pw = new PrintWriter(sw); 767 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 768 assertTrue(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 769 } 770 771 /** Verifies that the dump skips firmware memory, if firmware memory was not provided by HAL. */ 772 @Test 773 public void dumpOmitsFirmwareMemoryDumpIfUnavailable() { 774 mWifiDiagnostics.startLogging(true /* verbose enabled */); 775 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 776 verify(mWifiNative).getFwMemoryDump(); 777 778 StringWriter sw = new StringWriter(); 779 PrintWriter pw = new PrintWriter(sw); 780 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 781 assertFalse(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 782 } 783 784 /** Verifies that the dump omits firmware memory, if verbose was disabled after capture. */ 785 @Test 786 public void dumpOmitsFirmwareMemoryDumpIfVerboseDisabledAfterCapture() { 787 when(mWifiNative.getFwMemoryDump()).thenReturn(new byte[]{0, 1, 2}); 788 789 mWifiDiagnostics.startLogging(true /* verbose enabled */); 790 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 791 verify(mWifiNative).getFwMemoryDump(); 792 793 mWifiDiagnostics.startLogging(false /* verbose no longer enabled */); 794 795 StringWriter sw = new StringWriter(); 796 PrintWriter pw = new PrintWriter(sw); 797 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 798 assertFalse(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 799 } 800 801 @Test 802 public void dumpRequestsLastMileLoggerDump() { 803 mWifiDiagnostics.dump( 804 new FileDescriptor(), new PrintWriter(new StringWriter()), new String[]{}); 805 verify(mLastMileLogger).dump(anyObject()); 806 } 807 808 private void setBuildPropertiesToEnableRingBuffers() { 809 when(mBuildProperties.isEngBuild()).thenReturn(false); 810 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 811 when(mBuildProperties.isUserBuild()).thenReturn(false); 812 } 813} 814