1 /*
2  * Copyright (C) 2022 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 package com.android.server.wifi.hal;
18 
19 import static com.android.server.wifi.TestUtil.createCapabilityBitset;
20 
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyByte;
29 import static org.mockito.Mockito.doAnswer;
30 import static org.mockito.Mockito.doThrow;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.test.MockAnswerUtil;
35 import android.content.Context;
36 import android.content.res.Resources;
37 import android.hardware.wifi.V1_0.IWifiStaIface;
38 import android.hardware.wifi.V1_0.StaLinkLayerIfacePacketStats;
39 import android.hardware.wifi.V1_0.StaLinkLayerIfaceStats;
40 import android.hardware.wifi.V1_0.StaLinkLayerRadioStats;
41 import android.hardware.wifi.V1_0.StaLinkLayerStats;
42 import android.hardware.wifi.V1_0.StaRoamingCapabilities;
43 import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
44 import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
45 import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
46 import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
47 import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
48 import android.hardware.wifi.V1_0.WifiStatus;
49 import android.hardware.wifi.V1_0.WifiStatusCode;
50 import android.hardware.wifi.V1_3.WifiChannelStats;
51 import android.hardware.wifi.V1_5.StaLinkLayerIfaceContentionTimeStats;
52 import android.hardware.wifi.V1_5.StaPeerInfo;
53 import android.hardware.wifi.V1_5.StaRateStat;
54 import android.net.MacAddress;
55 import android.net.wifi.WifiManager;
56 import android.os.RemoteException;
57 
58 import com.android.server.wifi.SsidTranslator;
59 import com.android.server.wifi.WifiBaseTest;
60 import com.android.server.wifi.WifiLinkLayerStats;
61 import com.android.server.wifi.WifiLoggerHal;
62 import com.android.server.wifi.WifiNative;
63 import com.android.server.wifi.util.NativeUtil;
64 import com.android.wifi.resources.R;
65 
66 import org.junit.Before;
67 import org.junit.Test;
68 import org.mockito.Mock;
69 import org.mockito.MockitoAnnotations;
70 
71 import java.util.ArrayList;
72 import java.util.Arrays;
73 import java.util.BitSet;
74 import java.util.Collections;
75 import java.util.List;
76 import java.util.Random;
77 
78 public class WifiStaIfaceHidlImplTest extends WifiBaseTest {
79     private static final int[] TEST_FREQUENCIES = {2412, 2417, 2422, 2427, 2432, 2437};
80     private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("ee:33:a2:94:10:92");
81 
82     private WifiStaIfaceHidlImpl mDut;
83     private WifiStatus mWifiStatusSuccess;
84     private WifiStatus mWifiStatusFailure;
85     private WifiStatus mWifiStatusBusy;
86 
87     @Mock private IWifiStaIface mIWifiStaIfaceMock;
88     @Mock private android.hardware.wifi.V1_2.IWifiStaIface mIWifiStaIfaceMockV12;
89     @Mock private android.hardware.wifi.V1_3.IWifiStaIface mIWifiStaIfaceMockV13;
90     @Mock private android.hardware.wifi.V1_5.IWifiStaIface mIWifiStaIfaceMockV15;
91     @Mock private Context mContextMock;
92     @Mock private Resources mResourcesMock;
93     @Mock private SsidTranslator mSsidTranslatorMock;
94 
95     private class WifiStaIfaceHidlImplSpy extends WifiStaIfaceHidlImpl {
96         private int mVersion;
97 
WifiStaIfaceHidlImplSpy(int hidlVersion)98         WifiStaIfaceHidlImplSpy(int hidlVersion) {
99             super(mIWifiStaIfaceMock, mContextMock, mSsidTranslatorMock);
100             mVersion = hidlVersion;
101         }
102 
103         @Override
getWifiStaIfaceV1_2Mockable()104         protected android.hardware.wifi.V1_2.IWifiStaIface getWifiStaIfaceV1_2Mockable() {
105             return mVersion >= 2 ? mIWifiStaIfaceMockV12 : null;
106         }
107 
108         @Override
getWifiStaIfaceV1_3Mockable()109         protected android.hardware.wifi.V1_3.IWifiStaIface getWifiStaIfaceV1_3Mockable() {
110             return mVersion >= 3 ? mIWifiStaIfaceMockV13 : null;
111         }
112 
113         @Override
getWifiStaIfaceV1_5Mockable()114         protected android.hardware.wifi.V1_5.IWifiStaIface getWifiStaIfaceV1_5Mockable() {
115             return mVersion >= 5 ? mIWifiStaIfaceMockV15 : null;
116         }
117 
118         @Override
getWifiStaIfaceV1_6Mockable()119         protected android.hardware.wifi.V1_6.IWifiStaIface getWifiStaIfaceV1_6Mockable() {
120             return null;
121         }
122     }
123 
124     @Before
setUp()125     public void setUp() throws Exception {
126         MockitoAnnotations.initMocks(this);
127         when(mContextMock.getResources()).thenReturn(mResourcesMock);
128         mDut = new WifiStaIfaceHidlImplSpy(0);
129 
130         mWifiStatusSuccess = new WifiStatus();
131         mWifiStatusSuccess.code = WifiStatusCode.SUCCESS;
132         mWifiStatusFailure = new WifiStatus();
133         mWifiStatusFailure.code = WifiStatusCode.ERROR_UNKNOWN;
134         mWifiStatusFailure.description = "I don't even know what a Mock Turtle is.";
135         mWifiStatusBusy = new WifiStatus();
136         mWifiStatusBusy.code = WifiStatusCode.ERROR_BUSY;
137         mWifiStatusBusy.description = "Don't bother me, kid";
138     }
139 
140     /**
141      * Test translation to WifiManager.WIFI_FEATURE_*
142      */
143     @Test
testStaIfaceFeatureMaskTranslation()144     public void testStaIfaceFeatureMaskTranslation() {
145         int caps = (
146                 IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN
147                         | IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
148         );
149         BitSet expected = createCapabilityBitset(
150                 WifiManager.WIFI_FEATURE_SCANNER, WifiManager.WIFI_FEATURE_LINK_LAYER_STATS);
151         assertTrue(expected.equals(mDut.halToFrameworkStaIfaceCapability(caps)));
152     }
153 
154     /**
155      * Test that getFactoryMacAddress gets called when the HAL version is V1_3.
156      */
157     @Test
testGetStaFactoryMacWithHalV1_3()158     public void testGetStaFactoryMacWithHalV1_3() throws Exception {
159         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
160             public void answer(
161                     android.hardware.wifi.V1_3.IWifiStaIface.getFactoryMacAddressCallback cb)
162                     throws RemoteException {
163                 cb.onValues(mWifiStatusSuccess, MacAddress.BROADCAST_ADDRESS.toByteArray());
164             }
165         }).when(mIWifiStaIfaceMockV13).getFactoryMacAddress(any(
166                 android.hardware.wifi.V1_3.IWifiStaIface.getFactoryMacAddressCallback.class));
167         mDut = new WifiStaIfaceHidlImplSpy(3);
168         assertEquals(MacAddress.BROADCAST_ADDRESS, mDut.getFactoryMacAddress());
169     }
170 
171     /**
172      * Test that getLinkLayerStats_1_3 gets called when the HAL version is V1_3.
173      */
174     @Test
testLinkLayerStatsCorrectVersionWithHalV1_3()175     public void testLinkLayerStatsCorrectVersionWithHalV1_3() throws Exception {
176         mDut = new WifiStaIfaceHidlImplSpy(3);
177         mDut.getLinkLayerStats();
178         verify(mIWifiStaIfaceMockV13).getLinkLayerStats_1_3(any());
179     }
180 
181     /**
182      * Test getLinkLayerStats_1_5 gets called when the hal version is V1_5.
183      */
184     @Test
testLinkLayerStatsCorrectVersionWithHalV1_5()185     public void testLinkLayerStatsCorrectVersionWithHalV1_5() throws Exception {
186         mDut = new WifiStaIfaceHidlImplSpy(5);
187         mDut.getLinkLayerStats();
188         verify(mIWifiStaIfaceMockV15).getLinkLayerStats_1_5(any());
189     }
190 
191     /**
192      * Populate packet stats with non-negative random values.
193      */
randomizePacketStats(Random r, StaLinkLayerIfacePacketStats pstats)194     private static void randomizePacketStats(Random r, StaLinkLayerIfacePacketStats pstats) {
195         pstats.rxMpdu = r.nextLong() & 0xFFFFFFFFFFL; // more than 32 bits
196         pstats.txMpdu = r.nextLong() & 0xFFFFFFFFFFL;
197         pstats.lostMpdu = r.nextLong() & 0xFFFFFFFFFFL;
198         pstats.retries = r.nextLong() & 0xFFFFFFFFFFL;
199     }
200 
201     /**
202      * Populate contention time stats with non-negative random values.
203      */
randomizeContentionTimeStats(Random r, StaLinkLayerIfaceContentionTimeStats cstats)204     private static void randomizeContentionTimeStats(Random r,
205             StaLinkLayerIfaceContentionTimeStats cstats) {
206         cstats.contentionTimeMinInUsec = r.nextInt() & 0x7FFFFFFF;
207         cstats.contentionTimeMaxInUsec = r.nextInt() & 0x7FFFFFFF;
208         cstats.contentionTimeAvgInUsec = r.nextInt() & 0x7FFFFFFF;
209         cstats.contentionNumSamples = r.nextInt() & 0x7FFFFFFF;
210     }
211 
212     /**
213      * Populate radio stats with non-negative random values.
214      */
randomizeRadioStats(Random r, ArrayList<StaLinkLayerRadioStats> rstats)215     private static void randomizeRadioStats(Random r, ArrayList<StaLinkLayerRadioStats> rstats) {
216         StaLinkLayerRadioStats rstat = new StaLinkLayerRadioStats();
217         rstat.onTimeInMs = r.nextInt() & 0xFFFFFF;
218         rstat.txTimeInMs = r.nextInt() & 0xFFFFFF;
219         for (int i = 0; i < 4; i++) {
220             Integer v = r.nextInt() & 0xFFFFFF;
221             rstat.txTimeInMsPerLevel.add(v);
222         }
223         rstat.rxTimeInMs = r.nextInt() & 0xFFFFFF;
224         rstat.onTimeInMsForScan = r.nextInt() & 0xFFFFFF;
225         rstats.add(rstat);
226     }
227 
228     /**
229      * Populate radio stats V1_3 with non-negative random values.
230      */
randomizeRadioStats_1_3(Random r, android.hardware.wifi.V1_3.StaLinkLayerRadioStats rstat)231     private static void randomizeRadioStats_1_3(Random r,
232             android.hardware.wifi.V1_3.StaLinkLayerRadioStats rstat) {
233         rstat.V1_0.onTimeInMs = r.nextInt() & 0xFFFFFF;
234         rstat.V1_0.txTimeInMs = r.nextInt() & 0xFFFFFF;
235         for (int j = 0; j < 4; j++) {
236             Integer v = r.nextInt() & 0xFFFFFF;
237             rstat.V1_0.txTimeInMsPerLevel.add(v);
238         }
239         rstat.V1_0.rxTimeInMs = r.nextInt() & 0xFFFFFF;
240         rstat.V1_0.onTimeInMsForScan = r.nextInt() & 0xFFFFFF;
241         rstat.onTimeInMsForNanScan = r.nextInt() & 0xFFFFFF;
242         rstat.onTimeInMsForBgScan = r.nextInt() & 0xFFFFFF;
243         rstat.onTimeInMsForRoamScan = r.nextInt() & 0xFFFFFF;
244         rstat.onTimeInMsForPnoScan = r.nextInt() & 0xFFFFFF;
245         rstat.onTimeInMsForHs20Scan = r.nextInt() & 0xFFFFFF;
246         for (int k = 0; k < TEST_FREQUENCIES.length; k++) {
247             WifiChannelStats channelStats = new WifiChannelStats();
248             channelStats.channel.centerFreq = TEST_FREQUENCIES[k];
249             channelStats.onTimeInMs = r.nextInt() & 0xFFFFFF;
250             channelStats.ccaBusyTimeInMs = r.nextInt() & 0xFFFFFF;
251             rstat.channelStats.add(channelStats);
252         }
253     }
254 
255     /**
256      * Populate radio stats V1_5 with non-negative random values.
257      */
randomizeRadioStats_1_5(Random r, android.hardware.wifi.V1_5.StaLinkLayerRadioStats rstat)258     private static void randomizeRadioStats_1_5(Random r,
259             android.hardware.wifi.V1_5.StaLinkLayerRadioStats rstat) {
260         rstat.radioId = r.nextInt() & 0xFFFFFF;
261         randomizeRadioStats_1_3(r, rstat.V1_3);
262     }
263 
264     /**
265      * Populate peer info stats with non-negative random values.
266      */
randomizePeerInfoStats(Random r, ArrayList<StaPeerInfo> pstats)267     private static void randomizePeerInfoStats(Random r, ArrayList<StaPeerInfo> pstats) {
268         StaPeerInfo pstat = new StaPeerInfo();
269         pstat.staCount = 2;
270         pstat.chanUtil = 90;
271         pstat.rateStats = new ArrayList<StaRateStat>();
272         StaRateStat rateStat = new StaRateStat();
273         rateStat.rateInfo.preamble = r.nextInt() & 0x7FFFFFFF;
274         rateStat.rateInfo.nss = r.nextInt() & 0x7FFFFFFF;
275         rateStat.rateInfo.bw = r.nextInt() & 0x7FFFFFFF;
276         rateStat.rateInfo.rateMcsIdx = 9;
277         rateStat.rateInfo.bitRateInKbps = 101;
278         rateStat.txMpdu = r.nextInt() & 0x7FFFFFFF;
279         rateStat.rxMpdu = r.nextInt() & 0x7FFFFFFF;
280         rateStat.mpduLost = r.nextInt() & 0x7FFFFFFF;
281         rateStat.retries = r.nextInt() & 0x7FFFFFFF;
282         pstat.rateStats.add(rateStat);
283         pstats.add(pstat);
284     }
285 
verifyIfaceStats(StaLinkLayerIfaceStats iface, WifiLinkLayerStats wifiLinkLayerStats)286     private void verifyIfaceStats(StaLinkLayerIfaceStats iface,
287             WifiLinkLayerStats wifiLinkLayerStats) {
288         assertEquals(iface.beaconRx, wifiLinkLayerStats.links[0].beacon_rx);
289         assertEquals(iface.avgRssiMgmt, wifiLinkLayerStats.links[0].rssi_mgmt);
290 
291         assertEquals(iface.wmeBePktStats.rxMpdu, wifiLinkLayerStats.links[0].rxmpdu_be);
292         assertEquals(iface.wmeBePktStats.txMpdu, wifiLinkLayerStats.links[0].txmpdu_be);
293         assertEquals(iface.wmeBePktStats.lostMpdu, wifiLinkLayerStats.links[0].lostmpdu_be);
294         assertEquals(iface.wmeBePktStats.retries, wifiLinkLayerStats.links[0].retries_be);
295 
296         assertEquals(iface.wmeBkPktStats.rxMpdu, wifiLinkLayerStats.links[0].rxmpdu_bk);
297         assertEquals(iface.wmeBkPktStats.txMpdu, wifiLinkLayerStats.links[0].txmpdu_bk);
298         assertEquals(iface.wmeBkPktStats.lostMpdu, wifiLinkLayerStats.links[0].lostmpdu_bk);
299         assertEquals(iface.wmeBkPktStats.retries, wifiLinkLayerStats.links[0].retries_bk);
300 
301         assertEquals(iface.wmeViPktStats.rxMpdu, wifiLinkLayerStats.links[0].rxmpdu_vi);
302         assertEquals(iface.wmeViPktStats.txMpdu, wifiLinkLayerStats.links[0].txmpdu_vi);
303         assertEquals(iface.wmeViPktStats.lostMpdu, wifiLinkLayerStats.links[0].lostmpdu_vi);
304         assertEquals(iface.wmeViPktStats.retries, wifiLinkLayerStats.links[0].retries_vi);
305 
306         assertEquals(iface.wmeVoPktStats.rxMpdu, wifiLinkLayerStats.links[0].rxmpdu_vo);
307         assertEquals(iface.wmeVoPktStats.txMpdu, wifiLinkLayerStats.links[0].txmpdu_vo);
308         assertEquals(iface.wmeVoPktStats.lostMpdu, wifiLinkLayerStats.links[0].lostmpdu_vo);
309         assertEquals(iface.wmeVoPktStats.retries, wifiLinkLayerStats.links[0].retries_vo);
310     }
311 
verifyIfaceStats_1_5(android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface, WifiLinkLayerStats wifiLinkLayerStats)312     private void verifyIfaceStats_1_5(android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface,
313             WifiLinkLayerStats wifiLinkLayerStats) {
314         assertEquals(iface.wmeBeContentionTimeStats.contentionTimeMinInUsec,
315                 wifiLinkLayerStats.links[0].contentionTimeMinBeInUsec);
316         assertEquals(iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec,
317                 wifiLinkLayerStats.links[0].contentionTimeMaxBeInUsec);
318         assertEquals(iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec,
319                 wifiLinkLayerStats.links[0].contentionTimeAvgBeInUsec);
320         assertEquals(iface.wmeBeContentionTimeStats.contentionNumSamples,
321                 wifiLinkLayerStats.links[0].contentionNumSamplesBe);
322 
323         assertEquals(iface.wmeBkContentionTimeStats.contentionTimeMinInUsec,
324                 wifiLinkLayerStats.links[0].contentionTimeMinBkInUsec);
325         assertEquals(iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec,
326                 wifiLinkLayerStats.links[0].contentionTimeMaxBkInUsec);
327         assertEquals(iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec,
328                 wifiLinkLayerStats.links[0].contentionTimeAvgBkInUsec);
329         assertEquals(iface.wmeBkContentionTimeStats.contentionNumSamples,
330                 wifiLinkLayerStats.links[0].contentionNumSamplesBk);
331 
332         assertEquals(iface.wmeViContentionTimeStats.contentionTimeMinInUsec,
333                 wifiLinkLayerStats.links[0].contentionTimeMinViInUsec);
334         assertEquals(iface.wmeViContentionTimeStats.contentionTimeMaxInUsec,
335                 wifiLinkLayerStats.links[0].contentionTimeMaxViInUsec);
336         assertEquals(iface.wmeViContentionTimeStats.contentionTimeAvgInUsec,
337                 wifiLinkLayerStats.links[0].contentionTimeAvgViInUsec);
338         assertEquals(iface.wmeViContentionTimeStats.contentionNumSamples,
339                 wifiLinkLayerStats.links[0].contentionNumSamplesVi);
340 
341         assertEquals(iface.wmeVoContentionTimeStats.contentionTimeMinInUsec,
342                 wifiLinkLayerStats.links[0].contentionTimeMinVoInUsec);
343         assertEquals(iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec,
344                 wifiLinkLayerStats.links[0].contentionTimeMaxVoInUsec);
345         assertEquals(iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec,
346                 wifiLinkLayerStats.links[0].contentionTimeAvgVoInUsec);
347         assertEquals(iface.wmeVoContentionTimeStats.contentionNumSamples,
348                 wifiLinkLayerStats.links[0].contentionNumSamplesVo);
349 
350         for (int i = 0; i < iface.peers.size(); i++) {
351             assertEquals(iface.peers.get(i).staCount, wifiLinkLayerStats.links[0]
352                     .peerInfo[i].staCount);
353             assertEquals(iface.peers.get(i).chanUtil, wifiLinkLayerStats.links[0]
354                     .peerInfo[i].chanUtil);
355             for (int j = 0; j < iface.peers.get(i).rateStats.size(); j++) {
356                 assertEquals(iface.peers.get(i).rateStats.get(j).rateInfo.preamble,
357                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].preamble);
358                 assertEquals(iface.peers.get(i).rateStats.get(j).rateInfo.nss,
359                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].nss);
360                 assertEquals(iface.peers.get(i).rateStats.get(j).rateInfo.bw,
361                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].bw);
362                 assertEquals(iface.peers.get(i).rateStats.get(j).rateInfo.rateMcsIdx,
363                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].rateMcsIdx);
364                 assertEquals(iface.peers.get(i).rateStats.get(j).rateInfo.bitRateInKbps,
365                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].bitRateInKbps);
366                 assertEquals(iface.peers.get(i).rateStats.get(j).txMpdu,
367                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].txMpdu);
368                 assertEquals(iface.peers.get(i).rateStats.get(j).rxMpdu,
369                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].rxMpdu);
370                 assertEquals(iface.peers.get(i).rateStats.get(j).mpduLost,
371                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].mpduLost);
372                 assertEquals(iface.peers.get(i).rateStats.get(j).retries,
373                         wifiLinkLayerStats.links[0].peerInfo[i].rateStats[j].retries);
374             }
375         }
376     }
377 
verifyRadioStats(List<StaLinkLayerRadioStats> radios, WifiLinkLayerStats wifiLinkLayerStats)378     private void verifyRadioStats(List<StaLinkLayerRadioStats> radios,
379             WifiLinkLayerStats wifiLinkLayerStats) {
380         StaLinkLayerRadioStats radio = radios.get(0);
381         assertEquals(radio.onTimeInMs, wifiLinkLayerStats.on_time);
382         assertEquals(radio.txTimeInMs, wifiLinkLayerStats.tx_time);
383         assertEquals(radio.rxTimeInMs, wifiLinkLayerStats.rx_time);
384         assertEquals(radio.onTimeInMsForScan, wifiLinkLayerStats.on_time_scan);
385         assertEquals(radio.txTimeInMsPerLevel.size(),
386                 wifiLinkLayerStats.tx_time_per_level.length);
387         for (int i = 0; i < radio.txTimeInMsPerLevel.size(); i++) {
388             assertEquals((int) radio.txTimeInMsPerLevel.get(i),
389                     wifiLinkLayerStats.tx_time_per_level[i]);
390         }
391     }
392 
verifyRadioStats_1_3( android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio, WifiLinkLayerStats wifiLinkLayerStats)393     private void verifyRadioStats_1_3(
394             android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio,
395             WifiLinkLayerStats wifiLinkLayerStats) {
396         assertEquals(radio.V1_0.onTimeInMs, wifiLinkLayerStats.on_time);
397         assertEquals(radio.V1_0.txTimeInMs, wifiLinkLayerStats.tx_time);
398         assertEquals(radio.V1_0.rxTimeInMs, wifiLinkLayerStats.rx_time);
399         assertEquals(radio.V1_0.onTimeInMsForScan, wifiLinkLayerStats.on_time_scan);
400         assertEquals(radio.V1_0.txTimeInMsPerLevel.size(),
401                 wifiLinkLayerStats.tx_time_per_level.length);
402         for (int i = 0; i < radio.V1_0.txTimeInMsPerLevel.size(); i++) {
403             assertEquals((int) radio.V1_0.txTimeInMsPerLevel.get(i),
404                     wifiLinkLayerStats.tx_time_per_level[i]);
405         }
406         assertEquals(radio.onTimeInMsForNanScan, wifiLinkLayerStats.on_time_nan_scan);
407         assertEquals(radio.onTimeInMsForBgScan, wifiLinkLayerStats.on_time_background_scan);
408         assertEquals(radio.onTimeInMsForRoamScan, wifiLinkLayerStats.on_time_roam_scan);
409         assertEquals(radio.onTimeInMsForPnoScan, wifiLinkLayerStats.on_time_pno_scan);
410         assertEquals(radio.onTimeInMsForHs20Scan, wifiLinkLayerStats.on_time_hs20_scan);
411         assertEquals(radio.channelStats.size(),
412                 wifiLinkLayerStats.channelStatsMap.size());
413         for (int j = 0; j < radio.channelStats.size(); j++) {
414             WifiChannelStats channelStats = radio.channelStats.get(j);
415             WifiLinkLayerStats.ChannelStats retrievedChannelStats =
416                     wifiLinkLayerStats.channelStatsMap.get(channelStats.channel.centerFreq);
417             assertNotNull(retrievedChannelStats);
418             assertEquals(channelStats.channel.centerFreq, retrievedChannelStats.frequency);
419             assertEquals(channelStats.onTimeInMs, retrievedChannelStats.radioOnTimeMs);
420             assertEquals(channelStats.ccaBusyTimeInMs, retrievedChannelStats.ccaBusyTimeMs);
421         }
422     }
423 
verifyPerRadioStats(List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios, WifiLinkLayerStats wifiLinkLayerStats)424     private void verifyPerRadioStats(List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios,
425             WifiLinkLayerStats wifiLinkLayerStats) {
426         assertEquals(radios.size(),
427                 wifiLinkLayerStats.radioStats.length);
428         for (int i = 0; i < radios.size(); i++) {
429             android.hardware.wifi.V1_5.StaLinkLayerRadioStats radio = radios.get(i);
430             WifiLinkLayerStats.RadioStat radioStat = wifiLinkLayerStats.radioStats[i];
431             assertEquals(radio.radioId, radioStat.radio_id);
432             assertEquals(radio.V1_3.V1_0.onTimeInMs, radioStat.on_time);
433             assertEquals(radio.V1_3.V1_0.txTimeInMs, radioStat.tx_time);
434             assertEquals(radio.V1_3.V1_0.rxTimeInMs, radioStat.rx_time);
435             assertEquals(radio.V1_3.V1_0.onTimeInMsForScan, radioStat.on_time_scan);
436             assertEquals(radio.V1_3.onTimeInMsForNanScan, radioStat.on_time_nan_scan);
437             assertEquals(radio.V1_3.onTimeInMsForBgScan, radioStat.on_time_background_scan);
438             assertEquals(radio.V1_3.onTimeInMsForRoamScan, radioStat.on_time_roam_scan);
439             assertEquals(radio.V1_3.onTimeInMsForPnoScan, radioStat.on_time_pno_scan);
440             assertEquals(radio.V1_3.onTimeInMsForHs20Scan, radioStat.on_time_hs20_scan);
441 
442             assertEquals(radio.V1_3.channelStats.size(),
443                     radioStat.channelStatsMap.size());
444             for (int j = 0; j < radio.V1_3.channelStats.size(); j++) {
445                 WifiChannelStats channelStats = radio.V1_3.channelStats.get(j);
446                 WifiLinkLayerStats.ChannelStats retrievedChannelStats =
447                         radioStat.channelStatsMap.get(channelStats.channel.centerFreq);
448                 assertNotNull(retrievedChannelStats);
449                 assertEquals(channelStats.channel.centerFreq, retrievedChannelStats.frequency);
450                 assertEquals(channelStats.onTimeInMs, retrievedChannelStats.radioOnTimeMs);
451                 assertEquals(channelStats.ccaBusyTimeInMs, retrievedChannelStats.ccaBusyTimeMs);
452             }
453         }
454 
455     }
456 
verifyRadioStats_1_5( android.hardware.wifi.V1_5.StaLinkLayerRadioStats radio, WifiLinkLayerStats wifiLinkLayerStats)457     private void verifyRadioStats_1_5(
458             android.hardware.wifi.V1_5.StaLinkLayerRadioStats radio,
459             WifiLinkLayerStats wifiLinkLayerStats) {
460         verifyRadioStats_1_3(radio.V1_3, wifiLinkLayerStats);
461     }
462 
verifyTwoRadioStatsAggregation( android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio0, android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio1, WifiLinkLayerStats wifiLinkLayerStats)463     private void verifyTwoRadioStatsAggregation(
464             android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio0,
465             android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio1,
466             WifiLinkLayerStats wifiLinkLayerStats) {
467         assertEquals(radio0.V1_0.onTimeInMs + radio1.V1_0.onTimeInMs,
468                 wifiLinkLayerStats.on_time);
469         assertEquals(radio0.V1_0.txTimeInMs + radio1.V1_0.txTimeInMs,
470                 wifiLinkLayerStats.tx_time);
471         assertEquals(radio0.V1_0.rxTimeInMs + radio1.V1_0.rxTimeInMs,
472                 wifiLinkLayerStats.rx_time);
473         assertEquals(radio0.V1_0.onTimeInMsForScan + radio1.V1_0.onTimeInMsForScan,
474                 wifiLinkLayerStats.on_time_scan);
475         assertEquals(radio0.V1_0.txTimeInMsPerLevel.size(),
476                 radio1.V1_0.txTimeInMsPerLevel.size());
477         assertEquals(radio0.V1_0.txTimeInMsPerLevel.size(),
478                 wifiLinkLayerStats.tx_time_per_level.length);
479         for (int i = 0; i < radio0.V1_0.txTimeInMsPerLevel.size(); i++) {
480             assertEquals((int) radio0.V1_0.txTimeInMsPerLevel.get(i)
481                             + (int) radio1.V1_0.txTimeInMsPerLevel.get(i),
482                     wifiLinkLayerStats.tx_time_per_level[i]);
483         }
484         assertEquals(radio0.onTimeInMsForNanScan + radio1.onTimeInMsForNanScan,
485                 wifiLinkLayerStats.on_time_nan_scan);
486         assertEquals(radio0.onTimeInMsForBgScan + radio1.onTimeInMsForBgScan,
487                 wifiLinkLayerStats.on_time_background_scan);
488         assertEquals(radio0.onTimeInMsForRoamScan + radio1.onTimeInMsForRoamScan,
489                 wifiLinkLayerStats.on_time_roam_scan);
490         assertEquals(radio0.onTimeInMsForPnoScan + radio1.onTimeInMsForPnoScan,
491                 wifiLinkLayerStats.on_time_pno_scan);
492         assertEquals(radio0.onTimeInMsForHs20Scan + radio1.onTimeInMsForHs20Scan,
493                 wifiLinkLayerStats.on_time_hs20_scan);
494         assertEquals(radio0.channelStats.size(), radio1.channelStats.size());
495         assertEquals(radio0.channelStats.size(),
496                 wifiLinkLayerStats.channelStatsMap.size());
497         for (int j = 0; j < radio0.channelStats.size(); j++) {
498             WifiChannelStats radio0ChannelStats = radio0.channelStats.get(j);
499             WifiChannelStats radio1ChannelStats = radio1.channelStats.get(j);
500             WifiLinkLayerStats.ChannelStats retrievedChannelStats =
501                     wifiLinkLayerStats.channelStatsMap.get(radio0ChannelStats.channel.centerFreq);
502             assertNotNull(retrievedChannelStats);
503             assertEquals(radio0ChannelStats.channel.centerFreq, retrievedChannelStats.frequency);
504             assertEquals(radio1ChannelStats.channel.centerFreq, retrievedChannelStats.frequency);
505             assertEquals(radio0ChannelStats.onTimeInMs + radio1ChannelStats.onTimeInMs,
506                     retrievedChannelStats.radioOnTimeMs);
507             assertEquals(radio0ChannelStats.ccaBusyTimeInMs
508                     + radio1ChannelStats.ccaBusyTimeInMs, retrievedChannelStats.ccaBusyTimeMs);
509         }
510     }
511 
verifyTwoRadioStatsAggregation_1_3( List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios, WifiLinkLayerStats wifiLinkLayerStats)512     private void verifyTwoRadioStatsAggregation_1_3(
513             List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios,
514             WifiLinkLayerStats wifiLinkLayerStats) {
515         assertEquals(2, radios.size());
516         android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio0 = radios.get(0);
517         android.hardware.wifi.V1_3.StaLinkLayerRadioStats radio1 = radios.get(1);
518         verifyTwoRadioStatsAggregation(radio0, radio1, wifiLinkLayerStats);
519     }
520 
verifyTwoRadioStatsAggregation_1_5( List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios, WifiLinkLayerStats wifiLinkLayerStats)521     private void verifyTwoRadioStatsAggregation_1_5(
522             List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios,
523             WifiLinkLayerStats wifiLinkLayerStats) {
524         assertEquals(2, radios.size());
525         android.hardware.wifi.V1_5.StaLinkLayerRadioStats radio0 = radios.get(0);
526         android.hardware.wifi.V1_5.StaLinkLayerRadioStats radio1 = radios.get(1);
527         verifyTwoRadioStatsAggregation(radio0.V1_3, radio1.V1_3, wifiLinkLayerStats);
528     }
529 
530     /**
531      * Test that the link layer stats fields are populated correctly.
532      */
533     @Test
testLinkLayerStatsAssignment()534     public void testLinkLayerStatsAssignment() throws Exception {
535         Random r = new Random(1775968256);
536         StaLinkLayerStats stats = new StaLinkLayerStats();
537         randomizePacketStats(r, stats.iface.wmeBePktStats);
538         randomizePacketStats(r, stats.iface.wmeBkPktStats);
539         randomizePacketStats(r, stats.iface.wmeViPktStats);
540         randomizePacketStats(r, stats.iface.wmeVoPktStats);
541         randomizeRadioStats(r, stats.radios);
542         stats.timeStampInMs = r.nextLong() & 0xFFFFFFFFFFL;
543 
544         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats(stats);
545 
546         verifyIfaceStats(stats.iface, converted);
547         verifyRadioStats(stats.radios, converted);
548         assertEquals(stats.timeStampInMs, converted.timeStampInMs);
549         assertEquals(WifiLinkLayerStats.V1_0, converted.version);
550     }
551 
552     /**
553      * Test that the link layer stats V1_3 fields are populated correctly.
554      */
555     @Test
testLinkLayerStatsAssignment_1_3()556     public void testLinkLayerStatsAssignment_1_3() throws Exception {
557         Random r = new Random(1775968256);
558         android.hardware.wifi.V1_3.StaLinkLayerStats stats =
559                 new android.hardware.wifi.V1_3.StaLinkLayerStats();
560         randomizePacketStats(r, stats.iface.wmeBePktStats);
561         randomizePacketStats(r, stats.iface.wmeBkPktStats);
562         randomizePacketStats(r, stats.iface.wmeViPktStats);
563         randomizePacketStats(r, stats.iface.wmeVoPktStats);
564         android.hardware.wifi.V1_3.StaLinkLayerRadioStats rstat =
565                 new android.hardware.wifi.V1_3.StaLinkLayerRadioStats();
566         randomizeRadioStats_1_3(r, rstat);
567         stats.radios.add(rstat);
568         stats.timeStampInMs = r.nextLong() & 0xFFFFFFFFFFL;
569 
570         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_3(stats);
571 
572         verifyIfaceStats(stats.iface, converted);
573         verifyRadioStats_1_3(stats.radios.get(0), converted);
574         assertEquals(stats.timeStampInMs, converted.timeStampInMs);
575         assertEquals(WifiLinkLayerStats.V1_3, converted.version);
576         assertEquals(1, converted.numRadios);
577     }
578 
579     /**
580      * Test that the link layer stats V1_5 fields are populated correctly.
581      */
582     @Test
testLinkLayerStatsAssignment_1_5()583     public void testLinkLayerStatsAssignment_1_5() throws Exception {
584         Random r = new Random(1775968256);
585         android.hardware.wifi.V1_5.StaLinkLayerStats stats =
586                 new android.hardware.wifi.V1_5.StaLinkLayerStats();
587         randomizePacketStats(r, stats.iface.V1_0.wmeBePktStats);
588         randomizePacketStats(r, stats.iface.V1_0.wmeBkPktStats);
589         randomizePacketStats(r, stats.iface.V1_0.wmeViPktStats);
590         randomizePacketStats(r, stats.iface.V1_0.wmeVoPktStats);
591         android.hardware.wifi.V1_5.StaLinkLayerRadioStats rstat =
592                 new android.hardware.wifi.V1_5.StaLinkLayerRadioStats();
593         randomizeRadioStats_1_5(r, rstat);
594         stats.radios.add(rstat);
595         stats.timeStampInMs = r.nextLong() & 0xFFFFFFFFFFL;
596         randomizeContentionTimeStats(r, stats.iface.wmeBeContentionTimeStats);
597         randomizeContentionTimeStats(r, stats.iface.wmeBkContentionTimeStats);
598         randomizeContentionTimeStats(r, stats.iface.wmeViContentionTimeStats);
599         randomizeContentionTimeStats(r, stats.iface.wmeVoContentionTimeStats);
600         randomizePeerInfoStats(r, stats.iface.peers);
601 
602         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_5(stats);
603 
604         verifyIfaceStats(stats.iface.V1_0, converted);
605         verifyIfaceStats_1_5(stats.iface, converted);
606         verifyPerRadioStats(stats.radios, converted);
607         verifyRadioStats_1_5(stats.radios.get(0), converted);
608         assertEquals(stats.timeStampInMs, converted.timeStampInMs);
609         assertEquals(WifiLinkLayerStats.V1_5, converted.version);
610         assertEquals(1, converted.numRadios);
611     }
612 
613     /**
614      * Test that the link layer stats V1_3 fields are aggregated correctly for two radios.
615      */
616     @Test
testTwoRadioStatsAggregation_1_3()617     public void testTwoRadioStatsAggregation_1_3() throws Exception {
618         when(mResourcesMock.getBoolean(R.bool.config_wifiLinkLayerAllRadiosStatsAggregationEnabled))
619                 .thenReturn(true);
620         mDut = new WifiStaIfaceHidlImplSpy(0);
621         Random r = new Random(245786856);
622         android.hardware.wifi.V1_3.StaLinkLayerStats stats =
623                 new android.hardware.wifi.V1_3.StaLinkLayerStats();
624         // Fill stats in two radios
625         for (int i = 0; i < 2; i++) {
626             android.hardware.wifi.V1_3.StaLinkLayerRadioStats rstat =
627                     new android.hardware.wifi.V1_3.StaLinkLayerRadioStats();
628             randomizeRadioStats_1_3(r, rstat);
629             stats.radios.add(rstat);
630         }
631 
632         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_3(stats);
633         verifyTwoRadioStatsAggregation_1_3(stats.radios, converted);
634         assertEquals(2, converted.numRadios);
635     }
636 
637     /**
638      * Test that the link layer stats V1_3 fields are not aggregated on setting
639      * config_wifiLinkLayerAllRadiosStatsAggregationEnabled to false (default value).
640      */
641     @Test
testRadioStatsAggregationDisabled_1_3()642     public void testRadioStatsAggregationDisabled_1_3() throws Exception {
643         Random r = new Random(245786856);
644         android.hardware.wifi.V1_3.StaLinkLayerStats stats =
645                 new android.hardware.wifi.V1_3.StaLinkLayerStats();
646         // Fill stats in two radios
647         for (int i = 0; i < 2; i++) {
648             android.hardware.wifi.V1_3.StaLinkLayerRadioStats rstat =
649                     new android.hardware.wifi.V1_3.StaLinkLayerRadioStats();
650             randomizeRadioStats_1_3(r, rstat);
651             stats.radios.add(rstat);
652         }
653 
654         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_3(stats);
655         verifyRadioStats_1_3(stats.radios.get(0), converted);
656         assertEquals(1, converted.numRadios);
657     }
658 
659     /**
660      * Test that the link layer stats V1_5 fields are aggregated correctly for two radios.
661      */
662     @Test
testTwoRadioStatsAggregation_1_5()663     public void testTwoRadioStatsAggregation_1_5() throws Exception {
664         when(mResourcesMock.getBoolean(R.bool.config_wifiLinkLayerAllRadiosStatsAggregationEnabled))
665                 .thenReturn(true);
666         mDut = new WifiStaIfaceHidlImplSpy(0);
667         Random r = new Random(245786856);
668         android.hardware.wifi.V1_5.StaLinkLayerStats stats =
669                 new android.hardware.wifi.V1_5.StaLinkLayerStats();
670         // Fill stats in two radios
671         for (int i = 0; i < 2; i++) {
672             android.hardware.wifi.V1_5.StaLinkLayerRadioStats rstat =
673                     new android.hardware.wifi.V1_5.StaLinkLayerRadioStats();
674             randomizeRadioStats_1_5(r, rstat);
675             stats.radios.add(rstat);
676         }
677 
678         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_5(stats);
679         verifyPerRadioStats(stats.radios, converted);
680         verifyTwoRadioStatsAggregation_1_5(stats.radios, converted);
681         assertEquals(2, converted.numRadios);
682     }
683 
684     /**
685      * Test that the link layer stats V1_5 fields are not aggregated on setting
686      * config_wifiLinkLayerAllRadiosStatsAggregationEnabled to false (default value).
687      */
688     @Test
testRadioStatsAggregationDisabled_1_5()689     public void testRadioStatsAggregationDisabled_1_5() throws Exception {
690         Random r = new Random(245786856);
691         android.hardware.wifi.V1_5.StaLinkLayerStats stats =
692                 new android.hardware.wifi.V1_5.StaLinkLayerStats();
693         // Fill stats in two radios
694         for (int i = 0; i < 2; i++) {
695             android.hardware.wifi.V1_5.StaLinkLayerRadioStats rstat =
696                     new android.hardware.wifi.V1_5.StaLinkLayerRadioStats();
697             randomizeRadioStats_1_5(r, rstat);
698             stats.radios.add(rstat);
699         }
700 
701         WifiLinkLayerStats converted = mDut.frameworkFromHalLinkLayerStats_1_5(stats);
702         verifyPerRadioStats(stats.radios, converted);
703         verifyRadioStats_1_5(stats.radios.get(0), converted);
704         assertEquals(1, converted.numRadios);
705     }
706 
707     /**
708      * Tests the retrieval of tx packet fates.
709      */
710     @Test
testGetTxPktFates()711     public void testGetTxPktFates() throws Exception {
712         byte[] frameContentBytes = new byte[30];
713         new Random().nextBytes(frameContentBytes);
714         WifiDebugTxPacketFateReport fateReport = new WifiDebugTxPacketFateReport();
715         fateReport.fate = WifiDebugTxPacketFate.DRV_QUEUED;
716         fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
717         fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.ETHERNET_II;
718         fateReport.frameInfo.frameContent.addAll(
719                 NativeUtil.byteArrayToArrayList(frameContentBytes));
720 
721         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
722             public void answer(IWifiStaIface.getDebugTxPacketFatesCallback cb) {
723                 cb.onValues(mWifiStatusSuccess, new ArrayList<>(Arrays.asList(fateReport)));
724             }
725         }).when(mIWifiStaIfaceMock)
726                 .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
727 
728         List<WifiNative.TxFateReport> retrievedFates = mDut.getDebugTxPacketFates();
729         assertEquals(1, retrievedFates.size());
730         WifiNative.TxFateReport retrievedFate = retrievedFates.get(0);
731         verify(mIWifiStaIfaceMock)
732                 .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
733         assertEquals(WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED, retrievedFate.mFate);
734         assertEquals(fateReport.frameInfo.driverTimestampUsec, retrievedFate.mDriverTimestampUSec);
735         assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, retrievedFate.mFrameType);
736         assertArrayEquals(frameContentBytes, retrievedFate.mFrameBytes);
737     }
738 
739     /**
740      * Tests the retrieval of tx packet fates when the number of fates retrieved exceeds the
741      * maximum number of packet fates fetched ({@link WifiLoggerHal#MAX_FATE_LOG_LEN}).
742      */
743     @Test
testGetTxPktFatesExceedsInputArrayLength()744     public void testGetTxPktFatesExceedsInputArrayLength() throws Exception {
745         byte[] frameContentBytes = new byte[30];
746         new Random().nextBytes(frameContentBytes);
747         WifiDebugTxPacketFateReport fateReport = new WifiDebugTxPacketFateReport();
748         fateReport.fate = WifiDebugTxPacketFate.FW_DROP_OTHER;
749         fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
750         fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.MGMT_80211;
751         fateReport.frameInfo.frameContent.addAll(
752                 NativeUtil.byteArrayToArrayList(frameContentBytes));
753 
754         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
755             public void answer(IWifiStaIface.getDebugTxPacketFatesCallback cb) {
756                 cb.onValues(mWifiStatusSuccess, new ArrayList<>(
757                         // create twice as many as the max size
758                         Collections.nCopies(WifiLoggerHal.MAX_FATE_LOG_LEN * 2, fateReport)));
759             }
760         }).when(mIWifiStaIfaceMock)
761                 .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
762 
763         List<WifiNative.TxFateReport> retrievedFates = mDut.getDebugTxPacketFates();
764         // assert that at most WifiLoggerHal.MAX_FATE_LOG_LEN is retrieved
765         assertEquals(WifiLoggerHal.MAX_FATE_LOG_LEN, retrievedFates.size());
766         WifiNative.TxFateReport retrievedFate = retrievedFates.get(0);
767         verify(mIWifiStaIfaceMock)
768                 .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
769         assertEquals(WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER, retrievedFate.mFate);
770         assertEquals(fateReport.frameInfo.driverTimestampUsec, retrievedFate.mDriverTimestampUSec);
771         assertEquals(WifiLoggerHal.FRAME_TYPE_80211_MGMT, retrievedFate.mFrameType);
772         assertArrayEquals(frameContentBytes, retrievedFate.mFrameBytes);
773     }
774 
775     /**
776      * Tests the retrieval of rx packet fates.
777      */
778     @Test
testGetRxPktFates()779     public void testGetRxPktFates() throws Exception {
780         byte[] frameContentBytes = new byte[30];
781         new Random().nextBytes(frameContentBytes);
782         WifiDebugRxPacketFateReport fateReport = new WifiDebugRxPacketFateReport();
783         fateReport.fate = WifiDebugRxPacketFate.SUCCESS;
784         fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
785         fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.ETHERNET_II;
786         fateReport.frameInfo.frameContent.addAll(
787                 NativeUtil.byteArrayToArrayList(frameContentBytes));
788 
789         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
790             public void answer(IWifiStaIface.getDebugRxPacketFatesCallback cb) {
791                 cb.onValues(mWifiStatusSuccess, new ArrayList<>(Arrays.asList(fateReport)));
792             }
793         }).when(mIWifiStaIfaceMock)
794                 .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
795 
796         List<WifiNative.RxFateReport> retrievedFates = mDut.getDebugRxPacketFates();
797         assertEquals(1, retrievedFates.size());
798         WifiNative.RxFateReport retrievedFate = retrievedFates.get(0);
799         verify(mIWifiStaIfaceMock)
800                 .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
801         assertEquals(WifiLoggerHal.RX_PKT_FATE_SUCCESS, retrievedFate.mFate);
802         assertEquals(fateReport.frameInfo.driverTimestampUsec, retrievedFate.mDriverTimestampUSec);
803         assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, retrievedFate.mFrameType);
804         assertArrayEquals(frameContentBytes, retrievedFate.mFrameBytes);
805     }
806 
807     /**
808      * Tests the retrieval of rx packet fates when the number of fates retrieved exceeds the
809      * maximum number of packet fates fetched ({@link WifiLoggerHal#MAX_FATE_LOG_LEN}).
810      */
811     @Test
testGetRxPktFatesExceedsInputArrayLength()812     public void testGetRxPktFatesExceedsInputArrayLength() throws Exception {
813         byte[] frameContentBytes = new byte[30];
814         new Random().nextBytes(frameContentBytes);
815         WifiDebugRxPacketFateReport fateReport = new WifiDebugRxPacketFateReport();
816         fateReport.fate = WifiDebugRxPacketFate.FW_DROP_FILTER;
817         fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
818         fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.MGMT_80211;
819         fateReport.frameInfo.frameContent.addAll(
820                 NativeUtil.byteArrayToArrayList(frameContentBytes));
821 
822         doAnswer(new MockAnswerUtil.AnswerWithArguments() {
823             public void answer(IWifiStaIface.getDebugRxPacketFatesCallback cb) {
824                 cb.onValues(mWifiStatusSuccess, new ArrayList<>(
825                         // create twice as many as the max size
826                         Collections.nCopies(WifiLoggerHal.MAX_FATE_LOG_LEN * 2, fateReport)));
827             }
828         }).when(mIWifiStaIfaceMock)
829                 .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
830 
831         List<WifiNative.RxFateReport> retrievedFates = mDut.getDebugRxPacketFates();
832         assertEquals(WifiLoggerHal.MAX_FATE_LOG_LEN, retrievedFates.size());
833         verify(mIWifiStaIfaceMock)
834                 .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
835         WifiNative.RxFateReport retrievedFate = retrievedFates.get(0);
836         assertEquals(WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER, retrievedFate.mFate);
837         assertEquals(fateReport.frameInfo.driverTimestampUsec, retrievedFate.mDriverTimestampUSec);
838         assertEquals(WifiLoggerHal.FRAME_TYPE_80211_MGMT, retrievedFate.mFrameType);
839         assertArrayEquals(frameContentBytes, retrievedFate.mFrameBytes);
840     }
841 
842     /**
843      * Helper class for mocking the getRoamingCapabilities callback.
844      */
845     private class GetRoamingCapabilitiesAnswer extends MockAnswerUtil.AnswerWithArguments {
846         private final WifiStatus mStatus;
847         private final StaRoamingCapabilities mCaps;
848 
GetRoamingCapabilitiesAnswer(WifiStatus status, StaRoamingCapabilities caps)849         GetRoamingCapabilitiesAnswer(WifiStatus status, StaRoamingCapabilities caps) {
850             mStatus = status;
851             mCaps = caps;
852         }
853 
answer(IWifiStaIface.getRoamingCapabilitiesCallback cb)854         public void answer(IWifiStaIface.getRoamingCapabilitiesCallback cb) {
855             cb.onValues(mStatus, mCaps);
856         }
857     }
858 
859     /**
860      * Tests the retrieval of firmware roaming capabilities.
861      */
862     @Test
testFirmwareRoamingCapabilityRetrieval()863     public void testFirmwareRoamingCapabilityRetrieval() throws Exception {
864         for (int i = 0; i < 4; i++) {
865             int blocklistSize = i + 10;
866             int allowlistSize = i * 3;
867             StaRoamingCapabilities caps = new StaRoamingCapabilities();
868             caps.maxBlacklistSize = blocklistSize;
869             caps.maxWhitelistSize = allowlistSize;
870             doAnswer(new GetRoamingCapabilitiesAnswer(mWifiStatusSuccess, caps))
871                     .when(mIWifiStaIfaceMock).getRoamingCapabilities(
872                             any(IWifiStaIface.getRoamingCapabilitiesCallback.class));
873             WifiNative.RoamingCapabilities roamCap = mDut.getRoamingCapabilities();
874             assertNotNull(roamCap);
875             assertEquals(blocklistSize, roamCap.maxBlocklistSize);
876             assertEquals(allowlistSize, roamCap.maxAllowlistSize);
877         }
878     }
879 
880     /**
881      * Tests the unsuccessful retrieval of firmware roaming capabilities.
882      */
883     @Test
testUnsuccessfulFirmwareRoamingCapabilityRetrieval()884     public void testUnsuccessfulFirmwareRoamingCapabilityRetrieval() throws Exception {
885         StaRoamingCapabilities caps = new StaRoamingCapabilities();
886         caps.maxBlacklistSize = 43;
887         caps.maxWhitelistSize = 18;
888 
889         // HAL returns a failure status
890         doAnswer(new GetRoamingCapabilitiesAnswer(mWifiStatusFailure, null))
891                 .when(mIWifiStaIfaceMock).getRoamingCapabilities(
892                         any(IWifiStaIface.getRoamingCapabilitiesCallback.class));
893         assertNull(mDut.getRoamingCapabilities());
894 
895         // HAL returns failure status, but supplies caps anyway
896         doAnswer(new GetRoamingCapabilitiesAnswer(mWifiStatusFailure, caps))
897                 .when(mIWifiStaIfaceMock).getRoamingCapabilities(
898                         any(IWifiStaIface.getRoamingCapabilitiesCallback.class));
899         assertNull(mDut.getRoamingCapabilities());
900 
901         // lost connection
902         doThrow(new RemoteException())
903                 .when(mIWifiStaIfaceMock).getRoamingCapabilities(
904                         any(IWifiStaIface.getRoamingCapabilitiesCallback.class));
905         assertNull(mDut.getRoamingCapabilities());
906     }
907 
908     /**
909      * Tests enableFirmwareRoaming failure case due to an invalid argument.
910      */
911     @Test
testEnableFirmwareRoamingFailureInvalidArgument()912     public void testEnableFirmwareRoamingFailureInvalidArgument() throws Exception {
913         final int badState = WifiNative.DISABLE_FIRMWARE_ROAMING
914                 + WifiNative.ENABLE_FIRMWARE_ROAMING + 1;
915         assertEquals(WifiNative.SET_FIRMWARE_ROAMING_FAILURE, mDut.setRoamingState(badState));
916     }
917 
918     /**
919      * Tests that setRoamingState can handle a remote exception.
920      */
921     @Test
testEnableFirmwareRoamingException()922     public void testEnableFirmwareRoamingException() throws Exception {
923         doThrow(new RemoteException()).when(mIWifiStaIfaceMock).setRoamingState(anyByte());
924         assertEquals(WifiNative.SET_FIRMWARE_ROAMING_FAILURE,
925                 mDut.setRoamingState(WifiNative.ENABLE_FIRMWARE_ROAMING));
926     }
927 
928     /**
929      * Verifies setMacAddress() success.
930      */
931     @Test
testSetMacAddressSuccess()932     public void testSetMacAddressSuccess() throws Exception {
933         // Expose the 1.2 IWifiStaIface.
934         mDut = new WifiStaIfaceHidlImplSpy(2);
935         byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
936         when(mIWifiStaIfaceMockV12.setMacAddress(macByteArray)).thenReturn(mWifiStatusSuccess);
937 
938         assertTrue(mDut.setMacAddress(TEST_MAC_ADDRESS));
939         verify(mIWifiStaIfaceMockV12).setMacAddress(macByteArray);
940     }
941 
942     /**
943      * Verifies that setMacAddress() can handle a failure status.
944      */
945     @Test
testSetMacAddressFailDueToStatusFailure()946     public void testSetMacAddressFailDueToStatusFailure() throws Exception {
947         // Expose the 1.2 IWifiStaIface.
948         mDut = new WifiStaIfaceHidlImplSpy(2);
949         byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
950         when(mIWifiStaIfaceMockV12.setMacAddress(macByteArray)).thenReturn(mWifiStatusFailure);
951 
952         assertFalse(mDut.setMacAddress(TEST_MAC_ADDRESS));
953         verify(mIWifiStaIfaceMockV12).setMacAddress(macByteArray);
954     }
955 
956     /**
957      * Verifies that setMacAddress() can handle a RemoteException.
958      */
959     @Test
testSetMacAddressFailDueToRemoteException()960     public void testSetMacAddressFailDueToRemoteException() throws Exception {
961         // Expose the 1.2 IWifiStaIface.
962         mDut = new WifiStaIfaceHidlImplSpy(2);
963         byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
964         doThrow(new RemoteException()).when(mIWifiStaIfaceMockV12).setMacAddress(macByteArray);
965 
966         assertFalse(mDut.setMacAddress(TEST_MAC_ADDRESS));
967         verify(mIWifiStaIfaceMockV12).setMacAddress(macByteArray);
968     }
969 }
970