blob: 46a3de86aac4b83ad2f2a24e0a5ec58844c21123 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.wifi;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.MacAddress;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiScanner;
import android.net.wifi.nl80211.NativeScanResult;
import android.net.wifi.nl80211.RadioChainInfo;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.net.wifi.nl80211.WifiNl80211Manager.SendMgmtFrameCallback;
import android.os.Handler;
import androidx.test.filters.SmallTest;
import com.android.server.wifi.util.NativeUtil;
import com.android.server.wifi.util.NetdWrapper;
import org.junit.Before;
import org.junit.Test;
import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Unit tests for {@link com.android.server.wifi.WifiNative}.
*/
@SmallTest
public class WifiNativeTest extends WifiBaseTest {
private static final String WIFI_IFACE_NAME = "mockWlan";
private static final long FATE_REPORT_DRIVER_TIMESTAMP_USEC = 12345;
private static final byte[] FATE_REPORT_FRAME_BYTES = new byte[] {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 0, 1, 2, 3, 4, 5, 6, 7};
private static final WifiNative.TxFateReport TX_FATE_REPORT = new WifiNative.TxFateReport(
WifiLoggerHal.TX_PKT_FATE_SENT,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_ETHERNET_II,
FATE_REPORT_FRAME_BYTES
);
private static final WifiNative.RxFateReport RX_FATE_REPORT = new WifiNative.RxFateReport(
WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_ETHERNET_II,
FATE_REPORT_FRAME_BYTES
);
private static final FrameTypeMapping[] FRAME_TYPE_MAPPINGS = new FrameTypeMapping[] {
new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_UNKNOWN, "unknown", "N/A"),
new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, "data", "Ethernet"),
new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_80211_MGMT, "802.11 management",
"802.11 Mgmt"),
new FrameTypeMapping((byte) 42, "42", "N/A")
};
private static final FateMapping[] TX_FATE_MAPPINGS = new FateMapping[] {
new FateMapping(WifiLoggerHal.TX_PKT_FATE_ACKED, "acked"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_SENT, "sent"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_FW_QUEUED, "firmware queued"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID,
"firmware dropped (invalid frame)"),
new FateMapping(
WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS, "firmware dropped (no bufs)"),
new FateMapping(
WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER, "firmware dropped (other)"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED, "driver queued"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID,
"driver dropped (invalid frame)"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS,
"driver dropped (no bufs)"),
new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER, "driver dropped (other)"),
new FateMapping((byte) 42, "42")
};
private static final FateMapping[] RX_FATE_MAPPINGS = new FateMapping[] {
new FateMapping(WifiLoggerHal.RX_PKT_FATE_SUCCESS, "success"),
new FateMapping(WifiLoggerHal.RX_PKT_FATE_FW_QUEUED, "firmware queued"),
new FateMapping(
WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER, "firmware dropped (filter)"),
new FateMapping(WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID,
"firmware dropped (invalid frame)"),
new FateMapping(
WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS, "firmware dropped (no bufs)"),
new FateMapping(
WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER, "firmware dropped (other)"),
new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED, "driver queued"),
new FateMapping(
WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER, "driver dropped (filter)"),
new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID,
"driver dropped (invalid frame)"),
new FateMapping(
WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS, "driver dropped (no bufs)"),
new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER, "driver dropped (other)"),
new FateMapping((byte) 42, "42")
};
private static final WifiNl80211Manager.SignalPollResult SIGNAL_POLL_RESULT =
new WifiNl80211Manager.SignalPollResult(-60, 12, 6, 5240);
private static final Set<Integer> SCAN_FREQ_SET =
new HashSet<Integer>() {{
add(2410);
add(2450);
add(5050);
add(5200);
}};
private static final String TEST_QUOTED_SSID_1 = "\"testSsid1\"";
private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
private static final int[] TEST_FREQUENCIES_1 = {};
private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
private static final List<String> SCAN_HIDDEN_NETWORK_SSID_SET =
new ArrayList<String>() {{
add(TEST_QUOTED_SSID_1);
add(TEST_QUOTED_SSID_2);
}};
private static final List<byte[]> SCAN_HIDDEN_NETWORK_BYTE_SSID_SET =
new ArrayList<byte[]>() {{
add(NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
add(NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
}};
private static final WifiNative.PnoSettings TEST_PNO_SETTINGS =
new WifiNative.PnoSettings() {{
isConnected = false;
periodInMs = 6000;
networkList = new WifiNative.PnoNetwork[2];
networkList[0] = new WifiNative.PnoNetwork();
networkList[1] = new WifiNative.PnoNetwork();
networkList[0].ssid = TEST_QUOTED_SSID_1;
networkList[1].ssid = TEST_QUOTED_SSID_2;
networkList[0].frequencies = TEST_FREQUENCIES_1;
networkList[1].frequencies = TEST_FREQUENCIES_2;
}};
private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("ee:33:a2:94:10:92");
private static final String TEST_MAC_ADDRESS_STR = "f4:f5:e8:51:9e:09";
private static final String TEST_BSSID_STR = "a8:bd:27:5b:33:72";
private static final int TEST_MCS_RATE = 5;
private static final int TEST_SEQUENCE_NUM = 0x66b0;
private static final byte[] TEST_SSID =
new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
private static final byte[] TEST_BSSID =
new byte[] {(byte) 0x12, (byte) 0xef, (byte) 0xa1,
(byte) 0x2c, (byte) 0x97, (byte) 0x8b};
// This the IE buffer which is consistent with TEST_SSID.
private static final byte[] TEST_INFO_ELEMENT_SSID =
new byte[] {
// Element ID for SSID.
(byte) 0x00,
// Length of the SSID: 0x0b or 11.
(byte) 0x0b,
// This is string "GoogleGuest"
'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
// RSN IE data indicating EAP key management.
private static final byte[] TEST_INFO_ELEMENT_RSN =
new byte[] {
// Element ID for RSN.
(byte) 0x30,
// Length of the element data.
(byte) 0x18,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02,
(byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x04,
(byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x02, (byte) 0x01, (byte) 0x00,
(byte) 0x00, (byte) 0x0F, (byte) 0xAC, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
private static final int TEST_FREQUENCY = 2456;
private static final int TEST_SIGNAL_MBM = -4500;
private static final long TEST_TSF = 34455441;
private static final int TEST_CAPABILITY = 0b0000_0000_0010_0100;
private static final boolean TEST_ASSOCIATED = true;
private static final NativeScanResult MOCK_NATIVE_SCAN_RESULT = createMockNativeScanResult();
private static NativeScanResult createMockNativeScanResult() {
NativeScanResult result = new NativeScanResult();
result.ssid = TEST_SSID;
result.bssid = TEST_BSSID;
result.infoElement = TEST_INFO_ELEMENT_SSID;
result.frequency = TEST_FREQUENCY;
result.signalMbm = TEST_SIGNAL_MBM;
result.tsf = TEST_TSF;
result.capability = TEST_CAPABILITY;
result.associated = TEST_ASSOCIATED;
result.radioChainInfos = new ArrayList<>();
return result;
}
private static final RadioChainInfo MOCK_NATIVE_RADIO_CHAIN_INFO_1 = new RadioChainInfo(1, -89);
private static final RadioChainInfo MOCK_NATIVE_RADIO_CHAIN_INFO_2 = new RadioChainInfo(0, -78);
@Mock private WifiVendorHal mWifiVendorHal;
@Mock private WifiNl80211Manager mWificondControl;
@Mock private SupplicantStaIfaceHal mStaIfaceHal;
@Mock private HostapdHal mHostapdHal;
@Mock private WifiMonitor mWifiMonitor;
@Mock private PropertyService mPropertyService;
@Mock private WifiMetrics mWifiMetrics;
@Mock private Handler mHandler;
@Mock private SendMgmtFrameCallback mSendMgmtFrameCallback;
@Mock private Random mRandom;
@Mock private WifiInjector mWifiInjector;
@Mock private NetdWrapper mNetdWrapper;
ArgumentCaptor<WifiNl80211Manager.ScanEventCallback> mScanCallbackCaptor =
ArgumentCaptor.forClass(WifiNl80211Manager.ScanEventCallback.class);
private WifiNative mWifiNative;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mWifiVendorHal.initialize(any())).thenReturn(true);
when(mWifiVendorHal.isVendorHalSupported()).thenReturn(true);
when(mWifiVendorHal.startVendorHal()).thenReturn(true);
when(mWifiVendorHal.startVendorHalSta()).thenReturn(true);
when(mWifiVendorHal.startVendorHalAp()).thenReturn(true);
when(mWifiVendorHal.createStaIface(any())).thenReturn(WIFI_IFACE_NAME);
when(mWificondControl.setupInterfaceForClientMode(any(), any(), any(), any())).thenReturn(
true);
when(mStaIfaceHal.registerDeathHandler(any())).thenReturn(true);
when(mStaIfaceHal.isInitializationComplete()).thenReturn(true);
when(mStaIfaceHal.initialize()).thenReturn(true);
when(mStaIfaceHal.startDaemon()).thenReturn(true);
when(mStaIfaceHal.setupIface(any())).thenReturn(true);
when(mWifiInjector.makeNetdWrapper()).thenReturn(mNetdWrapper);
mWifiNative = new WifiNative(
mWifiVendorHal, mStaIfaceHal, mHostapdHal, mWificondControl,
mWifiMonitor, mPropertyService, mWifiMetrics,
mHandler, mRandom, mWifiInjector);
mWifiNative.initialize();
}
/**
* Verifies that TxFateReport's constructor sets all of the TxFateReport fields.
*/
@Test
public void testTxFateReportCtorSetsFields() {
WifiNative.TxFateReport fateReport = new WifiNative.TxFateReport(
WifiLoggerHal.TX_PKT_FATE_SENT, // non-zero value
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_ETHERNET_II, // non-zero value
FATE_REPORT_FRAME_BYTES
);
assertEquals(WifiLoggerHal.TX_PKT_FATE_SENT, fateReport.mFate);
assertEquals(FATE_REPORT_DRIVER_TIMESTAMP_USEC, fateReport.mDriverTimestampUSec);
assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, fateReport.mFrameType);
assertArrayEquals(FATE_REPORT_FRAME_BYTES, fateReport.mFrameBytes);
}
/**
* Verifies that RxFateReport's constructor sets all of the RxFateReport fields.
*/
@Test
public void testRxFateReportCtorSetsFields() {
WifiNative.RxFateReport fateReport = new WifiNative.RxFateReport(
WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, // non-zero value
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_ETHERNET_II, // non-zero value
FATE_REPORT_FRAME_BYTES
);
assertEquals(WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, fateReport.mFate);
assertEquals(FATE_REPORT_DRIVER_TIMESTAMP_USEC, fateReport.mDriverTimestampUSec);
assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, fateReport.mFrameType);
assertArrayEquals(FATE_REPORT_FRAME_BYTES, fateReport.mFrameBytes);
}
/**
* Verifies the hashCode methods for HiddenNetwork and PnoNetwork classes
*/
@Test
public void testHashCode() {
WifiNative.HiddenNetwork hiddenNet1 = new WifiNative.HiddenNetwork();
hiddenNet1.ssid = new String("sametext");
WifiNative.HiddenNetwork hiddenNet2 = new WifiNative.HiddenNetwork();
hiddenNet2.ssid = new String("sametext");
assertTrue(hiddenNet1.equals(hiddenNet2));
assertEquals(hiddenNet1.hashCode(), hiddenNet2.hashCode());
WifiNative.PnoNetwork pnoNet1 = new WifiNative.PnoNetwork();
pnoNet1.ssid = new String("sametext");
pnoNet1.flags = 2;
pnoNet1.auth_bit_field = 4;
pnoNet1.frequencies = TEST_FREQUENCIES_2;
WifiNative.PnoNetwork pnoNet2 = new WifiNative.PnoNetwork();
pnoNet2.ssid = new String("sametext");
pnoNet2.flags = 2;
pnoNet2.auth_bit_field = 4;
pnoNet2.frequencies = TEST_FREQUENCIES_2;
assertTrue(pnoNet1.equals(pnoNet2));
assertEquals(pnoNet1.hashCode(), pnoNet2.hashCode());
}
// Support classes for test{Tx,Rx}FateReportToString.
private static class FrameTypeMapping {
byte mTypeNumber;
String mExpectedTypeText;
String mExpectedProtocolText;
FrameTypeMapping(byte typeNumber, String expectedTypeText, String expectedProtocolText) {
this.mTypeNumber = typeNumber;
this.mExpectedTypeText = expectedTypeText;
this.mExpectedProtocolText = expectedProtocolText;
}
}
private static class FateMapping {
byte mFateNumber;
String mExpectedText;
FateMapping(byte fateNumber, String expectedText) {
this.mFateNumber = fateNumber;
this.mExpectedText = expectedText;
}
}
/**
* Verifies that FateReport.getTableHeader() prints the right header.
*/
@Test
public void testFateReportTableHeader() {
final String header = WifiNative.FateReport.getTableHeader();
assertEquals(
"\nTime usec Walltime Direction Fate "
+ "Protocol Type Result\n"
+ "--------- -------- --------- ---- "
+ "-------- ---- ------\n", header);
}
/**
* Verifies that TxFateReport.toTableRowString() includes the information we care about.
*/
@Test
public void testTxFateReportToTableRowString() {
WifiNative.TxFateReport fateReport = TX_FATE_REPORT;
assertTrue(
fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches(
FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp
+ "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime
+ "TX " // direction
+ "sent " // fate
+ "Ethernet " // type
+ "N/A " // protocol
+ "N/A" // result
)
);
for (FrameTypeMapping frameTypeMapping : FRAME_TYPE_MAPPINGS) {
fateReport = new WifiNative.TxFateReport(
WifiLoggerHal.TX_PKT_FATE_SENT,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
frameTypeMapping.mTypeNumber,
FATE_REPORT_FRAME_BYTES
);
assertTrue(
fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches(
FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp
+ "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime
+ "TX " // direction
+ "sent " // fate
+ frameTypeMapping.mExpectedProtocolText + " " // type
+ "N/A " // protocol
+ "N/A" // result
)
);
}
for (FateMapping fateMapping : TX_FATE_MAPPINGS) {
fateReport = new WifiNative.TxFateReport(
fateMapping.mFateNumber,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_80211_MGMT,
FATE_REPORT_FRAME_BYTES
);
assertTrue(
fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches(
FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp
+ "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime
+ "TX " // direction
+ Pattern.quote(fateMapping.mExpectedText) + " " // fate
+ "802.11 Mgmt " // type
+ "N/A " // protocol
+ "N/A" // result
)
);
}
}
/**
* Verifies that TxFateReport.toVerboseStringWithPiiAllowed() includes the information we care
* about.
*/
@Test
public void testTxFateReportToVerboseStringWithPiiAllowed() {
WifiNative.TxFateReport fateReport = TX_FATE_REPORT;
String verboseFateString = fateReport.toVerboseStringWithPiiAllowed();
assertTrue(verboseFateString.contains("Frame direction: TX"));
assertTrue(verboseFateString.contains("Frame timestamp: 12345"));
assertTrue(verboseFateString.contains("Frame fate: sent"));
assertTrue(verboseFateString.contains("Frame type: data"));
assertTrue(verboseFateString.contains("Frame protocol: Ethernet"));
assertTrue(verboseFateString.contains("Frame protocol type: N/A"));
assertTrue(verboseFateString.contains("Frame length: 16"));
assertTrue(verboseFateString.contains(
"61 62 63 64 65 66 67 68 00 01 02 03 04 05 06 07")); // hex dump
// TODO(quiche): uncomment this, once b/27975149 is fixed.
// assertTrue(verboseFateString.contains("abcdefgh........")); // hex dump
for (FrameTypeMapping frameTypeMapping : FRAME_TYPE_MAPPINGS) {
fateReport = new WifiNative.TxFateReport(
WifiLoggerHal.TX_PKT_FATE_SENT,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
frameTypeMapping.mTypeNumber,
FATE_REPORT_FRAME_BYTES
);
verboseFateString = fateReport.toVerboseStringWithPiiAllowed();
assertTrue(verboseFateString.contains("Frame type: "
+ frameTypeMapping.mExpectedTypeText));
}
for (FateMapping fateMapping : TX_FATE_MAPPINGS) {
fateReport = new WifiNative.TxFateReport(
fateMapping.mFateNumber,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_80211_MGMT,
FATE_REPORT_FRAME_BYTES
);
verboseFateString = fateReport.toVerboseStringWithPiiAllowed();
assertTrue(verboseFateString.contains("Frame fate: " + fateMapping.mExpectedText));
}
}
/**
* Verifies that RxFateReport.toTableRowString() includes the information we care about.
*/
@Test
public void testRxFateReportToTableRowString() {
WifiNative.RxFateReport fateReport = RX_FATE_REPORT;
assertTrue(
fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches(
FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp
+ "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime
+ "RX " // direction
+ Pattern.quote("firmware dropped (invalid frame) ") // fate
+ "Ethernet " // type
+ "N/A " // protocol
+ "N/A" // result
)
);
// FrameTypeMappings omitted, as they're the same as for TX.
for (FateMapping fateMapping : RX_FATE_MAPPINGS) {
fateReport = new WifiNative.RxFateReport(
fateMapping.mFateNumber,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_80211_MGMT,
FATE_REPORT_FRAME_BYTES
);
assertTrue(
fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches(
FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp
+ "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime
+ "RX " // direction
+ Pattern.quote(fateMapping.mExpectedText) + " " // fate
+ "802.11 Mgmt " // type
+ "N/A " // protocol
+ "N/A" // result
)
);
}
}
/**
* Verifies that RxFateReport.toVerboseStringWithPiiAllowed() includes the information we care
* about.
*/
@Test
public void testRxFateReportToVerboseStringWithPiiAllowed() {
WifiNative.RxFateReport fateReport = RX_FATE_REPORT;
String verboseFateString = fateReport.toVerboseStringWithPiiAllowed();
assertTrue(verboseFateString.contains("Frame direction: RX"));
assertTrue(verboseFateString.contains("Frame timestamp: 12345"));
assertTrue(verboseFateString.contains("Frame fate: firmware dropped (invalid frame)"));
assertTrue(verboseFateString.contains("Frame type: data"));
assertTrue(verboseFateString.contains("Frame protocol: Ethernet"));
assertTrue(verboseFateString.contains("Frame protocol type: N/A"));
assertTrue(verboseFateString.contains("Frame length: 16"));
assertTrue(verboseFateString.contains(
"61 62 63 64 65 66 67 68 00 01 02 03 04 05 06 07")); // hex dump
// TODO(quiche): uncomment this, once b/27975149 is fixed.
// assertTrue(verboseFateString.contains("abcdefgh........")); // hex dump
// FrameTypeMappings omitted, as they're the same as for TX.
for (FateMapping fateMapping : RX_FATE_MAPPINGS) {
fateReport = new WifiNative.RxFateReport(
fateMapping.mFateNumber,
FATE_REPORT_DRIVER_TIMESTAMP_USEC,
WifiLoggerHal.FRAME_TYPE_80211_MGMT,
FATE_REPORT_FRAME_BYTES
);
verboseFateString = fateReport.toVerboseStringWithPiiAllowed();
assertTrue(verboseFateString.contains("Frame fate: " + fateMapping.mExpectedText));
}
}
/**
* Verifies that startPktFateMonitoring returns false when HAL is not started.
*/
@Test
public void testStartPktFateMonitoringReturnsFalseWhenHalIsNotStarted() {
assertFalse(mWifiNative.isHalStarted());
assertFalse(mWifiNative.startPktFateMonitoring(WIFI_IFACE_NAME));
}
/**
* Verifies that getTxPktFates returns error when HAL is not started.
*/
@Test
public void testGetTxPktFatesReturnsErrorWhenHalIsNotStarted() {
WifiNative.TxFateReport[] fateReports = null;
assertFalse(mWifiNative.isHalStarted());
assertFalse(mWifiNative.getTxPktFates(WIFI_IFACE_NAME, fateReports));
}
/**
* Verifies that getRxPktFates returns error when HAL is not started.
*/
@Test
public void testGetRxPktFatesReturnsErrorWhenHalIsNotStarted() {
WifiNative.RxFateReport[] fateReports = null;
assertFalse(mWifiNative.isHalStarted());
assertFalse(mWifiNative.getRxPktFates(WIFI_IFACE_NAME, fateReports));
}
// TODO(quiche): Add tests for the success cases (when HAL has been started). Specifically:
// - testStartPktFateMonitoringCallsHalIfHalIsStarted()
// - testGetTxPktFatesCallsHalIfHalIsStarted()
// - testGetRxPktFatesCallsHalIfHalIsStarted()
//
// Adding these tests is difficult to do at the moment, because we can't mock out the HAL
// itself. Also, we can't mock out the native methods, because those methods are private.
// b/28005116.
/** Verifies that getDriverStateDumpNative returns null when HAL is not started. */
@Test
public void testGetDriverStateDumpReturnsNullWhenHalIsNotStarted() {
assertEquals(null, mWifiNative.getDriverStateDump());
}
// TODO(b/28005116): Add test for the success case of getDriverStateDump().
/**
* Verifies client mode + scan success.
*/
@Test
public void testClientModeScanSuccess() {
mWifiNative.setupInterfaceForClientInConnectivityMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
mScanCallbackCaptor.capture(), any());
mScanCallbackCaptor.getValue().onScanResultReady();
verify(mWifiMonitor).broadcastScanResultEvent(WIFI_IFACE_NAME);
}
/**
* Verifies client mode + scan failure.
*/
@Test
public void testClientModeScanFailure() {
mWifiNative.setupInterfaceForClientInConnectivityMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
mScanCallbackCaptor.capture(), any());
mScanCallbackCaptor.getValue().onScanFailed();
verify(mWifiMonitor).broadcastScanFailedEvent(WIFI_IFACE_NAME);
}
/**
* Verifies client mode + PNO scan success.
*/
@Test
public void testClientModePnoScanSuccess() {
mWifiNative.setupInterfaceForClientInConnectivityMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
any(), mScanCallbackCaptor.capture());
mScanCallbackCaptor.getValue().onScanResultReady();
verify(mWifiMonitor).broadcastPnoScanResultEvent(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementPnoFoundNetworkEventCount();
}
/**
* Verifies client mode + PNO scan failure.
*/
@Test
public void testClientModePnoScanFailure() {
mWifiNative.setupInterfaceForClientInConnectivityMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
any(), mScanCallbackCaptor.capture());
mScanCallbackCaptor.getValue().onScanFailed();
verify(mWifiMetrics).incrementPnoScanFailedCount();
}
/**
* Verifies scan mode + scan success.
*/
@Test
public void testScanModeScanSuccess() {
mWifiNative.setupInterfaceForClientInScanMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
mScanCallbackCaptor.capture(), any());
mScanCallbackCaptor.getValue().onScanResultReady();
verify(mWifiMonitor).broadcastScanResultEvent(WIFI_IFACE_NAME);
}
/**
* Verifies scan mode + scan failure.
*/
@Test
public void testScanModeScanFailure() {
mWifiNative.setupInterfaceForClientInScanMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
mScanCallbackCaptor.capture(), any());
mScanCallbackCaptor.getValue().onScanFailed();
verify(mWifiMonitor).broadcastScanFailedEvent(WIFI_IFACE_NAME);
}
/**
* Verifies scan mode + PNO scan success.
*/
@Test
public void testScanModePnoScanSuccess() {
mWifiNative.setupInterfaceForClientInScanMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
any(), mScanCallbackCaptor.capture());
mScanCallbackCaptor.getValue().onScanResultReady();
verify(mWifiMonitor).broadcastPnoScanResultEvent(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementPnoFoundNetworkEventCount();
}
/**
* Verifies scan mode + PNO scan failure.
*/
@Test
public void testScanModePnoScanFailure() {
mWifiNative.setupInterfaceForClientInScanMode(null);
verify(mWificondControl).setupInterfaceForClientMode(eq(WIFI_IFACE_NAME), any(),
any(), mScanCallbackCaptor.capture());
mScanCallbackCaptor.getValue().onScanFailed();
verify(mWifiMetrics).incrementPnoScanFailedCount();
}
/**
* Verifies that signalPoll() calls underlying WificondControl.
*/
@Test
public void testSignalPoll() throws Exception {
when(mWificondControl.signalPoll(WIFI_IFACE_NAME))
.thenReturn(SIGNAL_POLL_RESULT);
WifiNl80211Manager.SignalPollResult pollResult = mWifiNative.signalPoll(WIFI_IFACE_NAME);
assertEquals(SIGNAL_POLL_RESULT.currentRssiDbm, pollResult.currentRssiDbm);
assertEquals(SIGNAL_POLL_RESULT.txBitrateMbps, pollResult.txBitrateMbps);
assertEquals(SIGNAL_POLL_RESULT.associationFrequencyMHz,
pollResult.associationFrequencyMHz);
assertEquals(SIGNAL_POLL_RESULT.rxBitrateMbps, pollResult.rxBitrateMbps);
verify(mWificondControl).signalPoll(WIFI_IFACE_NAME);
}
/**
* Verifies that scan() calls underlying WificondControl.
*/
@Test
public void testScan() throws Exception {
mWifiNative.scan(WIFI_IFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, SCAN_FREQ_SET,
SCAN_HIDDEN_NETWORK_SSID_SET);
ArgumentCaptor<List<byte[]>> ssidSetCaptor = ArgumentCaptor.forClass(List.class);
verify(mWificondControl).startScan(
eq(WIFI_IFACE_NAME), eq(WifiScanner.SCAN_TYPE_HIGH_ACCURACY),
eq(SCAN_FREQ_SET), ssidSetCaptor.capture());
List<byte[]> ssidSet = ssidSetCaptor.getValue();
assertArrayEquals(ssidSet.toArray(), SCAN_HIDDEN_NETWORK_BYTE_SSID_SET.toArray());
}
/**
* Verifies that startPnoscan() calls underlying WificondControl.
*/
@Test
public void testStartPnoScanOnRequestProcessed() throws Exception {
mWifiNative.startPnoScan(WIFI_IFACE_NAME, TEST_PNO_SETTINGS);
ArgumentCaptor<WifiNl80211Manager.PnoScanRequestCallback> captor =
ArgumentCaptor.forClass(WifiNl80211Manager.PnoScanRequestCallback.class);
verify(mWificondControl).startPnoScan(eq(WIFI_IFACE_NAME),
eq(TEST_PNO_SETTINGS.toNativePnoSettings()), any(), captor.capture());
captor.getValue().onPnoRequestSucceeded();
verify(mWifiMetrics).incrementPnoScanStartAttemptCount();
}
/**
* Verifies that startPnoscan() calls underlying WificondControl.
*/
@Test
public void testStartPnoScanOnRequestFailed() throws Exception {
mWifiNative.startPnoScan(WIFI_IFACE_NAME, TEST_PNO_SETTINGS);
ArgumentCaptor<WifiNl80211Manager.PnoScanRequestCallback> captor =
ArgumentCaptor.forClass(WifiNl80211Manager.PnoScanRequestCallback.class);
verify(mWificondControl).startPnoScan(eq(WIFI_IFACE_NAME),
eq(TEST_PNO_SETTINGS.toNativePnoSettings()), any(), captor.capture());
captor.getValue().onPnoRequestFailed();
verify(mWifiMetrics).incrementPnoScanStartAttemptCount();
verify(mWifiMetrics).incrementPnoScanFailedCount();
}
/**
* Verifies that stopPnoscan() calls underlying WificondControl.
*/
@Test
public void testStopPnoScan() throws Exception {
mWifiNative.stopPnoScan(WIFI_IFACE_NAME);
verify(mWificondControl).stopPnoScan(WIFI_IFACE_NAME);
}
/**
* Verifies that getScanResults() can parse NativeScanResult from wificond correctly,
*/
@Test
public void testGetScanResults() {
// Mock the returned array of NativeScanResult.
List<NativeScanResult> mockScanResults = Arrays.asList(MOCK_NATIVE_SCAN_RESULT);
when(mWificondControl.getScanResults(anyString(), anyInt())).thenReturn(mockScanResults);
ArrayList<ScanDetail> returnedScanResults = mWifiNative.getScanResults(WIFI_IFACE_NAME);
assertEquals(mockScanResults.size(), returnedScanResults.size());
// Since NativeScanResult is organized differently from ScanResult, this only checks
// a few fields.
for (int i = 0; i < mockScanResults.size(); i++) {
assertArrayEquals(mockScanResults.get(i).getSsid(),
returnedScanResults.get(i).getScanResult().SSID.getBytes());
assertEquals(mockScanResults.get(i).getFrequencyMhz(),
returnedScanResults.get(i).getScanResult().frequency);
assertEquals(mockScanResults.get(i).getTsf(),
returnedScanResults.get(i).getScanResult().timestamp);
}
}
/**
* Verifies that getScanResults() can parse NativeScanResult from wificond correctly,
* when there is radio chain info.
*/
@Test
public void testGetScanResultsWithRadioChainInfo() throws Exception {
// Mock the returned array of NativeScanResult.
NativeScanResult nativeScanResult = createMockNativeScanResult();
// Add radio chain info
List<RadioChainInfo> nativeRadioChainInfos = Arrays.asList(
MOCK_NATIVE_RADIO_CHAIN_INFO_1, MOCK_NATIVE_RADIO_CHAIN_INFO_2);
nativeScanResult.radioChainInfos = nativeRadioChainInfos;
List<NativeScanResult> mockScanResults = Arrays.asList(nativeScanResult);
when(mWificondControl.getScanResults(anyString(), anyInt())).thenReturn(mockScanResults);
ArrayList<ScanDetail> returnedScanResults = mWifiNative.getScanResults(WIFI_IFACE_NAME);
assertEquals(mockScanResults.size(), returnedScanResults.size());
// Since NativeScanResult is organized differently from ScanResult, this only checks
// a few fields.
for (int i = 0; i < mockScanResults.size(); i++) {
assertArrayEquals(mockScanResults.get(i).getSsid(),
returnedScanResults.get(i).getScanResult().SSID.getBytes());
assertEquals(mockScanResults.get(i).getFrequencyMhz(),
returnedScanResults.get(i).getScanResult().frequency);
assertEquals(mockScanResults.get(i).getTsf(),
returnedScanResults.get(i).getScanResult().timestamp);
ScanResult.RadioChainInfo[] scanRcis = returnedScanResults.get(
i).getScanResult().radioChainInfos;
assertEquals(nativeRadioChainInfos.size(), scanRcis.length);
for (int j = 0; j < scanRcis.length; ++j) {
assertEquals(nativeRadioChainInfos.get(j).getChainId(), scanRcis[j].id);
assertEquals(nativeRadioChainInfos.get(j).getLevelDbm(), scanRcis[j].level);
}
}
}
/**
* Verifies that connectToNetwork() calls underlying WificondControl and SupplicantStaIfaceHal.
*/
@Test
public void testConnectToNetwork() throws Exception {
WifiConfiguration config = mock(WifiConfiguration.class);
mWifiNative.connectToNetwork(WIFI_IFACE_NAME, config);
// connectToNetwork() should abort ongoing scan before connection.
verify(mWificondControl).abortScan(WIFI_IFACE_NAME);
verify(mStaIfaceHal).connectToNetwork(WIFI_IFACE_NAME, config);
}
/**
* Verifies that roamToNetwork() calls underlying WificondControl and SupplicantStaIfaceHal.
*/
@Test
public void testRoamToNetwork() throws Exception {
WifiConfiguration config = mock(WifiConfiguration.class);
mWifiNative.roamToNetwork(WIFI_IFACE_NAME, config);
// roamToNetwork() should abort ongoing scan before connection.
verify(mWificondControl).abortScan(WIFI_IFACE_NAME);
verify(mStaIfaceHal).roamToNetwork(WIFI_IFACE_NAME, config);
}
/**
* Verifies that setMacAddress() calls underlying WifiVendorHal.
*/
@Test
public void testSetMacAddress() throws Exception {
mWifiNative.setMacAddress(WIFI_IFACE_NAME, TEST_MAC_ADDRESS);
verify(mStaIfaceHal).disconnect(WIFI_IFACE_NAME);
verify(mWifiVendorHal).setMacAddress(WIFI_IFACE_NAME, TEST_MAC_ADDRESS);
}
/**
* Verifies that isSetMacAddressSupported() calls underlying WifiVendorHal.
*/
@Test
public void testIsSetMacAddressSupported() throws Exception {
mWifiNative.isSetMacAddressSupported(WIFI_IFACE_NAME);
verify(mWifiVendorHal).isSetMacAddressSupported(WIFI_IFACE_NAME);
}
/**
* Test that selectTxPowerScenario() calls into WifiVendorHal (success case)
*/
@Test
public void testSelectTxPowerScenario_success() throws Exception {
when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(true);
SarInfo sarInfo = new SarInfo();
assertTrue(mWifiNative.selectTxPowerScenario(sarInfo));
verify(mWifiVendorHal).selectTxPowerScenario(sarInfo);
}
/**
* Test that selectTxPowerScenario() calls into WifiVendorHal (failure case)
*/
@Test
public void testSelectTxPowerScenario_failure() throws Exception {
when(mWifiVendorHal.selectTxPowerScenario(any(SarInfo.class))).thenReturn(false);
SarInfo sarInfo = new SarInfo();
assertFalse(mWifiNative.selectTxPowerScenario(sarInfo));
verify(mWifiVendorHal).selectTxPowerScenario(sarInfo);
}
/**
* Test that setPowerSave() with true, results in calling into SupplicantStaIfaceHal
*/
@Test
public void testSetPowerSaveTrue() throws Exception {
mWifiNative.setPowerSave(WIFI_IFACE_NAME, true);
verify(mStaIfaceHal).setPowerSave(WIFI_IFACE_NAME, true);
}
/**
* Test that setPowerSave() with false, results in calling into SupplicantStaIfaceHal
*/
@Test
public void testSetPowerSaveFalse() throws Exception {
mWifiNative.setPowerSave(WIFI_IFACE_NAME, false);
verify(mStaIfaceHal).setPowerSave(WIFI_IFACE_NAME, false);
}
/**
* Test that setLowLatencyMode() with true, results in calling into WifiVendorHal
*/
@Test
public void testLowLatencyModeTrue() throws Exception {
when(mWifiVendorHal.setLowLatencyMode(anyBoolean())).thenReturn(true);
assertTrue(mWifiNative.setLowLatencyMode(true));
verify(mWifiVendorHal).setLowLatencyMode(true);
}
/**
* Test that setLowLatencyMode() with false, results in calling into WifiVendorHal
*/
@Test
public void testLowLatencyModeFalse() throws Exception {
when(mWifiVendorHal.setLowLatencyMode(anyBoolean())).thenReturn(true);
assertTrue(mWifiNative.setLowLatencyMode(false));
verify(mWifiVendorHal).setLowLatencyMode(false);
}
/**
* Test that setLowLatencyMode() returns with failure when WifiVendorHal fails.
*/
@Test
public void testSetLowLatencyModeFail() throws Exception {
final boolean lowLatencyMode = true;
when(mWifiVendorHal.setLowLatencyMode(anyBoolean())).thenReturn(false);
assertFalse(mWifiNative.setLowLatencyMode(lowLatencyMode));
verify(mWifiVendorHal).setLowLatencyMode(lowLatencyMode);
}
@Test
public void testGetFactoryMacAddress() throws Exception {
when(mWifiVendorHal.getFactoryMacAddress(any())).thenReturn(MacAddress.BROADCAST_ADDRESS);
assertNotNull(mWifiNative.getFactoryMacAddress(WIFI_IFACE_NAME));
verify(mWifiVendorHal).getFactoryMacAddress(any());
}
/**
* Test that flushRingBufferData(), results in calling into WifiVendorHal
*/
@Test
public void testFlushRingBufferDataTrue() throws Exception {
when(mWifiVendorHal.flushRingBufferData()).thenReturn(true);
assertTrue(mWifiNative.flushRingBufferData());
verify(mWifiVendorHal).flushRingBufferData();
}
/**
* Tests that WifiNative#sendMgmtFrame() calls WificondControl#sendMgmtFrame()
*/
@Test
public void testSendMgmtFrame() {
mWifiNative.sendMgmtFrame(WIFI_IFACE_NAME, FATE_REPORT_FRAME_BYTES,
mSendMgmtFrameCallback, TEST_MCS_RATE);
verify(mWificondControl).sendMgmtFrame(eq(WIFI_IFACE_NAME),
AdditionalMatchers.aryEq(FATE_REPORT_FRAME_BYTES), eq(TEST_MCS_RATE),
any(), eq(mSendMgmtFrameCallback));
}
/**
* Tests that probeLink() generates the correct frame and calls WificondControl#sendMgmtFrame().
*/
@Test
public void testProbeLinkSuccess() {
byte[] expectedFrame = {
0x40, 0x00, 0x3c, 0x00, (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b,
0x33, 0x72, (byte) 0xf4, (byte) 0xf5, (byte) 0xe8, 0x51, (byte) 0x9e, 0x09,
(byte) 0xa8, (byte) 0xbd, 0x27, 0x5b, 0x33, 0x72, (byte) 0xb0, 0x66,
0x00, 0x00
};
when(mStaIfaceHal.getMacAddress(WIFI_IFACE_NAME)).thenReturn(TEST_MAC_ADDRESS_STR);
when(mRandom.nextInt()).thenReturn(TEST_SEQUENCE_NUM);
mWifiNative.probeLink(WIFI_IFACE_NAME, MacAddress.fromString(TEST_BSSID_STR),
mSendMgmtFrameCallback, TEST_MCS_RATE);
verify(mSendMgmtFrameCallback, never()).onFailure(anyInt());
verify(mWificondControl).sendMgmtFrame(eq(WIFI_IFACE_NAME),
AdditionalMatchers.aryEq(expectedFrame), eq(TEST_MCS_RATE),
any(), eq(mSendMgmtFrameCallback));
}
/**
* Tests that probeLink() triggers the failure callback when it cannot get the sender MAC
* address.
*/
@Test
public void testProbeLinkFailureCannotGetSenderMac() {
when(mStaIfaceHal.getMacAddress(WIFI_IFACE_NAME)).thenReturn(null);
mWifiNative.probeLink(WIFI_IFACE_NAME, MacAddress.fromString(TEST_BSSID_STR),
mSendMgmtFrameCallback, TEST_MCS_RATE);
verify(mSendMgmtFrameCallback).onFailure(
WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
verify(mWificondControl, never()).sendMgmtFrame(any(), any(), anyInt(), any(), any());
}
/**
* Tests that probeLink() triggers the failure callback when it cannot get the BSSID.
*/
@Test
public void testProbeLinkFailureCannotGetBssid() {
when(mStaIfaceHal.getMacAddress(WIFI_IFACE_NAME)).thenReturn(TEST_MAC_ADDRESS_STR);
mWifiNative.probeLink(WIFI_IFACE_NAME, null, mSendMgmtFrameCallback, TEST_MCS_RATE);
verify(mSendMgmtFrameCallback).onFailure(
WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
verify(mWificondControl, never()).sendMgmtFrame(any(), any(), anyInt(), any(), any());
}
/**
* Tests that WifiNative#addHlpReq() calls
* SupplicantStaIfaceHal#addHlpReq()
*/
@Test
public void testaddHlpReq() {
byte[] hlpPacket = {
0x40, 0x00, 0x3c, 0x00, (byte) 0xa8, (byte) 0xbd, 0x27, 0x5b,
0x33, 0x72, (byte) 0xf4, (byte) 0xf5, (byte) 0xe8, 0x51, (byte) 0x9e, 0x09,
(byte) 0xa8, (byte) 0xbd, 0x27, 0x5b, 0x33, 0x72, (byte) 0xb0, 0x66,
0x00, 0x00
};
mWifiNative.addHlpReq(WIFI_IFACE_NAME, TEST_MAC_ADDRESS, hlpPacket);
verify(mStaIfaceHal).addHlpReq(eq(WIFI_IFACE_NAME),
eq(TEST_MAC_ADDRESS.toByteArray()), eq(hlpPacket));
}
/**
* Tests that WifiNative#flushAllHlp() calls
* SupplicantStaIfaceHal#flushAllHlp()
*/
@Test
public void testflushAllHlp() {
mWifiNative.flushAllHlp(WIFI_IFACE_NAME);
verify(mStaIfaceHal).flushAllHlp(eq(WIFI_IFACE_NAME));
}
}