Home | History | Annotate | Download | only in rtt
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 package com.android.server.wifi.rtt;
     19 
     20 import static org.hamcrest.core.IsEqual.equalTo;
     21 import static org.junit.Assert.assertFalse;
     22 import static org.junit.Assert.assertTrue;
     23 import static org.mockito.ArgumentMatchers.any;
     24 import static org.mockito.ArgumentMatchers.anyInt;
     25 import static org.mockito.ArgumentMatchers.eq;
     26 import static org.mockito.Mockito.verify;
     27 import static org.mockito.Mockito.verifyNoMoreInteractions;
     28 import static org.mockito.Mockito.when;
     29 
     30 import android.hardware.wifi.V1_0.IWifiRttController;
     31 import android.hardware.wifi.V1_0.RttBw;
     32 import android.hardware.wifi.V1_0.RttCapabilities;
     33 import android.hardware.wifi.V1_0.RttConfig;
     34 import android.hardware.wifi.V1_0.RttPeerType;
     35 import android.hardware.wifi.V1_0.RttPreamble;
     36 import android.hardware.wifi.V1_0.RttResult;
     37 import android.hardware.wifi.V1_0.RttStatus;
     38 import android.hardware.wifi.V1_0.RttType;
     39 import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
     40 import android.hardware.wifi.V1_0.WifiStatus;
     41 import android.hardware.wifi.V1_0.WifiStatusCode;
     42 import android.net.MacAddress;
     43 import android.net.wifi.rtt.RangingRequest;
     44 
     45 import com.android.server.wifi.HalDeviceManager;
     46 
     47 import org.hamcrest.core.IsNull;
     48 import org.junit.Before;
     49 import org.junit.Rule;
     50 import org.junit.Test;
     51 import org.junit.rules.ErrorCollector;
     52 import org.mockito.ArgumentCaptor;
     53 import org.mockito.Mock;
     54 import org.mockito.MockitoAnnotations;
     55 
     56 import java.util.ArrayList;
     57 import java.util.List;
     58 
     59 /**
     60  * Unit test harness for the RttNative class.
     61  */
     62 public class RttNativeTest {
     63     private RttNative mDut;
     64     private WifiStatus mStatusSuccess;
     65 
     66     private ArgumentCaptor<ArrayList> mRttConfigCaptor = ArgumentCaptor.forClass(ArrayList.class);
     67     private ArgumentCaptor<List> mRttResultCaptor = ArgumentCaptor.forClass(List.class);
     68     private ArgumentCaptor<HalDeviceManager.ManagerStatusListener> mHdmStatusListener =
     69             ArgumentCaptor.forClass(HalDeviceManager.ManagerStatusListener.class);
     70     private ArgumentCaptor<IWifiRttController.getCapabilitiesCallback> mGetCapCbCatpr =
     71             ArgumentCaptor.forClass(IWifiRttController.getCapabilitiesCallback.class);
     72 
     73     @Rule
     74     public ErrorCollector collector = new ErrorCollector();
     75 
     76     @Mock
     77     public RttServiceImpl mockRttServiceImpl;
     78 
     79     @Mock
     80     public HalDeviceManager mockHalDeviceManager;
     81 
     82     @Mock
     83     public IWifiRttController mockRttController;
     84 
     85     @Before
     86     public void setUp() throws Exception {
     87         MockitoAnnotations.initMocks(this);
     88 
     89         when(mockHalDeviceManager.isStarted()).thenReturn(true);
     90         when(mockHalDeviceManager.createRttController()).thenReturn(mockRttController);
     91 
     92         mStatusSuccess = new WifiStatus();
     93         mStatusSuccess.code = WifiStatusCode.SUCCESS;
     94         when(mockRttController.registerEventCallback(any())).thenReturn(mStatusSuccess);
     95         when(mockRttController.rangeRequest(anyInt(), any(ArrayList.class))).thenReturn(
     96                 mStatusSuccess);
     97         when(mockRttController.rangeCancel(anyInt(), any(ArrayList.class))).thenReturn(
     98                 mStatusSuccess);
     99 
    100         mDut = new RttNative(mockRttServiceImpl, mockHalDeviceManager);
    101         mDut.start(null);
    102         verify(mockHalDeviceManager).registerStatusListener(mHdmStatusListener.capture(), any());
    103         verify(mockRttController).registerEventCallback(any());
    104         verify(mockRttServiceImpl).enableIfPossible();
    105         verify(mockRttController).getCapabilities(mGetCapCbCatpr.capture());
    106         // will override capabilities (just call cb again) for specific tests
    107         mGetCapCbCatpr.getValue().onValues(mStatusSuccess, getFullRttCapabilities());
    108         assertTrue(mDut.isReady());
    109     }
    110 
    111     /**
    112      * Validate successful ranging flow.
    113      */
    114     @Test
    115     public void testRangeRequest() throws Exception {
    116         int cmdId = 55;
    117         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
    118 
    119         // (1) issue range request
    120         mDut.rangeRequest(cmdId, request, true);
    121 
    122         // (2) verify HAL call and parameters
    123         verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
    124 
    125         // verify contents of HAL request (hard codes knowledge from getDummyRangingRequest()).
    126         ArrayList<RttConfig> halRequest = mRttConfigCaptor.getValue();
    127 
    128         collector.checkThat("number of entries", halRequest.size(),
    129                 equalTo(request.mRttPeers.size()));
    130 
    131         RttConfig rttConfig = halRequest.get(0);
    132         collector.checkThat("entry 0: MAC", rttConfig.addr,
    133                 equalTo(MacAddress.fromString("00:01:02:03:04:00").toByteArray()));
    134         collector.checkThat("entry 0: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    135         collector.checkThat("entry 0: peer type", rttConfig.peer, equalTo(RttPeerType.AP));
    136         collector.checkThat("entry 0: lci", rttConfig.mustRequestLci, equalTo(true));
    137         collector.checkThat("entry 0: lcr", rttConfig.mustRequestLcr, equalTo(true));
    138 
    139         rttConfig = halRequest.get(1);
    140         collector.checkThat("entry 1: MAC", rttConfig.addr,
    141                 equalTo(MacAddress.fromString("0A:0B:0C:0D:0E:00").toByteArray()));
    142         collector.checkThat("entry 1: rtt type", rttConfig.type, equalTo(RttType.ONE_SIDED));
    143         collector.checkThat("entry 1: peer type", rttConfig.peer, equalTo(RttPeerType.AP));
    144         collector.checkThat("entry 1: lci", rttConfig.mustRequestLci, equalTo(true));
    145         collector.checkThat("entry 1: lcr", rttConfig.mustRequestLcr, equalTo(true));
    146 
    147         rttConfig = halRequest.get(2);
    148         collector.checkThat("entry 2: MAC", rttConfig.addr,
    149                 equalTo(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
    150         collector.checkThat("entry 2: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    151         collector.checkThat("entry 2: peer type", rttConfig.peer, equalTo(RttPeerType.NAN));
    152         collector.checkThat("entry 2: lci", rttConfig.mustRequestLci, equalTo(false));
    153         collector.checkThat("entry 2: lcr", rttConfig.mustRequestLcr, equalTo(false));
    154 
    155         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    156     }
    157 
    158     /**
    159      * Validate ranging request with a mix of Repsonders with and without IEEE 802.11mc support,
    160      * from a non- privileged context.
    161      */
    162     @Test
    163     public void testRangeRequestNotPrivilegedNo80211mcSupportMixed() throws Exception {
    164         int cmdId = 66;
    165 
    166         // the request has 3 responders: first AP support 802.11mc, second AP does not, third is
    167         // Aware (which supports 802.11mc by default)
    168         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
    169 
    170         // (1) issue range request
    171         mDut.rangeRequest(cmdId, request, false);
    172 
    173         // (2) verify HAL call and parameters
    174         verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
    175 
    176         // verify contents of HAL request (hard codes knowledge from getDummyRangingRequest()).
    177         ArrayList<RttConfig> halRequest = mRttConfigCaptor.getValue();
    178 
    179         collector.checkThat("number of entries", halRequest.size(), equalTo(2));
    180 
    181         RttConfig rttConfig = halRequest.get(0);
    182         collector.checkThat("entry 0: MAC", rttConfig.addr,
    183                 equalTo(MacAddress.fromString("00:01:02:03:04:00").toByteArray()));
    184         collector.checkThat("entry 0: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    185         collector.checkThat("entry 0: peer type", rttConfig.peer, equalTo(RttPeerType.AP));
    186         collector.checkThat("entry 0: lci", rttConfig.mustRequestLci, equalTo(false));
    187         collector.checkThat("entry 0: lcr", rttConfig.mustRequestLcr, equalTo(false));
    188 
    189         rttConfig = halRequest.get(1);
    190         collector.checkThat("entry 1: MAC", rttConfig.addr,
    191                 equalTo(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
    192         collector.checkThat("entry 1: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    193         collector.checkThat("entry 1: peer type", rttConfig.peer, equalTo(RttPeerType.NAN));
    194         collector.checkThat("entry 1: lci", rttConfig.mustRequestLci, equalTo(false));
    195         collector.checkThat("entry 1: lcr", rttConfig.mustRequestLcr, equalTo(false));
    196 
    197         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    198     }
    199 
    200     /**
    201      * Validate successful ranging flow - with privileges access but with limited capabilities:
    202      * - No single-sided RTT
    203      * - No LCI/LCR
    204      * - Limited BW
    205      * - Limited Preamble
    206      */
    207     @Test
    208     public void testRangeRequestWithLimitedCapabilities() throws Exception {
    209         int cmdId = 55;
    210         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
    211 
    212         // update capabilities to a limited set
    213         RttCapabilities cap = getFullRttCapabilities();
    214         cap.rttOneSidedSupported = false;
    215         cap.lciSupported = false;
    216         cap.lcrSupported = false;
    217         cap.bwSupport = RttBw.BW_10MHZ | RttBw.BW_160MHZ;
    218         cap.preambleSupport = RttPreamble.LEGACY;
    219         mGetCapCbCatpr.getValue().onValues(mStatusSuccess, cap);
    220 
    221         // Note: request 1: BW = 40MHz --> 10MHz, Preamble = HT (since 40MHz) -> Legacy
    222 
    223         // (1) issue range request
    224         mDut.rangeRequest(cmdId, request, true);
    225 
    226         // (2) verify HAL call and parameters
    227         verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
    228 
    229         // verify contents of HAL request (hard codes knowledge from getDummyRangingRequest()).
    230         ArrayList<RttConfig> halRequest = mRttConfigCaptor.getValue();
    231 
    232         collector.checkThat("number of entries", halRequest.size(), equalTo(2));
    233 
    234         RttConfig rttConfig = halRequest.get(0);
    235         collector.checkThat("entry 0: MAC", rttConfig.addr,
    236                 equalTo(MacAddress.fromString("00:01:02:03:04:00").toByteArray()));
    237         collector.checkThat("entry 0: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    238         collector.checkThat("entry 0: peer type", rttConfig.peer, equalTo(RttPeerType.AP));
    239         collector.checkThat("entry 0: lci", rttConfig.mustRequestLci, equalTo(false));
    240         collector.checkThat("entry 0: lcr", rttConfig.mustRequestLcr, equalTo(false));
    241         collector.checkThat("entry 0: channel.width", rttConfig.channel.width, equalTo(
    242                 WifiChannelWidthInMhz.WIDTH_40));
    243         collector.checkThat("entry 0: bw", rttConfig.bw, equalTo(RttBw.BW_10MHZ));
    244         collector.checkThat("entry 0: preamble", rttConfig.preamble, equalTo(RttPreamble.LEGACY));
    245 
    246         rttConfig = halRequest.get(1);
    247         collector.checkThat("entry 1: MAC", rttConfig.addr,
    248                 equalTo(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
    249         collector.checkThat("entry 1: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    250         collector.checkThat("entry 1: peer type", rttConfig.peer, equalTo(RttPeerType.NAN));
    251         collector.checkThat("entry 1: lci", rttConfig.mustRequestLci, equalTo(false));
    252         collector.checkThat("entry 1: lcr", rttConfig.mustRequestLcr, equalTo(false));
    253 
    254         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    255     }
    256 
    257     /**
    258      * Validate successful ranging flow - with privileges access but with limited capabilities:
    259      * - Very limited BW
    260      * - Very limited Preamble
    261      */
    262     @Test
    263     public void testRangeRequestWithLimitedCapabilitiesNoOverlap() throws Exception {
    264         int cmdId = 55;
    265         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
    266 
    267         // update capabilities to a limited set
    268         RttCapabilities cap = getFullRttCapabilities();
    269         cap.bwSupport = RttBw.BW_80MHZ;
    270         cap.preambleSupport = RttPreamble.VHT;
    271         mGetCapCbCatpr.getValue().onValues(mStatusSuccess, cap);
    272 
    273         // Note: request 1: BW = 40MHz --> no overlap -> dropped
    274         // Note: request 2: BW = 160MHz --> 160MHz, preamble = VHT (since 160MHz) -> no overlap,
    275         //                                                                           dropped
    276 
    277         // (1) issue range request
    278         mDut.rangeRequest(cmdId, request, true);
    279 
    280         // (2) verify HAL call and parameters
    281         verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
    282 
    283         // verify contents of HAL request (hard codes knowledge from getDummyRangingRequest()).
    284         ArrayList<RttConfig> halRequest = mRttConfigCaptor.getValue();
    285 
    286         collector.checkThat("number of entries", halRequest.size(), equalTo(1));
    287 
    288         RttConfig rttConfig = halRequest.get(0);
    289         collector.checkThat("entry 0: MAC", rttConfig.addr,
    290                 equalTo(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
    291         collector.checkThat("entry 0: rtt type", rttConfig.type, equalTo(RttType.TWO_SIDED));
    292         collector.checkThat("entry 0: peer type", rttConfig.peer, equalTo(RttPeerType.NAN));
    293         collector.checkThat("entry 0: lci", rttConfig.mustRequestLci, equalTo(false));
    294         collector.checkThat("entry 0: lcr", rttConfig.mustRequestLcr, equalTo(false));
    295 
    296         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    297     }
    298 
    299     /**
    300      * Validate ranging request with all Repsonders without IEEE 802.11mc support, from a non-
    301      * privileged context.
    302      */
    303     @Test
    304     public void testRangeRequestNotPrivilegedNo80211mcSupportForAny() throws Exception {
    305         int cmdId = 77;
    306         RangingRequest request = RttTestUtils.getDummyRangingRequestNo80211mcSupport((byte) 0);
    307 
    308         // (1) issue range request
    309         mDut.rangeRequest(cmdId, request, false);
    310 
    311         // (2) verify immediate result callback (empty result set)
    312         verify(mockRttServiceImpl).onRangingResults(eq(cmdId), mRttResultCaptor.capture());
    313 
    314         collector.checkThat("Result set", mRttResultCaptor.getValue().size(), equalTo(0));
    315 
    316         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    317     }
    318 
    319     /**
    320      * Validate no range request when Wi-Fi is down
    321      */
    322     @Test
    323     public void testWifiDown() throws Exception {
    324         int cmdId = 55;
    325         RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
    326 
    327         // (1) configure Wi-Fi down and send a status change indication
    328         when(mockHalDeviceManager.isStarted()).thenReturn(false);
    329         mHdmStatusListener.getValue().onStatusChanged();
    330         verify(mockRttServiceImpl).disable();
    331         assertFalse(mDut.isReady());
    332 
    333         // (2) issue range request
    334         mDut.rangeRequest(cmdId, request, true);
    335 
    336         verifyNoMoreInteractions(mockRttServiceImpl, mockRttController);
    337     }
    338 
    339     /**
    340      * Validate ranging cancel flow.
    341      */
    342     @Test
    343     public void testRangeCancel() throws Exception {
    344         int cmdId = 66;
    345         ArrayList<byte[]> macAddresses = new ArrayList<>();
    346         byte[] mac1 = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
    347         byte[] mac2 = {0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    348         macAddresses.add(mac1);
    349         macAddresses.add(mac2);
    350 
    351         // (1) issue cancel request
    352         mDut.rangeCancel(cmdId, macAddresses);
    353 
    354         // (2) verify HAL call and parameters
    355         verify(mockRttController).rangeCancel(cmdId, macAddresses);
    356 
    357         verifyNoMoreInteractions(mockRttController);
    358     }
    359 
    360     /**
    361      * Validate correct result conversion from HAL to framework.
    362      */
    363     @Test
    364     public void testRangeResults() throws Exception {
    365         int cmdId = 55;
    366         ArrayList<RttResult> results = new ArrayList<>();
    367         RttResult res = new RttResult();
    368         res.addr[0] = 5;
    369         res.addr[1] = 6;
    370         res.addr[2] = 7;
    371         res.addr[3] = 8;
    372         res.addr[4] = 9;
    373         res.addr[5] = 10;
    374         res.status = RttStatus.SUCCESS;
    375         res.distanceInMm = 1500;
    376         res.timeStampInUs = 666;
    377         results.add(res);
    378 
    379         // (1) have HAL call native with results
    380         mDut.onResults(cmdId, results);
    381 
    382         // (2) verify call to framework
    383         verify(mockRttServiceImpl).onRangingResults(eq(cmdId), mRttResultCaptor.capture());
    384 
    385         // verify contents of the framework results
    386         List<RttResult> rttR = mRttResultCaptor.getValue();
    387 
    388         collector.checkThat("number of entries", rttR.size(), equalTo(1));
    389 
    390         RttResult rttResult = rttR.get(0);
    391         collector.checkThat("status", rttResult.status,
    392                 equalTo(RttStatus.SUCCESS));
    393         collector.checkThat("mac", rttResult.addr,
    394                 equalTo(MacAddress.fromString("05:06:07:08:09:0A").toByteArray()));
    395         collector.checkThat("distanceCm", rttResult.distanceInMm, equalTo(1500));
    396         collector.checkThat("timestamp", rttResult.timeStampInUs, equalTo(666L));
    397 
    398         verifyNoMoreInteractions(mockRttController, mockRttServiceImpl);
    399     }
    400 
    401     /**
    402      * Validate correct cleanup when a null array of results is provided by HAL.
    403      */
    404     @Test
    405     public void testRangeResultsNullArray() {
    406         int cmdId = 66;
    407 
    408         mDut.onResults(cmdId, null);
    409         verify(mockRttServiceImpl).onRangingResults(eq(cmdId), mRttResultCaptor.capture());
    410 
    411         collector.checkThat("number of entries", mRttResultCaptor.getValue().size(), equalTo(0));
    412     }
    413 
    414     /**
    415      * Validate correct cleanup when an array of results containing null entries is provided by HAL.
    416      */
    417     @Test
    418     public void testRangeResultsSomeNulls() {
    419         int cmdId = 77;
    420 
    421         ArrayList<RttResult> results = new ArrayList<>();
    422         results.add(null);
    423         results.add(new RttResult());
    424         results.add(null);
    425         results.add(null);
    426         results.add(new RttResult());
    427         results.add(null);
    428 
    429         mDut.onResults(cmdId, results);
    430         verify(mockRttServiceImpl).onRangingResults(eq(cmdId), mRttResultCaptor.capture());
    431 
    432         List<RttResult> rttR = mRttResultCaptor.getValue();
    433         collector.checkThat("number of entries", rttR.size(), equalTo(2));
    434         for (int i = 0; i < rttR.size(); ++i) {
    435             collector.checkThat("entry", rttR.get(i), IsNull.notNullValue());
    436         }
    437     }
    438 
    439     // Utilities
    440 
    441     /**
    442      * Return an RttCapabilities structure with all features enabled and support for all
    443      * preambles and bandwidths. The purpose is to enable any request. The returned structure can
    444      * then be modified to disable specific features.
    445      */
    446     RttCapabilities getFullRttCapabilities() {
    447         RttCapabilities cap = new RttCapabilities();
    448 
    449         cap.rttOneSidedSupported = true;
    450         cap.rttFtmSupported = true;
    451         cap.lciSupported = true;
    452         cap.lcrSupported = true;
    453         cap.responderSupported = true; // unused
    454         cap.preambleSupport = RttPreamble.LEGACY | RttPreamble.HT | RttPreamble.VHT;
    455         cap.bwSupport =
    456                 RttBw.BW_5MHZ | RttBw.BW_10MHZ | RttBw.BW_20MHZ | RttBw.BW_40MHZ | RttBw.BW_80MHZ
    457                         | RttBw.BW_160MHZ;
    458         cap.mcVersion = 1; // unused
    459 
    460         return cap;
    461     }
    462 }
    463