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
17package com.android.server.wifi;
18
19import static org.junit.Assert.assertArrayEquals;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertNotEquals;
23import static org.junit.Assert.assertNotNull;
24import static org.junit.Assert.assertNull;
25import static org.junit.Assert.assertTrue;
26import static org.mockito.Mockito.any;
27import static org.mockito.Mockito.anyBoolean;
28import static org.mockito.Mockito.anyInt;
29import static org.mockito.Mockito.anyObject;
30import static org.mockito.Mockito.anyShort;
31import static org.mockito.Mockito.doAnswer;
32import static org.mockito.Mockito.doNothing;
33import static org.mockito.Mockito.doThrow;
34import static org.mockito.Mockito.eq;
35import static org.mockito.Mockito.mock;
36import static org.mockito.Mockito.never;
37import static org.mockito.Mockito.reset;
38import static org.mockito.Mockito.spy;
39import static org.mockito.Mockito.times;
40import static org.mockito.Mockito.verify;
41import static org.mockito.Mockito.verifyNoMoreInteractions;
42import static org.mockito.Mockito.when;
43
44import android.app.test.MockAnswerUtil.AnswerWithArguments;
45import android.hardware.wifi.V1_0.IWifiApIface;
46import android.hardware.wifi.V1_0.IWifiChip;
47import android.hardware.wifi.V1_0.IWifiChipEventCallback;
48import android.hardware.wifi.V1_0.IWifiIface;
49import android.hardware.wifi.V1_0.IWifiRttController;
50import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
51import android.hardware.wifi.V1_0.IWifiStaIface;
52import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
53import android.hardware.wifi.V1_0.IfaceType;
54import android.hardware.wifi.V1_0.RttBw;
55import android.hardware.wifi.V1_0.RttCapabilities;
56import android.hardware.wifi.V1_0.RttConfig;
57import android.hardware.wifi.V1_0.RttPreamble;
58import android.hardware.wifi.V1_0.StaApfPacketFilterCapabilities;
59import android.hardware.wifi.V1_0.StaBackgroundScanCapabilities;
60import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
61import android.hardware.wifi.V1_0.StaLinkLayerIfacePacketStats;
62import android.hardware.wifi.V1_0.StaLinkLayerRadioStats;
63import android.hardware.wifi.V1_0.StaLinkLayerStats;
64import android.hardware.wifi.V1_0.StaScanData;
65import android.hardware.wifi.V1_0.StaScanDataFlagMask;
66import android.hardware.wifi.V1_0.StaScanResult;
67import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
68import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
69import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
70import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
71import android.hardware.wifi.V1_0.WifiDebugRingBufferVerboseLevel;
72import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
73import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
74import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
75import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
76import android.hardware.wifi.V1_0.WifiInformationElement;
77import android.hardware.wifi.V1_0.WifiStatus;
78import android.hardware.wifi.V1_0.WifiStatusCode;
79import android.hardware.wifi.V1_2.IWifiChipEventCallback.IfaceInfo;
80import android.hardware.wifi.V1_2.IWifiChipEventCallback.RadioModeInfo;
81import android.net.KeepalivePacketData;
82import android.net.MacAddress;
83import android.net.apf.ApfCapabilities;
84import android.net.wifi.RttManager;
85import android.net.wifi.ScanResult;
86import android.net.wifi.WifiManager;
87import android.net.wifi.WifiScanner;
88import android.net.wifi.WifiSsid;
89import android.net.wifi.WifiWakeReasonAndCounts;
90import android.os.Looper;
91import android.os.RemoteException;
92import android.os.test.TestLooper;
93import android.system.OsConstants;
94import android.util.Pair;
95
96import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
97import com.android.server.wifi.util.NativeUtil;
98
99import org.junit.Before;
100import org.junit.Test;
101import org.mockito.ArgumentCaptor;
102import org.mockito.Mock;
103import org.mockito.MockitoAnnotations;
104import org.mockito.stubbing.Answer;
105
106import java.net.InetAddress;
107import java.util.ArrayList;
108import java.util.Arrays;
109import java.util.HashSet;
110import java.util.List;
111import java.util.Random;
112import java.util.Set;
113
114/**
115 * Unit tests for {@link com.android.server.wifi.WifiVendorHal}.
116 */
117public class WifiVendorHalTest {
118
119    private static final String TEST_IFACE_NAME = "wlan0";
120    private static final String TEST_IFACE_NAME_1 = "wlan1";
121    private static final MacAddress TEST_MAC_ADDRESS = MacAddress.fromString("ee:33:a2:94:10:92");
122
123    WifiVendorHal mWifiVendorHal;
124    private WifiStatus mWifiStatusSuccess;
125    private WifiStatus mWifiStatusFailure;
126    WifiLog mWifiLog;
127    @Mock
128    private HalDeviceManager mHalDeviceManager;
129    @Mock
130    private TestLooper mLooper;
131    @Mock
132    private WifiVendorHal.HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
133    @Mock
134    private IWifiApIface mIWifiApIface;
135    @Mock
136    private IWifiChip mIWifiChip;
137    @Mock
138    private android.hardware.wifi.V1_1.IWifiChip mIWifiChipV11;
139    @Mock
140    private android.hardware.wifi.V1_2.IWifiChip mIWifiChipV12;
141    @Mock
142    private IWifiStaIface mIWifiStaIface;
143    @Mock
144    private android.hardware.wifi.V1_2.IWifiStaIface mIWifiStaIfaceV12;
145    @Mock
146    private IWifiRttController mIWifiRttController;
147    private IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
148    private IWifiChipEventCallback mIWifiChipEventCallback;
149    private android.hardware.wifi.V1_2.IWifiChipEventCallback mIWifiChipEventCallbackV12;
150    @Mock
151    private WifiNative.VendorHalDeathEventHandler mVendorHalDeathHandler;
152    @Mock
153    private WifiNative.VendorHalRadioModeChangeEventHandler mVendorHalRadioModeChangeHandler;
154
155    /**
156     * Spy used to return the V1_1 IWifiChip mock object to simulate the 1.1 HAL running on the
157     * device.
158     */
159    private class WifiVendorHalSpyV1_1 extends WifiVendorHal {
160        WifiVendorHalSpyV1_1(HalDeviceManager halDeviceManager, Looper looper) {
161            super(halDeviceManager, looper);
162        }
163
164        @Override
165        protected android.hardware.wifi.V1_1.IWifiChip getWifiChipForV1_1Mockable() {
166            return mIWifiChipV11;
167        }
168
169        @Override
170        protected android.hardware.wifi.V1_2.IWifiChip getWifiChipForV1_2Mockable() {
171            return null;
172        }
173
174        @Override
175        protected android.hardware.wifi.V1_2.IWifiStaIface getWifiStaIfaceForV1_2Mockable(
176                String ifaceName) {
177            return null;
178        }
179    }
180
181    /**
182     * Spy used to return the V1_2 IWifiChip and IWifiStaIface mock objects to simulate
183     * the 1.2 HAL running on the device.
184     */
185    private class WifiVendorHalSpyV1_2 extends WifiVendorHal {
186        WifiVendorHalSpyV1_2(HalDeviceManager halDeviceManager, Looper looper) {
187            super(halDeviceManager, looper);
188        }
189
190        @Override
191        protected android.hardware.wifi.V1_1.IWifiChip getWifiChipForV1_1Mockable() {
192            return null;
193        }
194
195        @Override
196        protected android.hardware.wifi.V1_2.IWifiChip getWifiChipForV1_2Mockable() {
197            return mIWifiChipV12;
198        }
199
200        @Override
201        protected android.hardware.wifi.V1_2.IWifiStaIface getWifiStaIfaceForV1_2Mockable(
202                String ifaceName) {
203            return mIWifiStaIfaceV12;
204        }
205    }
206
207    /**
208     * Identity function to supply a type to its argument, which is a lambda
209     */
210    static Answer<WifiStatus> answerWifiStatus(Answer<WifiStatus> statusLambda) {
211        return (statusLambda);
212    }
213
214    /**
215     * Sets up for unit test
216     */
217    @Before
218    public void setUp() throws Exception {
219        MockitoAnnotations.initMocks(this);
220        mWifiLog = new FakeWifiLog();
221        mLooper = new TestLooper();
222        mWifiStatusSuccess = new WifiStatus();
223        mWifiStatusSuccess.code = WifiStatusCode.SUCCESS;
224        mWifiStatusFailure = new WifiStatus();
225        mWifiStatusFailure.code = WifiStatusCode.ERROR_UNKNOWN;
226        mWifiStatusFailure.description = "I don't even know what a Mock Turtle is.";
227        when(mIWifiStaIface.enableLinkLayerStatsCollection(false)).thenReturn(mWifiStatusSuccess);
228
229        // Setup the HalDeviceManager mock's start/stop behaviour. This can be overridden in
230        // individual tests, if needed.
231        doAnswer(new AnswerWithArguments() {
232            public boolean answer() {
233                when(mHalDeviceManager.isReady()).thenReturn(true);
234                when(mHalDeviceManager.isStarted()).thenReturn(true);
235                mHalDeviceManagerStatusCallbacks.onStatusChanged();
236                return true;
237            }
238        }).when(mHalDeviceManager).start();
239
240        doAnswer(new AnswerWithArguments() {
241            public void answer() {
242                when(mHalDeviceManager.isReady()).thenReturn(true);
243                when(mHalDeviceManager.isStarted()).thenReturn(false);
244                mHalDeviceManagerStatusCallbacks.onStatusChanged();
245            }
246        }).when(mHalDeviceManager).stop();
247        when(mHalDeviceManager.createStaIface(anyBoolean(), any(), eq(null)))
248                .thenReturn(mIWifiStaIface);
249        when(mHalDeviceManager.createApIface(any(), eq(null)))
250                .thenReturn(mIWifiApIface);
251        when(mHalDeviceManager.removeIface(any())).thenReturn(true);
252        when(mHalDeviceManager.getChip(any(IWifiIface.class)))
253                .thenReturn(mIWifiChip);
254        when(mHalDeviceManager.createRttController()).thenReturn(mIWifiRttController);
255        when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
256                .thenReturn(mWifiStatusSuccess);
257        mIWifiStaIfaceEventCallback = null;
258        when(mIWifiStaIface.registerEventCallback(any(IWifiStaIfaceEventCallback.class)))
259                .thenAnswer(answerWifiStatus((invocation) -> {
260                    Object[] args = invocation.getArguments();
261                    mIWifiStaIfaceEventCallback = (IWifiStaIfaceEventCallback) args[0];
262                    return (mWifiStatusSuccess);
263                }));
264        when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
265                .thenAnswer(answerWifiStatus((invocation) -> {
266                    Object[] args = invocation.getArguments();
267                    mIWifiChipEventCallback = (IWifiChipEventCallback) args[0];
268                    return (mWifiStatusSuccess);
269                }));
270        when(mIWifiChipV12.registerEventCallback_1_2(
271                any(android.hardware.wifi.V1_2.IWifiChipEventCallback.class)))
272                .thenAnswer(answerWifiStatus((invocation) -> {
273                    Object[] args = invocation.getArguments();
274                    mIWifiChipEventCallbackV12 =
275                            (android.hardware.wifi.V1_2.IWifiChipEventCallback) args[0];
276                    return (mWifiStatusSuccess);
277                }));
278
279        when(mIWifiRttController.registerEventCallback(any(IWifiRttControllerEventCallback.class)))
280                .thenReturn(mWifiStatusSuccess);
281
282        doAnswer(new AnswerWithArguments() {
283            public void answer(IWifiIface.getNameCallback cb)
284                    throws RemoteException {
285                cb.onValues(mWifiStatusSuccess, TEST_IFACE_NAME);
286            }
287        }).when(mIWifiStaIface).getName(any(IWifiIface.getNameCallback.class));
288        doAnswer(new AnswerWithArguments() {
289            public void answer(IWifiIface.getNameCallback cb)
290                    throws RemoteException {
291                cb.onValues(mWifiStatusSuccess, TEST_IFACE_NAME);
292            }
293        }).when(mIWifiApIface).getName(any(IWifiIface.getNameCallback.class));
294
295        // Create the vendor HAL object under test.
296        mWifiVendorHal = new WifiVendorHal(mHalDeviceManager, mLooper.getLooper());
297
298        // Initialize the vendor HAL to capture the registered callback.
299        mWifiVendorHal.initialize(mVendorHalDeathHandler);
300        ArgumentCaptor<WifiVendorHal.HalDeviceManagerStatusListener> hdmCallbackCaptor =
301                ArgumentCaptor.forClass(WifiVendorHal.HalDeviceManagerStatusListener.class);
302        verify(mHalDeviceManager).registerStatusListener(hdmCallbackCaptor.capture(), eq(null));
303        mHalDeviceManagerStatusCallbacks = hdmCallbackCaptor.getValue();
304
305    }
306
307    /**
308     * Tests the successful starting of HAL in STA mode using
309     * {@link WifiVendorHal#startVendorHalSta()}.
310     */
311    @Test
312    public void testStartHalSuccessInStaMode() throws  Exception {
313        assertTrue(mWifiVendorHal.startVendorHalSta());
314        assertTrue(mWifiVendorHal.isHalStarted());
315
316        verify(mHalDeviceManager).start();
317        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
318        verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
319        verify(mHalDeviceManager).createRttController();
320        verify(mHalDeviceManager).isReady();
321        verify(mHalDeviceManager).isStarted();
322        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
323        verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
324
325        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
326    }
327
328    /**
329     * Tests the successful starting of HAL in AP mode using
330     * {@link WifiVendorHal#startVendorHalAp()}.
331     */
332    @Test
333    public void testStartHalSuccessInApMode() throws Exception {
334        assertTrue(mWifiVendorHal.startVendorHalAp());
335        assertTrue(mWifiVendorHal.isHalStarted());
336
337        verify(mHalDeviceManager).start();
338        verify(mHalDeviceManager).createApIface(any(), eq(null));
339        verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
340        verify(mHalDeviceManager).isReady();
341        verify(mHalDeviceManager).isStarted();
342
343        verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null));
344        verify(mHalDeviceManager, never()).createRttController();
345    }
346
347    /**
348     * Tests the failure to start HAL in STA mode using
349     * {@link WifiVendorHal#startVendorHalSta()}.
350     */
351    @Test
352    public void testStartHalFailureInStaMode() throws Exception {
353        // No callbacks are invoked in this case since the start itself failed. So, override
354        // default AnswerWithArguments that we setup.
355        doAnswer(new AnswerWithArguments() {
356            public boolean answer() throws Exception {
357                return false;
358            }
359        }).when(mHalDeviceManager).start();
360        assertFalse(mWifiVendorHal.startVendorHalSta());
361        assertFalse(mWifiVendorHal.isHalStarted());
362
363        verify(mHalDeviceManager).start();
364
365        verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null));
366        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
367        verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
368        verify(mHalDeviceManager, never()).createRttController();
369        verify(mIWifiStaIface, never())
370                .registerEventCallback(any(IWifiStaIfaceEventCallback.class));
371    }
372
373    /**
374     * Tests the failure to start HAL in STA mode using
375     * {@link WifiVendorHal#startVendorHalSta()}.
376     */
377    @Test
378    public void testStartHalFailureInIfaceCreationInStaMode() throws Exception {
379        when(mHalDeviceManager.createStaIface(anyBoolean(), any(), eq(null))).thenReturn(null);
380        assertFalse(mWifiVendorHal.startVendorHalSta());
381        assertFalse(mWifiVendorHal.isHalStarted());
382
383        verify(mHalDeviceManager).start();
384        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
385        verify(mHalDeviceManager).stop();
386
387        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
388        verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
389        verify(mHalDeviceManager, never()).createRttController();
390        verify(mIWifiStaIface, never())
391                .registerEventCallback(any(IWifiStaIfaceEventCallback.class));
392    }
393
394    /**
395     * Tests the failure to start HAL in STA mode using
396     * {@link WifiVendorHal#startVendorHalSta()}.
397     */
398    @Test
399    public void testStartHalFailureInRttControllerCreationInStaMode() throws Exception {
400        when(mHalDeviceManager.createRttController()).thenReturn(null);
401        assertFalse(mWifiVendorHal.startVendorHalSta());
402        assertFalse(mWifiVendorHal.isHalStarted());
403
404        verify(mHalDeviceManager).start();
405        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
406        verify(mHalDeviceManager).createRttController();
407        verify(mHalDeviceManager).stop();
408        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
409
410        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
411        verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
412    }
413
414    /**
415     * Tests the failure to start HAL in STA mode using
416     * {@link WifiVendorHal#startVendorHalSta()}.
417     */
418    @Test
419    public void testStartHalFailureInChipGetInStaMode() throws Exception {
420        when(mHalDeviceManager.getChip(any(IWifiIface.class))).thenReturn(null);
421        assertFalse(mWifiVendorHal.startVendorHalSta());
422        assertFalse(mWifiVendorHal.isHalStarted());
423
424        verify(mHalDeviceManager).start();
425        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
426        verify(mHalDeviceManager).createRttController();
427        verify(mHalDeviceManager).getChip(any(IWifiIface.class));
428        verify(mHalDeviceManager).stop();
429        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
430
431        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
432    }
433
434    /**
435     * Tests the failure to start HAL in STA mode using
436     * {@link WifiVendorHal#startVendorHalSta()}.
437     */
438    @Test
439    public void testStartHalFailureInStaIfaceCallbackRegistration() throws Exception {
440        when(mIWifiStaIface.registerEventCallback(any(IWifiStaIfaceEventCallback.class)))
441                .thenReturn(mWifiStatusFailure);
442        assertFalse(mWifiVendorHal.startVendorHalSta());
443        assertFalse(mWifiVendorHal.isHalStarted());
444
445        verify(mHalDeviceManager).start();
446        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
447        verify(mHalDeviceManager).stop();
448        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
449
450        verify(mHalDeviceManager, never()).createRttController();
451        verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
452        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
453    }
454
455    /**
456     * Tests the failure to start HAL in STA mode using
457     * {@link WifiVendorHal#startVendorHalSta()}.
458     */
459    @Test
460    public void testStartHalFailureInChipCallbackRegistration() throws Exception {
461        when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
462                .thenReturn(mWifiStatusFailure);
463        assertFalse(mWifiVendorHal.startVendorHalSta());
464        assertFalse(mWifiVendorHal.isHalStarted());
465
466        verify(mHalDeviceManager).start();
467        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
468        verify(mHalDeviceManager).createRttController();
469        verify(mHalDeviceManager).getChip(any(IWifiIface.class));
470        verify(mHalDeviceManager).stop();
471        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
472        verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
473
474        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
475    }
476
477    /**
478     * Tests the failure to start HAL in AP mode using
479     * {@link WifiVendorHal#startVendorHalAp()}.
480     */
481    @Test
482    public void testStartHalFailureInApMode() throws Exception {
483        when(mHalDeviceManager.createApIface(any(), eq(null))).thenReturn(null);
484        assertFalse(mWifiVendorHal.startVendorHalAp());
485        assertFalse(mWifiVendorHal.isHalStarted());
486
487        verify(mHalDeviceManager).start();
488        verify(mHalDeviceManager).createApIface(any(), eq(null));
489        verify(mHalDeviceManager).stop();
490
491        verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null));
492        verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
493        verify(mHalDeviceManager, never()).createRttController();
494    }
495
496    /**
497     * Tests the stopping of HAL in STA mode using
498     * {@link WifiVendorHal#stopVendorHal()}.
499     */
500    @Test
501    public void testStopHalInStaMode() {
502        assertTrue(mWifiVendorHal.startVendorHalSta());
503        assertTrue(mWifiVendorHal.isHalStarted());
504
505        mWifiVendorHal.stopVendorHal();
506        assertFalse(mWifiVendorHal.isHalStarted());
507
508        verify(mHalDeviceManager).start();
509        verify(mHalDeviceManager).stop();
510        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
511        verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
512        verify(mHalDeviceManager).createRttController();
513        verify(mHalDeviceManager, times(2)).isReady();
514        verify(mHalDeviceManager, times(2)).isStarted();
515
516        verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
517    }
518
519    /**
520     * Tests the stopping of HAL in AP mode using
521     * {@link WifiVendorHal#stopVendorHal()}.
522     */
523    @Test
524    public void testStopHalInApMode() {
525        assertTrue(mWifiVendorHal.startVendorHalAp());
526        assertTrue(mWifiVendorHal.isHalStarted());
527
528        mWifiVendorHal.stopVendorHal();
529        assertFalse(mWifiVendorHal.isHalStarted());
530
531        verify(mHalDeviceManager).start();
532        verify(mHalDeviceManager).stop();
533        verify(mHalDeviceManager).createApIface(any(), eq(null));
534        verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
535        verify(mHalDeviceManager, times(2)).isReady();
536        verify(mHalDeviceManager, times(2)).isStarted();
537
538        verify(mHalDeviceManager, never()).createStaIface(anyBoolean(), any(), eq(null));
539        verify(mHalDeviceManager, never()).createRttController();
540    }
541
542    /**
543     * Tests the handling of interface destroyed callback from HalDeviceManager.
544     */
545    @Test
546    public void testStaInterfaceDestroyedHandling() throws  Exception {
547        ArgumentCaptor<InterfaceDestroyedListener> internalListenerCaptor =
548                ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
549        InterfaceDestroyedListener externalLister = mock(InterfaceDestroyedListener.class);
550
551        assertTrue(mWifiVendorHal.startVendorHal());
552        assertNotNull(mWifiVendorHal.createStaIface(false, externalLister));
553        assertTrue(mWifiVendorHal.isHalStarted());
554
555        verify(mHalDeviceManager).start();
556        verify(mHalDeviceManager).createStaIface(eq(false), internalListenerCaptor.capture(),
557                eq(null));
558        verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
559        verify(mHalDeviceManager).createRttController();
560        verify(mHalDeviceManager).isReady();
561        verify(mHalDeviceManager).isStarted();
562        verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
563        verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
564
565        // Now trigger the interface destroyed callback from HalDeviceManager and ensure the
566        // external listener is invoked and iface removed from internal database.
567        internalListenerCaptor.getValue().onDestroyed(TEST_IFACE_NAME);
568        verify(externalLister).onDestroyed(TEST_IFACE_NAME);
569
570        // This should fail now, since the interface was already destroyed.
571        assertFalse(mWifiVendorHal.removeStaIface(TEST_IFACE_NAME));
572        verify(mHalDeviceManager, never()).removeIface(any());
573    }
574
575    /**
576     * Tests the handling of interface destroyed callback from HalDeviceManager.
577     */
578    @Test
579    public void testApInterfaceDestroyedHandling() throws  Exception {
580        ArgumentCaptor<InterfaceDestroyedListener> internalListenerCaptor =
581                ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
582        InterfaceDestroyedListener externalLister = mock(InterfaceDestroyedListener.class);
583
584        assertTrue(mWifiVendorHal.startVendorHal());
585        assertNotNull(mWifiVendorHal.createApIface(externalLister));
586        assertTrue(mWifiVendorHal.isHalStarted());
587
588        verify(mHalDeviceManager).start();
589        verify(mHalDeviceManager).createApIface(internalListenerCaptor.capture(), eq(null));
590        verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
591        verify(mHalDeviceManager).isReady();
592        verify(mHalDeviceManager).isStarted();
593        verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
594
595        // Now trigger the interface destroyed callback from HalDeviceManager and ensure the
596        // external listener is invoked and iface removed from internal database.
597        internalListenerCaptor.getValue().onDestroyed(TEST_IFACE_NAME);
598        verify(externalLister).onDestroyed(TEST_IFACE_NAME);
599
600        // This should fail now, since the interface was already destroyed.
601        assertFalse(mWifiVendorHal.removeApIface(TEST_IFACE_NAME));
602        verify(mHalDeviceManager, never()).removeIface(any());
603    }
604
605    /**
606     * Test that enter logs when verbose logging is enabled
607     */
608    @Test
609    public void testEnterLogging() {
610        mWifiVendorHal.mLog = spy(mWifiLog);
611        mWifiVendorHal.enableVerboseLogging(true);
612        mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
613        verify(mWifiVendorHal.mLog).trace(eq("filter length %"), eq(1));
614    }
615
616    /**
617     * Test that enter does not log when verbose logging is not enabled
618     */
619    @Test
620    public void testEnterSilenceWhenNotEnabled() {
621        mWifiVendorHal.mLog = spy(mWifiLog);
622        mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
623        mWifiVendorHal.enableVerboseLogging(true);
624        mWifiVendorHal.enableVerboseLogging(false);
625        mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
626        verify(mWifiVendorHal.mLog, never()).trace(eq("filter length %"), anyInt());
627    }
628
629    /**
630     * Test that boolResult logs a false result
631     */
632    @Test
633    public void testBoolResultFalse() {
634        mWifiLog = spy(mWifiLog);
635        mWifiVendorHal.mLog = mWifiLog;
636        mWifiVendorHal.mVerboseLog = mWifiLog;
637        assertFalse(mWifiVendorHal.getBgScanCapabilities(
638                TEST_IFACE_NAME, new WifiNative.ScanCapabilities()));
639        verify(mWifiLog).err("% returns %");
640    }
641
642    /**
643     * Test that getBgScanCapabilities is hooked up to the HAL correctly
644     *
645     * A call before the vendor HAL is started should return a non-null result with version 0
646     *
647     * A call after the HAL is started should return the mocked values.
648     */
649    @Test
650    public void testGetBgScanCapabilities() throws Exception {
651        StaBackgroundScanCapabilities capabilities = new StaBackgroundScanCapabilities();
652        capabilities.maxCacheSize = 12;
653        capabilities.maxBuckets = 34;
654        capabilities.maxApCachePerScan = 56;
655        capabilities.maxReportingThreshold = 78;
656
657        doAnswer(new AnswerWithArguments() {
658            public void answer(IWifiStaIface.getBackgroundScanCapabilitiesCallback cb)
659                    throws RemoteException {
660                cb.onValues(mWifiStatusSuccess, capabilities);
661            }
662        }).when(mIWifiStaIface).getBackgroundScanCapabilities(any(
663                IWifiStaIface.getBackgroundScanCapabilitiesCallback.class));
664
665        WifiNative.ScanCapabilities result = new WifiNative.ScanCapabilities();
666
667        // should fail - not started
668        assertFalse(mWifiVendorHal.getBgScanCapabilities(TEST_IFACE_NAME, result));
669        // Start the vendor hal
670        assertTrue(mWifiVendorHal.startVendorHalSta());
671        // should succeed
672        assertTrue(mWifiVendorHal.getBgScanCapabilities(TEST_IFACE_NAME, result));
673
674        assertEquals(12, result.max_scan_cache_size);
675        assertEquals(34, result.max_scan_buckets);
676        assertEquals(56, result.max_ap_cache_per_scan);
677        assertEquals(78, result.max_scan_reporting_threshold);
678    }
679
680    /**
681     * Test translation to WifiManager.WIFI_FEATURE_*
682     *
683     * Just do a spot-check with a few feature bits here; since the code is table-
684     * driven we don't have to work hard to exercise all of it.
685     */
686    @Test
687    public void testStaIfaceFeatureMaskTranslation() {
688        int caps = (
689                IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN
690                | IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
691            );
692        int expected = (
693                WifiManager.WIFI_FEATURE_SCANNER
694                | WifiManager.WIFI_FEATURE_LINK_LAYER_STATS);
695        assertEquals(expected, mWifiVendorHal.wifiFeatureMaskFromStaCapabilities(caps));
696    }
697
698    /**
699     * Test translation to WifiManager.WIFI_FEATURE_*
700     *
701     * Just do a spot-check with a few feature bits here; since the code is table-
702     * driven we don't have to work hard to exercise all of it.
703     */
704    @Test
705    public void testChipFeatureMaskTranslation() {
706        int caps = (
707                android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT
708                        | android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2D_RTT
709                        | android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2AP_RTT
710        );
711        int expected = (
712                WifiManager.WIFI_FEATURE_TX_POWER_LIMIT
713                        | WifiManager.WIFI_FEATURE_D2D_RTT
714                        | WifiManager.WIFI_FEATURE_D2AP_RTT
715        );
716        assertEquals(expected, mWifiVendorHal.wifiFeatureMaskFromChipCapabilities(caps));
717    }
718
719    /**
720     * Test get supported features. Tests whether we coalesce information from different sources
721     * (IWifiStaIface, IWifiChip and HalDeviceManager) into the bitmask of supported features
722     * correctly.
723     */
724    @Test
725    public void testGetSupportedFeatures() throws Exception {
726        assertTrue(mWifiVendorHal.startVendorHalSta());
727
728        int staIfaceHidlCaps = (
729                IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN
730                        | IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
731        );
732        int chipHidlCaps =
733                android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT;
734        Set<Integer>  halDeviceManagerSupportedIfaces = new HashSet<Integer>() {{
735                add(IfaceType.STA);
736                add(IfaceType.P2P);
737            }};
738        int expectedFeatureSet = (
739                WifiManager.WIFI_FEATURE_SCANNER
740                        | WifiManager.WIFI_FEATURE_LINK_LAYER_STATS
741                        | WifiManager.WIFI_FEATURE_TX_POWER_LIMIT
742                        | WifiManager.WIFI_FEATURE_INFRA
743                        | WifiManager.WIFI_FEATURE_P2P
744        );
745
746        doAnswer(new AnswerWithArguments() {
747            public void answer(IWifiStaIface.getCapabilitiesCallback cb) throws RemoteException {
748                cb.onValues(mWifiStatusSuccess, staIfaceHidlCaps);
749            }
750        }).when(mIWifiStaIface).getCapabilities(any(IWifiStaIface.getCapabilitiesCallback.class));
751        doAnswer(new AnswerWithArguments() {
752            public void answer(IWifiChip.getCapabilitiesCallback cb) throws RemoteException {
753                cb.onValues(mWifiStatusSuccess, chipHidlCaps);
754            }
755        }).when(mIWifiChip).getCapabilities(any(IWifiChip.getCapabilitiesCallback.class));
756        when(mHalDeviceManager.getSupportedIfaceTypes())
757                .thenReturn(halDeviceManagerSupportedIfaces);
758
759        assertEquals(expectedFeatureSet, mWifiVendorHal.getSupportedFeatureSet(TEST_IFACE_NAME));
760    }
761
762    /**
763     * Test enablement of link layer stats after startup
764     *
765     * Request link layer stats before HAL start
766     * - should not make it to the HAL layer
767     * Start the HAL in STA mode
768     * Request link layer stats twice more
769     * - enable request should make it to the HAL layer
770     * - HAL layer should have been called to make the requests (i.e., two calls total)
771     */
772    @Test
773    public void testLinkLayerStatsEnableAfterStartup() throws Exception {
774        doNothing().when(mIWifiStaIface).getLinkLayerStats(any());
775
776        assertNull(mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME));
777        assertTrue(mWifiVendorHal.startVendorHalSta());
778        assertTrue(mWifiVendorHal.isHalStarted());
779
780        verify(mHalDeviceManager).start();
781        mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME);
782        mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME);
783        verify(mIWifiStaIface).enableLinkLayerStatsCollection(false); // mLinkLayerStatsDebug
784        verify(mIWifiStaIface, times(2)).getLinkLayerStats(any());
785    }
786
787    /**
788     * Test that link layer stats are not enabled and harmless in AP mode
789     *
790     * Start the HAL in AP mode
791     * - stats should not be enabled
792     * Request link layer stats
793     * - HAL layer should have been called to make the request
794     */
795    @Test
796    public void testLinkLayerStatsNotEnabledAndHarmlessInApMode() throws Exception {
797        doNothing().when(mIWifiStaIface).getLinkLayerStats(any());
798
799        assertTrue(mWifiVendorHal.startVendorHalAp());
800        assertTrue(mWifiVendorHal.isHalStarted());
801        assertNull(mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME));
802
803        verify(mHalDeviceManager).start();
804
805        verify(mIWifiStaIface, never()).enableLinkLayerStatsCollection(false);
806        verify(mIWifiStaIface, never()).getLinkLayerStats(any());
807    }
808
809    /**
810     * Test that the link layer stats fields are populated correctly.
811     *
812     * This is done by filling with random values and then using toString on the
813     * original and converted values, comparing just the numerics in the result.
814     * This makes the assumption that the fields are in the same order in both string
815     * representations, which is not quite true. So apply some fixups before the final
816     * comparison.
817     */
818    @Test
819    public void testLinkLayerStatsAssignment() throws Exception {
820        Random r = new Random(1775968256);
821        StaLinkLayerStats stats = new StaLinkLayerStats();
822        randomizePacketStats(r, stats.iface.wmeBePktStats);
823        randomizePacketStats(r, stats.iface.wmeBkPktStats);
824        randomizePacketStats(r, stats.iface.wmeViPktStats);
825        randomizePacketStats(r, stats.iface.wmeVoPktStats);
826        randomizeRadioStats(r, stats.radios);
827
828        stats.timeStampInMs = r.nextLong() & 0xFFFFFFFFFFL;
829
830        String expected = numbersOnly(stats.toString() + " ");
831
832        WifiLinkLayerStats converted = WifiVendorHal.frameworkFromHalLinkLayerStats(stats);
833
834        String actual = numbersOnly(converted.toString() + " ");
835
836        // Do the required fixups to the both expected and actual
837        expected = rmValue(expected, stats.radios.get(0).rxTimeInMs);
838        expected = rmValue(expected, stats.radios.get(0).onTimeInMsForScan);
839
840        actual = rmValue(actual, stats.radios.get(0).rxTimeInMs);
841        actual = rmValue(actual, stats.radios.get(0).onTimeInMsForScan);
842
843        // The remaining fields should agree
844        assertEquals(expected, actual);
845    }
846
847    /** Just the digits with delimiting spaces, please */
848    private static String numbersOnly(String s) {
849        return s.replaceAll("[^0-9]+", " ");
850    }
851
852    /** Remove the given value from the space-delimited string, or die trying. */
853    private static String rmValue(String s, long value) throws Exception {
854        String ans = s.replaceAll(" " + value + " ", " ");
855        assertNotEquals(s, ans);
856        return ans;
857    }
858
859    /**
860     * Populate packet stats with non-negative random values
861     */
862    private static void randomizePacketStats(Random r, StaLinkLayerIfacePacketStats pstats) {
863        pstats.rxMpdu = r.nextLong() & 0xFFFFFFFFFFL; // more than 32 bits
864        pstats.txMpdu = r.nextLong() & 0xFFFFFFFFFFL;
865        pstats.lostMpdu = r.nextLong() & 0xFFFFFFFFFFL;
866        pstats.retries = r.nextLong() & 0xFFFFFFFFFFL;
867    }
868
869   /**
870     * Populate radio stats with non-negative random values
871     */
872    private static void randomizeRadioStats(Random r, ArrayList<StaLinkLayerRadioStats> rstats) {
873        StaLinkLayerRadioStats rstat = new StaLinkLayerRadioStats();
874        rstat.onTimeInMs = r.nextInt() & 0xFFFFFF;
875        rstat.txTimeInMs = r.nextInt() & 0xFFFFFF;
876        for (int i = 0; i < 4; i++) {
877            Integer v = r.nextInt() & 0xFFFFFF;
878            rstat.txTimeInMsPerLevel.add(v);
879        }
880        rstat.rxTimeInMs = r.nextInt() & 0xFFFFFF;
881        rstat.onTimeInMsForScan = r.nextInt() & 0xFFFFFF;
882        rstats.add(rstat);
883    }
884
885    /**
886     * Test that getFirmwareVersion() and getDriverVersion() work
887     *
888     * Calls before the STA is started are expected to return null.
889     */
890    @Test
891    public void testVersionGetters() throws Exception {
892        String firmwareVersion = "fuzzy";
893        String driverVersion = "dizzy";
894        IWifiChip.ChipDebugInfo chipDebugInfo = new IWifiChip.ChipDebugInfo();
895        chipDebugInfo.firmwareDescription = firmwareVersion;
896        chipDebugInfo.driverDescription = driverVersion;
897
898        doAnswer(new AnswerWithArguments() {
899            public void answer(IWifiChip.requestChipDebugInfoCallback cb) throws RemoteException {
900                cb.onValues(mWifiStatusSuccess, chipDebugInfo);
901            }
902        }).when(mIWifiChip).requestChipDebugInfo(any(IWifiChip.requestChipDebugInfoCallback.class));
903
904        assertNull(mWifiVendorHal.getFirmwareVersion());
905        assertNull(mWifiVendorHal.getDriverVersion());
906
907        assertTrue(mWifiVendorHal.startVendorHalSta());
908
909        assertEquals(firmwareVersion, mWifiVendorHal.getFirmwareVersion());
910        assertEquals(driverVersion, mWifiVendorHal.getDriverVersion());
911    }
912
913    /**
914     * For checkRoundTripIntTranslation lambdas
915     */
916    interface IntForInt {
917        int translate(int value);
918    }
919
920    /**
921     * Checks that translation from x to y and back again is the identity function
922     *
923     * @param xFromY reverse translator
924     * @param yFromX forward translator
925     * @param xLimit non-inclusive upper bound on x (lower bound is zero)
926     */
927    private void checkRoundTripIntTranslation(
928            IntForInt xFromY, IntForInt yFromX, int xFirst, int xLimit) throws Exception {
929        int ex = 0;
930        for (int i = xFirst; i < xLimit; i++) {
931            assertEquals(i, xFromY.translate(yFromX.translate(i)));
932        }
933        try {
934            yFromX.translate(xLimit);
935            assertTrue("expected an exception here", false);
936        } catch (IllegalArgumentException e) {
937            ex++;
938        }
939        try {
940            xFromY.translate(yFromX.translate(xLimit - 1) + 1);
941            assertTrue("expected an exception here", false);
942        } catch (IllegalArgumentException e) {
943            ex++;
944        }
945        assertEquals(2, ex);
946    }
947
948
949    /**
950     * Test translations of RTT type
951     */
952    @Test
953    public void testRttTypeTranslation() throws Exception {
954        checkRoundTripIntTranslation(
955                (y) -> WifiVendorHal.halRttTypeFromFrameworkRttType(y),
956                (x) -> WifiVendorHal.frameworkRttTypeFromHalRttType(x),
957                1, 3);
958    }
959
960    /**
961     * Test translations of peer type
962     */
963    @Test
964    public void testPeerTranslation() throws Exception {
965        checkRoundTripIntTranslation(
966                (y) -> WifiVendorHal.halPeerFromFrameworkPeer(y),
967                (x) -> WifiVendorHal.frameworkPeerFromHalPeer(x),
968                1, 6);
969    }
970
971    /**
972     * Test translations of channel width
973     */
974    @Test
975    public void testChannelWidth() throws Exception {
976        checkRoundTripIntTranslation(
977                (y) -> WifiVendorHal.halChannelWidthFromFrameworkChannelWidth(y),
978                (x) -> WifiVendorHal.frameworkChannelWidthFromHalChannelWidth(x),
979                0, 5);
980    }
981
982    /**
983     * Test translations of preamble type mask
984     */
985    @Test
986    public void testPreambleTranslation() throws Exception {
987        checkRoundTripIntTranslation(
988                (y) -> WifiVendorHal.halPreambleFromFrameworkPreamble(y),
989                (x) -> WifiVendorHal.frameworkPreambleFromHalPreamble(x),
990                0, 8);
991    }
992
993    /**
994     * Test translations of bandwidth mask
995     */
996    @Test
997    public void testBandwidthTranslations() throws Exception {
998        checkRoundTripIntTranslation(
999                (y) -> WifiVendorHal.halBwFromFrameworkBw(y),
1000                (x) -> WifiVendorHal.frameworkBwFromHalBw(x),
1001                0, 64);
1002    }
1003
1004    /**
1005     * Test translation of framwork RttParams to hal RttConfig
1006     */
1007    @Test
1008    public void testGetRttStuff() throws Exception {
1009        RttManager.RttParams params = new RttManager.RttParams();
1010        params.bssid = "03:01:04:01:05:09";
1011        params.frequency = 2420;
1012        params.channelWidth = ScanResult.CHANNEL_WIDTH_40MHZ;
1013        params.centerFreq0 = 2440;
1014        params.centerFreq1 = 1;
1015        params.num_samples = 2;
1016        params.num_retries = 3;
1017        params.numberBurst = 4;
1018        params.interval = 5;
1019        params.numSamplesPerBurst = 8;
1020        params.numRetriesPerMeasurementFrame = 6;
1021        params.numRetriesPerFTMR = 7;
1022        params.LCIRequest = false;
1023        params.LCRRequest = false;
1024        params.burstTimeout = 15;
1025        String frameish = params.toString();
1026        assertFalse(frameish.contains("=0,")); // make sure all fields are initialized
1027        RttConfig config = WifiVendorHal.halRttConfigFromFrameworkRttParams(params);
1028        String halish = config.toString();
1029        StringBuffer expect = new StringBuffer(200);
1030        expect.append("{.addr = [3, 1, 4, 1, 5, 9], .type = ONE_SIDED, .peer = AP, ");
1031        expect.append(".channel = {.width = WIDTH_40, .centerFreq = 2420, ");
1032        expect.append(".centerFreq0 = 2440, .centerFreq1 = 1}, ");
1033        expect.append(".burstPeriod = 5, .numBurst = 4, .numFramesPerBurst = 8, ");
1034        expect.append(".numRetriesPerRttFrame = 6, .numRetriesPerFtmr = 7, ");
1035        expect.append(".mustRequestLci = false, .mustRequestLcr = false, .burstDuration = 15, ");
1036        expect.append(".preamble = HT, .bw = BW_20MHZ}");
1037        assertEquals(expect.toString(), halish);
1038    }
1039
1040    /**
1041     * Test that RTT capabilities are plumbed through
1042     */
1043    @Test
1044    public void testGetRttCapabilities() throws Exception {
1045        RttCapabilities capabilities = new RttCapabilities();
1046        capabilities.lcrSupported = true;
1047        capabilities.preambleSupport = RttPreamble.LEGACY | RttPreamble.VHT;
1048        capabilities.bwSupport = RttBw.BW_5MHZ | RttBw.BW_20MHZ;
1049        capabilities.mcVersion = 43;
1050        doAnswer(new AnswerWithArguments() {
1051            public void answer(IWifiRttController.getCapabilitiesCallback cb)
1052                    throws RemoteException {
1053                cb.onValues(mWifiStatusSuccess, capabilities);
1054            }
1055        }).when(mIWifiRttController).getCapabilities(any(
1056                IWifiRttController.getCapabilitiesCallback.class));
1057
1058        assertNull(mWifiVendorHal.getRttCapabilities());
1059
1060        assertTrue(mWifiVendorHal.startVendorHalSta());
1061
1062        RttManager.RttCapabilities actual = mWifiVendorHal.getRttCapabilities();
1063        assertTrue(actual.lcrSupported);
1064        assertEquals(RttManager.PREAMBLE_LEGACY | RttManager.PREAMBLE_VHT,
1065                actual.preambleSupported);
1066        assertEquals(RttManager.RTT_BW_5_SUPPORT | RttManager.RTT_BW_20_SUPPORT,
1067                actual.bwSupported);
1068        assertEquals(43, (int) capabilities.mcVersion);
1069    }
1070
1071    /**
1072     * Negative test of disableRttResponder
1073     */
1074    @Test
1075    public void testDisableOfUnstartedRtt() throws Exception {
1076        assertFalse(mWifiVendorHal.disableRttResponder());
1077    }
1078
1079    /**
1080     * Test that setScanningMacOui is hooked up to the HAL correctly
1081     */
1082    @Test
1083    public void testSetScanningMacOui() throws Exception {
1084        byte[] oui = NativeUtil.macAddressOuiToByteArray("DA:A1:19");
1085        byte[] zzz = NativeUtil.macAddressOuiToByteArray("00:00:00");
1086
1087        when(mIWifiStaIface.setScanningMacOui(any())).thenReturn(mWifiStatusSuccess);
1088
1089        // expect fail - STA not started
1090        assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, oui));
1091        assertTrue(mWifiVendorHal.startVendorHalSta());
1092        // expect fail - null
1093        assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, null));
1094        // expect fail - len
1095        assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, new byte[]{(byte) 1}));
1096        assertTrue(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, oui));
1097        assertTrue(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, zzz));
1098
1099        verify(mIWifiStaIface).setScanningMacOui(eq(oui));
1100        verify(mIWifiStaIface).setScanningMacOui(eq(zzz));
1101    }
1102
1103    @Test
1104    public void testStartSendingOffloadedPacket() throws Exception {
1105        byte[] srcMac = NativeUtil.macAddressToByteArray("4007b2088c81");
1106        byte[] dstMac = NativeUtil.macAddressToByteArray("4007b8675309");
1107        InetAddress src = InetAddress.parseNumericAddress("192.168.13.13");
1108        InetAddress dst = InetAddress.parseNumericAddress("93.184.216.34");
1109        int slot = 13;
1110        int millis = 16000;
1111
1112        KeepalivePacketData kap = KeepalivePacketData.nattKeepalivePacket(src, 63000, dst, 4500);
1113
1114        when(mIWifiStaIface.startSendingKeepAlivePackets(
1115                anyInt(), any(), anyShort(), any(), any(), anyInt()
1116        )).thenReturn(mWifiStatusSuccess);
1117
1118        assertTrue(mWifiVendorHal.startVendorHalSta());
1119        assertTrue(0 == mWifiVendorHal.startSendingOffloadedPacket(
1120                TEST_IFACE_NAME, slot, srcMac, dstMac, kap.getPacket(),
1121                OsConstants.ETH_P_IPV6, millis));
1122
1123        verify(mIWifiStaIface).startSendingKeepAlivePackets(
1124                eq(slot), any(), anyShort(), any(), any(), eq(millis));
1125    }
1126
1127    @Test
1128    public void testStopSendingOffloadedPacket() throws Exception {
1129        int slot = 13;
1130
1131        when(mIWifiStaIface.stopSendingKeepAlivePackets(anyInt())).thenReturn(mWifiStatusSuccess);
1132
1133        assertTrue(mWifiVendorHal.startVendorHalSta());
1134        assertTrue(0 == mWifiVendorHal.stopSendingOffloadedPacket(
1135                TEST_IFACE_NAME, slot));
1136
1137        verify(mIWifiStaIface).stopSendingKeepAlivePackets(eq(slot));
1138    }
1139
1140    /**
1141     * Test the setup, invocation, and removal of a RSSI event handler
1142     *
1143     */
1144    @Test
1145    public void testRssiMonitoring() throws Exception {
1146        when(mIWifiStaIface.startRssiMonitoring(anyInt(), anyInt(), anyInt()))
1147                .thenReturn(mWifiStatusSuccess);
1148        when(mIWifiStaIface.stopRssiMonitoring(anyInt()))
1149                .thenReturn(mWifiStatusSuccess);
1150
1151        ArrayList<Byte> breach = new ArrayList<>(10);
1152        byte hi = -21;
1153        byte med = -42;
1154        byte lo = -84;
1155        Byte lower = -88;
1156        WifiNative.WifiRssiEventHandler handler;
1157        handler = ((cur) -> {
1158            breach.add(cur);
1159        });
1160        // not started
1161        assertEquals(-1, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
1162        // not started
1163        assertEquals(-1, mWifiVendorHal.stopRssiMonitoring(TEST_IFACE_NAME));
1164        assertTrue(mWifiVendorHal.startVendorHalSta());
1165        assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
1166        int theCmdId = mWifiVendorHal.sRssiMonCmdId;
1167        breach.clear();
1168        mIWifiStaIfaceEventCallback.onRssiThresholdBreached(theCmdId, new byte[6], lower);
1169        assertEquals(breach.get(0), lower);
1170        assertEquals(0, mWifiVendorHal.stopRssiMonitoring(TEST_IFACE_NAME));
1171        assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
1172        // replacing works
1173        assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, med, lo, handler));
1174        // null handler fails
1175        assertEquals(-1, mWifiVendorHal.startRssiMonitoring(
1176                TEST_IFACE_NAME, hi, lo, null));
1177        assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
1178        // empty range
1179        assertEquals(-1, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, lo, hi, handler));
1180    }
1181
1182    /**
1183     * Test that getApfCapabilities is hooked up to the HAL correctly
1184     *
1185     * A call before the vendor HAL is started should return a non-null result with version 0
1186     *
1187     * A call after the HAL is started should return the mocked values.
1188     */
1189    @Test
1190    public void testApfCapabilities() throws Exception {
1191        int myVersion = 33;
1192        int myMaxSize = 1234;
1193
1194        StaApfPacketFilterCapabilities capabilities = new StaApfPacketFilterCapabilities();
1195        capabilities.version = myVersion;
1196        capabilities.maxLength = myMaxSize;
1197
1198        doAnswer(new AnswerWithArguments() {
1199            public void answer(IWifiStaIface.getApfPacketFilterCapabilitiesCallback cb)
1200                    throws RemoteException {
1201                cb.onValues(mWifiStatusSuccess, capabilities);
1202            }
1203        }).when(mIWifiStaIface).getApfPacketFilterCapabilities(any(
1204                IWifiStaIface.getApfPacketFilterCapabilitiesCallback.class));
1205
1206
1207        assertEquals(0, mWifiVendorHal.getApfCapabilities(TEST_IFACE_NAME)
1208                .apfVersionSupported);
1209
1210        assertTrue(mWifiVendorHal.startVendorHalSta());
1211
1212        ApfCapabilities actual = mWifiVendorHal.getApfCapabilities(TEST_IFACE_NAME);
1213
1214        assertEquals(myVersion, actual.apfVersionSupported);
1215        assertEquals(myMaxSize, actual.maximumApfProgramSize);
1216        assertEquals(android.system.OsConstants.ARPHRD_ETHER, actual.apfPacketFormat);
1217        assertNotEquals(0, actual.apfPacketFormat);
1218    }
1219
1220    /**
1221     * Test that an APF program can be installed.
1222     */
1223    @Test
1224    public void testInstallApf() throws Exception {
1225        byte[] filter = new byte[] {19, 53, 10};
1226
1227        ArrayList<Byte> expected = new ArrayList<>(3);
1228        for (byte b : filter) expected.add(b);
1229
1230        when(mIWifiStaIface.installApfPacketFilter(anyInt(), any(ArrayList.class)))
1231                .thenReturn(mWifiStatusSuccess);
1232
1233        assertTrue(mWifiVendorHal.startVendorHalSta());
1234        assertTrue(mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, filter));
1235
1236        verify(mIWifiStaIface).installApfPacketFilter(eq(0), eq(expected));
1237    }
1238
1239    /**
1240     * Test that an APF program and data buffer can be read back.
1241     */
1242    @Test
1243    public void testReadApf() throws Exception {
1244        // Expose the 1.2 IWifiStaIface.
1245        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
1246
1247        byte[] program = new byte[] {65, 66, 67};
1248        ArrayList<Byte> expected = new ArrayList<>(3);
1249        for (byte b : program) expected.add(b);
1250
1251        doAnswer(new AnswerWithArguments() {
1252            public void answer(
1253                    android.hardware.wifi.V1_2.IWifiStaIface.readApfPacketFilterDataCallback cb)
1254                    throws RemoteException {
1255                cb.onValues(mWifiStatusSuccess, expected);
1256            }
1257        }).when(mIWifiStaIfaceV12).readApfPacketFilterData(any(
1258                android.hardware.wifi.V1_2.IWifiStaIface.readApfPacketFilterDataCallback.class));
1259
1260        assertTrue(mWifiVendorHal.startVendorHalSta());
1261        assertArrayEquals(program, mWifiVendorHal.readPacketFilter(TEST_IFACE_NAME));
1262    }
1263
1264    /**
1265     * Test that the country code is set in AP mode (when it should be).
1266     */
1267    @Test
1268    public void testSetCountryCodeHal() throws Exception {
1269        byte[] expected = new byte[]{(byte) 'C', (byte) 'A'};
1270
1271        when(mIWifiApIface.setCountryCode(any()))
1272                .thenReturn(mWifiStatusSuccess);
1273
1274        assertTrue(mWifiVendorHal.startVendorHalAp());
1275
1276        assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, null));
1277        assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, ""));
1278        assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "A"));
1279        // Only one expected to succeed
1280        assertTrue(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "CA"));
1281        assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "ZZZ"));
1282
1283        verify(mIWifiApIface).setCountryCode(eq(expected));
1284    }
1285
1286    /**
1287     * Test that RemoteException is caught and logged.
1288     */
1289    @Test
1290    public void testRemoteExceptionIsHandled() throws Exception {
1291        mWifiLog = spy(mWifiLog);
1292        mWifiVendorHal.mVerboseLog = mWifiLog;
1293        when(mIWifiApIface.setCountryCode(any()))
1294                .thenThrow(new RemoteException("oops"));
1295        assertTrue(mWifiVendorHal.startVendorHalAp());
1296        assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "CA"));
1297        assertFalse(mWifiVendorHal.isHalStarted());
1298        verify(mWifiLog).err("% RemoteException in HIDL call %");
1299    }
1300
1301    /**
1302     * Test that startLoggingToDebugRingBuffer is plumbed to chip
1303     *
1304     * A call before the vendor hal is started should just return false.
1305     * After starting in STA mode, the call should succeed, and pass ther right things down.
1306     */
1307    @Test
1308    public void testStartLoggingRingBuffer() throws Exception {
1309        when(mIWifiChip.startLoggingToDebugRingBuffer(
1310                any(String.class), anyInt(), anyInt(), anyInt()
1311        )).thenReturn(mWifiStatusSuccess);
1312
1313        assertFalse(mWifiVendorHal.startLoggingRingBuffer(1, 0x42, 0, 0, "One"));
1314        assertTrue(mWifiVendorHal.startVendorHalSta());
1315        assertTrue(mWifiVendorHal.startLoggingRingBuffer(1, 0x42, 11, 3000, "One"));
1316
1317        verify(mIWifiChip).startLoggingToDebugRingBuffer("One", 1, 11, 3000);
1318    }
1319
1320    /**
1321     * Same test as testStartLoggingRingBuffer, but in AP mode rather than STA.
1322     */
1323    @Test
1324    public void testStartLoggingRingBufferOnAp() throws Exception {
1325        when(mIWifiChip.startLoggingToDebugRingBuffer(
1326                any(String.class), anyInt(), anyInt(), anyInt()
1327        )).thenReturn(mWifiStatusSuccess);
1328
1329        assertFalse(mWifiVendorHal.startLoggingRingBuffer(1, 0x42, 0, 0, "One"));
1330        assertTrue(mWifiVendorHal.startVendorHalAp());
1331        assertTrue(mWifiVendorHal.startLoggingRingBuffer(1, 0x42, 11, 3000, "One"));
1332
1333        verify(mIWifiChip).startLoggingToDebugRingBuffer("One", 1, 11, 3000);
1334    }
1335
1336    /**
1337     * Test that getRingBufferStatus gets and translates its stuff correctly
1338     */
1339    @Test
1340    public void testRingBufferStatus() throws Exception {
1341        WifiDebugRingBufferStatus one = new WifiDebugRingBufferStatus();
1342        one.ringName = "One";
1343        one.flags = WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES;
1344        one.ringId = 5607371;
1345        one.sizeInBytes = 54321;
1346        one.freeSizeInBytes = 42;
1347        one.verboseLevel = WifiDebugRingBufferVerboseLevel.VERBOSE;
1348        String oneExpect = "name: One flag: 1 ringBufferId: 5607371 ringBufferByteSize: 54321"
1349                + " verboseLevel: 2 writtenBytes: 0 readBytes: 0 writtenRecords: 0";
1350
1351        WifiDebugRingBufferStatus two = new WifiDebugRingBufferStatus();
1352        two.ringName = "Two";
1353        two.flags = WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES
1354                | WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES;
1355        two.ringId = 4512470;
1356        two.sizeInBytes = 300;
1357        two.freeSizeInBytes = 42;
1358        two.verboseLevel = WifiDebugRingBufferVerboseLevel.DEFAULT;
1359
1360        ArrayList<WifiDebugRingBufferStatus> halBufferStatus = new ArrayList<>(2);
1361        halBufferStatus.add(one);
1362        halBufferStatus.add(two);
1363
1364        WifiNative.RingBufferStatus[] actual;
1365
1366        doAnswer(new AnswerWithArguments() {
1367            public void answer(IWifiChip.getDebugRingBuffersStatusCallback cb)
1368                    throws RemoteException {
1369                cb.onValues(mWifiStatusSuccess, halBufferStatus);
1370            }
1371        }).when(mIWifiChip).getDebugRingBuffersStatus(any(
1372                IWifiChip.getDebugRingBuffersStatusCallback.class));
1373
1374        assertTrue(mWifiVendorHal.startVendorHalSta());
1375        actual = mWifiVendorHal.getRingBufferStatus();
1376
1377        assertEquals(halBufferStatus.size(), actual.length);
1378        assertEquals(oneExpect, actual[0].toString());
1379        assertEquals(two.ringId, actual[1].ringBufferId);
1380    }
1381
1382    /**
1383     * Test that getRingBufferData calls forceDumpToDebugRingBuffer
1384     *
1385     * Try once before hal start, and twice after (one success, one failure).
1386     */
1387    @Test
1388    public void testForceRingBufferDump() throws Exception {
1389        when(mIWifiChip.forceDumpToDebugRingBuffer(eq("Gunk"))).thenReturn(mWifiStatusSuccess);
1390        when(mIWifiChip.forceDumpToDebugRingBuffer(eq("Glop"))).thenReturn(mWifiStatusFailure);
1391
1392        assertFalse(mWifiVendorHal.getRingBufferData("Gunk")); // hal not started
1393
1394        assertTrue(mWifiVendorHal.startVendorHalSta());
1395
1396        assertTrue(mWifiVendorHal.getRingBufferData("Gunk")); // mocked call succeeds
1397        assertFalse(mWifiVendorHal.getRingBufferData("Glop")); // mocked call fails
1398
1399        verify(mIWifiChip).forceDumpToDebugRingBuffer("Gunk");
1400        verify(mIWifiChip).forceDumpToDebugRingBuffer("Glop");
1401    }
1402
1403    /**
1404     * Tests the start of packet fate monitoring.
1405     *
1406     * Try once before hal start, and once after (one success, one failure).
1407     */
1408    @Test
1409    public void testStartPktFateMonitoring() throws Exception {
1410        when(mIWifiStaIface.startDebugPacketFateMonitoring()).thenReturn(mWifiStatusSuccess);
1411
1412        assertFalse(mWifiVendorHal.startPktFateMonitoring(TEST_IFACE_NAME));
1413        verify(mIWifiStaIface, never()).startDebugPacketFateMonitoring();
1414
1415        assertTrue(mWifiVendorHal.startVendorHalSta());
1416        assertTrue(mWifiVendorHal.startPktFateMonitoring(TEST_IFACE_NAME));
1417        verify(mIWifiStaIface).startDebugPacketFateMonitoring();
1418    }
1419
1420    /**
1421     * Tests the retrieval of tx packet fates.
1422     *
1423     * Try once before hal start, and once after.
1424     */
1425    @Test
1426    public void testGetTxPktFates() throws Exception {
1427        byte[] frameContentBytes = new byte[30];
1428        new Random().nextBytes(frameContentBytes);
1429        WifiDebugTxPacketFateReport fateReport = new WifiDebugTxPacketFateReport();
1430        fateReport.fate = WifiDebugTxPacketFate.DRV_QUEUED;
1431        fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
1432        fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.ETHERNET_II;
1433        fateReport.frameInfo.frameContent.addAll(
1434                NativeUtil.byteArrayToArrayList(frameContentBytes));
1435
1436        doAnswer(new AnswerWithArguments() {
1437            public void answer(IWifiStaIface.getDebugTxPacketFatesCallback cb) {
1438                cb.onValues(mWifiStatusSuccess,
1439                        new ArrayList<WifiDebugTxPacketFateReport>(Arrays.asList(fateReport)));
1440            }
1441        }).when(mIWifiStaIface)
1442                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1443
1444        WifiNative.TxFateReport[] retrievedFates = new WifiNative.TxFateReport[1];
1445        assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
1446        verify(mIWifiStaIface, never())
1447                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1448
1449        assertTrue(mWifiVendorHal.startVendorHalSta());
1450
1451        assertTrue(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
1452        verify(mIWifiStaIface)
1453                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1454        assertEquals(WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED, retrievedFates[0].mFate);
1455        assertEquals(fateReport.frameInfo.driverTimestampUsec,
1456                retrievedFates[0].mDriverTimestampUSec);
1457        assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, retrievedFates[0].mFrameType);
1458        assertArrayEquals(frameContentBytes, retrievedFates[0].mFrameBytes);
1459    }
1460
1461    /**
1462     * Tests the retrieval of tx packet fates when the number of fates retrieved exceeds the
1463     * input array.
1464     *
1465     * Try once before hal start, and once after.
1466     */
1467    @Test
1468    public void testGetTxPktFatesExceedsInputArrayLength() throws Exception {
1469        byte[] frameContentBytes = new byte[30];
1470        new Random().nextBytes(frameContentBytes);
1471        WifiDebugTxPacketFateReport fateReport = new WifiDebugTxPacketFateReport();
1472        fateReport.fate = WifiDebugTxPacketFate.FW_DROP_OTHER;
1473        fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
1474        fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.MGMT_80211;
1475        fateReport.frameInfo.frameContent.addAll(
1476                NativeUtil.byteArrayToArrayList(frameContentBytes));
1477
1478        doAnswer(new AnswerWithArguments() {
1479            public void answer(IWifiStaIface.getDebugTxPacketFatesCallback cb) {
1480                cb.onValues(mWifiStatusSuccess,
1481                        new ArrayList<WifiDebugTxPacketFateReport>(Arrays.asList(
1482                                fateReport, fateReport)));
1483            }
1484        }).when(mIWifiStaIface)
1485                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1486
1487        WifiNative.TxFateReport[] retrievedFates = new WifiNative.TxFateReport[1];
1488        assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
1489        verify(mIWifiStaIface, never())
1490                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1491
1492        assertTrue(mWifiVendorHal.startVendorHalSta());
1493
1494        assertTrue(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
1495        verify(mIWifiStaIface)
1496                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1497        assertEquals(WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER, retrievedFates[0].mFate);
1498        assertEquals(fateReport.frameInfo.driverTimestampUsec,
1499                retrievedFates[0].mDriverTimestampUSec);
1500        assertEquals(WifiLoggerHal.FRAME_TYPE_80211_MGMT, retrievedFates[0].mFrameType);
1501        assertArrayEquals(frameContentBytes, retrievedFates[0].mFrameBytes);
1502    }
1503
1504    /**
1505     * Tests the retrieval of rx packet fates.
1506     *
1507     * Try once before hal start, and once after.
1508     */
1509    @Test
1510    public void testGetRxPktFates() throws Exception {
1511        byte[] frameContentBytes = new byte[30];
1512        new Random().nextBytes(frameContentBytes);
1513        WifiDebugRxPacketFateReport fateReport = new WifiDebugRxPacketFateReport();
1514        fateReport.fate = WifiDebugRxPacketFate.SUCCESS;
1515        fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
1516        fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.ETHERNET_II;
1517        fateReport.frameInfo.frameContent.addAll(
1518                NativeUtil.byteArrayToArrayList(frameContentBytes));
1519
1520        doAnswer(new AnswerWithArguments() {
1521            public void answer(IWifiStaIface.getDebugRxPacketFatesCallback cb) {
1522                cb.onValues(mWifiStatusSuccess,
1523                        new ArrayList<WifiDebugRxPacketFateReport>(Arrays.asList(fateReport)));
1524            }
1525        }).when(mIWifiStaIface)
1526                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1527
1528        WifiNative.RxFateReport[] retrievedFates = new WifiNative.RxFateReport[1];
1529        assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
1530        verify(mIWifiStaIface, never())
1531                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1532
1533        assertTrue(mWifiVendorHal.startVendorHalSta());
1534
1535        assertTrue(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
1536        verify(mIWifiStaIface)
1537                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1538        assertEquals(WifiLoggerHal.RX_PKT_FATE_SUCCESS, retrievedFates[0].mFate);
1539        assertEquals(fateReport.frameInfo.driverTimestampUsec,
1540                retrievedFates[0].mDriverTimestampUSec);
1541        assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, retrievedFates[0].mFrameType);
1542        assertArrayEquals(frameContentBytes, retrievedFates[0].mFrameBytes);
1543    }
1544
1545    /**
1546     * Tests the retrieval of rx packet fates when the number of fates retrieved exceeds the
1547     * input array.
1548     *
1549     * Try once before hal start, and once after.
1550     */
1551    @Test
1552    public void testGetRxPktFatesExceedsInputArrayLength() throws Exception {
1553        byte[] frameContentBytes = new byte[30];
1554        new Random().nextBytes(frameContentBytes);
1555        WifiDebugRxPacketFateReport fateReport = new WifiDebugRxPacketFateReport();
1556        fateReport.fate = WifiDebugRxPacketFate.FW_DROP_FILTER;
1557        fateReport.frameInfo.driverTimestampUsec = new Random().nextLong();
1558        fateReport.frameInfo.frameType = WifiDebugPacketFateFrameType.MGMT_80211;
1559        fateReport.frameInfo.frameContent.addAll(
1560                NativeUtil.byteArrayToArrayList(frameContentBytes));
1561
1562        doAnswer(new AnswerWithArguments() {
1563            public void answer(IWifiStaIface.getDebugRxPacketFatesCallback cb) {
1564                cb.onValues(mWifiStatusSuccess,
1565                        new ArrayList<WifiDebugRxPacketFateReport>(Arrays.asList(
1566                                fateReport, fateReport)));
1567            }
1568        }).when(mIWifiStaIface)
1569                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1570
1571        WifiNative.RxFateReport[] retrievedFates = new WifiNative.RxFateReport[1];
1572        assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
1573        verify(mIWifiStaIface, never())
1574                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1575
1576        assertTrue(mWifiVendorHal.startVendorHalSta());
1577
1578        assertTrue(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
1579        verify(mIWifiStaIface)
1580                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1581        assertEquals(WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER, retrievedFates[0].mFate);
1582        assertEquals(fateReport.frameInfo.driverTimestampUsec,
1583                retrievedFates[0].mDriverTimestampUSec);
1584        assertEquals(WifiLoggerHal.FRAME_TYPE_80211_MGMT, retrievedFates[0].mFrameType);
1585        assertArrayEquals(frameContentBytes, retrievedFates[0].mFrameBytes);
1586    }
1587
1588    /**
1589     * Tests the failure to retrieve tx packet fates when the input array is empty.
1590     */
1591    @Test
1592    public void testGetTxPktFatesEmptyInputArray() throws Exception {
1593        assertTrue(mWifiVendorHal.startVendorHalSta());
1594        assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, new WifiNative.TxFateReport[0]));
1595        verify(mIWifiStaIface, never())
1596                .getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
1597    }
1598
1599    /**
1600     * Tests the failure to retrieve rx packet fates when the input array is empty.
1601     */
1602    @Test
1603    public void testGetRxPktFatesEmptyInputArray() throws Exception {
1604        assertTrue(mWifiVendorHal.startVendorHalSta());
1605        assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, new WifiNative.RxFateReport[0]));
1606        verify(mIWifiStaIface, never())
1607                .getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
1608    }
1609
1610    /**
1611     * Tests the nd offload enable/disable.
1612     */
1613    @Test
1614    public void testEnableDisableNdOffload() throws Exception {
1615        when(mIWifiStaIface.enableNdOffload(anyBoolean())).thenReturn(mWifiStatusSuccess);
1616
1617        assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
1618        verify(mIWifiStaIface, never()).enableNdOffload(anyBoolean());
1619
1620        assertTrue(mWifiVendorHal.startVendorHalSta());
1621
1622        assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
1623        verify(mIWifiStaIface).enableNdOffload(eq(true));
1624        assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, false));
1625        verify(mIWifiStaIface).enableNdOffload(eq(false));
1626    }
1627
1628    /**
1629     * Tests the nd offload enable failure.
1630     */
1631    @Test
1632    public void testEnableNdOffloadFailure() throws Exception {
1633        when(mIWifiStaIface.enableNdOffload(eq(true))).thenReturn(mWifiStatusFailure);
1634
1635        assertTrue(mWifiVendorHal.startVendorHalSta());
1636
1637        assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
1638        verify(mIWifiStaIface).enableNdOffload(eq(true));
1639    }
1640
1641    /**
1642     * Tests the retrieval of wlan wake reason stats.
1643     */
1644    @Test
1645    public void testGetWlanWakeReasonCount() throws Exception {
1646        WifiDebugHostWakeReasonStats stats = new WifiDebugHostWakeReasonStats();
1647        Random rand = new Random();
1648        stats.totalCmdEventWakeCnt = rand.nextInt();
1649        stats.totalDriverFwLocalWakeCnt = rand.nextInt();
1650        stats.totalRxPacketWakeCnt = rand.nextInt();
1651        stats.rxPktWakeDetails.rxUnicastCnt = rand.nextInt();
1652        stats.rxPktWakeDetails.rxMulticastCnt = rand.nextInt();
1653        stats.rxIcmpPkWakeDetails.icmpPkt = rand.nextInt();
1654        stats.rxIcmpPkWakeDetails.icmp6Pkt = rand.nextInt();
1655        stats.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt = rand.nextInt();
1656        stats.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt = rand.nextInt();
1657
1658        doAnswer(new AnswerWithArguments() {
1659            public void answer(IWifiChip.getDebugHostWakeReasonStatsCallback cb) {
1660                cb.onValues(mWifiStatusSuccess, stats);
1661            }
1662        }).when(mIWifiChip).getDebugHostWakeReasonStats(
1663                any(IWifiChip.getDebugHostWakeReasonStatsCallback.class));
1664
1665        assertNull(mWifiVendorHal.getWlanWakeReasonCount());
1666        verify(mIWifiChip, never())
1667                .getDebugHostWakeReasonStats(
1668                        any(IWifiChip.getDebugHostWakeReasonStatsCallback.class));
1669
1670        assertTrue(mWifiVendorHal.startVendorHalSta());
1671
1672        WifiWakeReasonAndCounts retrievedStats = mWifiVendorHal.getWlanWakeReasonCount();
1673        verify(mIWifiChip).getDebugHostWakeReasonStats(
1674                any(IWifiChip.getDebugHostWakeReasonStatsCallback.class));
1675        assertNotNull(retrievedStats);
1676        assertEquals(stats.totalCmdEventWakeCnt, retrievedStats.totalCmdEventWake);
1677        assertEquals(stats.totalDriverFwLocalWakeCnt, retrievedStats.totalDriverFwLocalWake);
1678        assertEquals(stats.totalRxPacketWakeCnt, retrievedStats.totalRxDataWake);
1679        assertEquals(stats.rxPktWakeDetails.rxUnicastCnt, retrievedStats.rxUnicast);
1680        assertEquals(stats.rxPktWakeDetails.rxMulticastCnt, retrievedStats.rxMulticast);
1681        assertEquals(stats.rxIcmpPkWakeDetails.icmpPkt, retrievedStats.icmp);
1682        assertEquals(stats.rxIcmpPkWakeDetails.icmp6Pkt, retrievedStats.icmp6);
1683        assertEquals(stats.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt,
1684                retrievedStats.ipv4RxMulticast);
1685        assertEquals(stats.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt,
1686                retrievedStats.ipv6Multicast);
1687    }
1688
1689    /**
1690     * Tests the failure in retrieval of wlan wake reason stats.
1691     */
1692    @Test
1693    public void testGetWlanWakeReasonCountFailure() throws Exception {
1694        doAnswer(new AnswerWithArguments() {
1695            public void answer(IWifiChip.getDebugHostWakeReasonStatsCallback cb) {
1696                cb.onValues(mWifiStatusFailure, new WifiDebugHostWakeReasonStats());
1697            }
1698        }).when(mIWifiChip).getDebugHostWakeReasonStats(
1699                any(IWifiChip.getDebugHostWakeReasonStatsCallback.class));
1700
1701        // This should work in both AP & STA mode.
1702        assertTrue(mWifiVendorHal.startVendorHalAp());
1703
1704        assertNull(mWifiVendorHal.getWlanWakeReasonCount());
1705        verify(mIWifiChip).getDebugHostWakeReasonStats(
1706                any(IWifiChip.getDebugHostWakeReasonStatsCallback.class));
1707    }
1708
1709    /**
1710     * Test that getFwMemoryDump is properly plumbed
1711     */
1712    @Test
1713    public void testGetFwMemoryDump() throws Exception {
1714        byte [] sample = NativeUtil.hexStringToByteArray("268c7a3fbfa4661c0bdd6a36");
1715        ArrayList<Byte> halBlob = NativeUtil.byteArrayToArrayList(sample);
1716
1717        doAnswer(new AnswerWithArguments() {
1718            public void answer(IWifiChip.requestFirmwareDebugDumpCallback cb)
1719                    throws RemoteException {
1720                cb.onValues(mWifiStatusSuccess, halBlob);
1721            }
1722        }).when(mIWifiChip).requestFirmwareDebugDump(any(
1723                IWifiChip.requestFirmwareDebugDumpCallback.class));
1724
1725        assertTrue(mWifiVendorHal.startVendorHalSta());
1726        assertArrayEquals(sample, mWifiVendorHal.getFwMemoryDump());
1727    }
1728
1729    /**
1730     * Test that getDriverStateDump is properly plumbed
1731     *
1732     * Just for variety, use AP mode here.
1733     */
1734    @Test
1735    public void testGetDriverStateDump() throws Exception {
1736        byte [] sample = NativeUtil.hexStringToByteArray("e83ff543cf80083e6459d20f");
1737        ArrayList<Byte> halBlob = NativeUtil.byteArrayToArrayList(sample);
1738
1739        doAnswer(new AnswerWithArguments() {
1740            public void answer(IWifiChip.requestDriverDebugDumpCallback cb)
1741                    throws RemoteException {
1742                cb.onValues(mWifiStatusSuccess, halBlob);
1743            }
1744        }).when(mIWifiChip).requestDriverDebugDump(any(
1745                IWifiChip.requestDriverDebugDumpCallback.class));
1746
1747        assertTrue(mWifiVendorHal.startVendorHalAp());
1748        assertArrayEquals(sample, mWifiVendorHal.getDriverStateDump());
1749    }
1750
1751    /**
1752     * Test that background scan failure is handled correctly.
1753     */
1754    @Test
1755    public void testBgScanFailureCallback() throws Exception {
1756        assertTrue(mWifiVendorHal.startVendorHalSta());
1757        assertNotNull(mIWifiStaIfaceEventCallback);
1758
1759        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1760        startBgScan(eventHandler);
1761
1762        mIWifiStaIfaceEventCallback.onBackgroundScanFailure(mWifiVendorHal.mScan.cmdId);
1763        verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
1764    }
1765
1766    /**
1767     * Test that background scan failure with wrong id is not reported.
1768     */
1769    @Test
1770    public void testBgScanFailureCallbackWithInvalidCmdId() throws Exception {
1771        assertTrue(mWifiVendorHal.startVendorHalSta());
1772        assertNotNull(mIWifiStaIfaceEventCallback);
1773
1774        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1775        startBgScan(eventHandler);
1776
1777        mIWifiStaIfaceEventCallback.onBackgroundScanFailure(mWifiVendorHal.mScan.cmdId + 1);
1778        verify(eventHandler, never()).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
1779    }
1780
1781    /**
1782     * Test that background scan full results are handled correctly.
1783     */
1784    @Test
1785    public void testBgScanFullScanResults() throws Exception {
1786        assertTrue(mWifiVendorHal.startVendorHalSta());
1787        assertNotNull(mIWifiStaIfaceEventCallback);
1788
1789        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1790        startBgScan(eventHandler);
1791
1792        Pair<StaScanResult, ScanResult> result = createHidlAndFrameworkBgScanResult();
1793        mIWifiStaIfaceEventCallback.onBackgroundFullScanResult(
1794                mWifiVendorHal.mScan.cmdId, 5, result.first);
1795
1796        ArgumentCaptor<ScanResult> scanResultCaptor = ArgumentCaptor.forClass(ScanResult.class);
1797        verify(eventHandler).onFullScanResult(scanResultCaptor.capture(), eq(5));
1798
1799        assertScanResultEqual(result.second, scanResultCaptor.getValue());
1800    }
1801
1802    /**
1803     * Test that background scan results are handled correctly.
1804     */
1805    @Test
1806    public void testBgScanScanResults() throws Exception {
1807        assertTrue(mWifiVendorHal.startVendorHalSta());
1808        assertNotNull(mIWifiStaIfaceEventCallback);
1809
1810        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1811        startBgScan(eventHandler);
1812
1813        Pair<ArrayList<StaScanData>, ArrayList<WifiScanner.ScanData>> data =
1814                createHidlAndFrameworkBgScanDatas();
1815        mIWifiStaIfaceEventCallback.onBackgroundScanResults(
1816                mWifiVendorHal.mScan.cmdId, data.first);
1817
1818        verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1819        assertScanDatasEqual(
1820                data.second, Arrays.asList(mWifiVendorHal.mScan.latestScanResults));
1821    }
1822
1823    /**
1824     * Test that starting a new background scan when one is active will stop the previous one.
1825     */
1826    @Test
1827    public void testBgScanReplacement() throws Exception {
1828        when(mIWifiStaIface.stopBackgroundScan(anyInt())).thenReturn(mWifiStatusSuccess);
1829        assertTrue(mWifiVendorHal.startVendorHalSta());
1830        assertNotNull(mIWifiStaIfaceEventCallback);
1831        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1832        startBgScan(eventHandler);
1833        int cmdId1 = mWifiVendorHal.mScan.cmdId;
1834        startBgScan(eventHandler);
1835        assertNotEquals(mWifiVendorHal.mScan.cmdId, cmdId1);
1836        verify(mIWifiStaIface, times(2)).startBackgroundScan(anyInt(), any());
1837        verify(mIWifiStaIface).stopBackgroundScan(cmdId1);
1838    }
1839
1840    /**
1841     * Test stopping a background scan.
1842     */
1843    @Test
1844    public void testBgScanStop() throws Exception {
1845        when(mIWifiStaIface.stopBackgroundScan(anyInt())).thenReturn(mWifiStatusSuccess);
1846        assertTrue(mWifiVendorHal.startVendorHalSta());
1847        assertNotNull(mIWifiStaIfaceEventCallback);
1848        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1849        startBgScan(eventHandler);
1850
1851        int cmdId = mWifiVendorHal.mScan.cmdId;
1852
1853        mWifiVendorHal.stopBgScan(TEST_IFACE_NAME);
1854        mWifiVendorHal.stopBgScan(TEST_IFACE_NAME); // second call should not do anything
1855        verify(mIWifiStaIface).stopBackgroundScan(cmdId); // Should be called just once
1856    }
1857
1858    /**
1859     * Test pausing and restarting a background scan.
1860     */
1861    @Test
1862    public void testBgScanPauseAndRestart() throws Exception {
1863        when(mIWifiStaIface.stopBackgroundScan(anyInt())).thenReturn(mWifiStatusSuccess);
1864        assertTrue(mWifiVendorHal.startVendorHalSta());
1865        assertNotNull(mIWifiStaIfaceEventCallback);
1866        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
1867        startBgScan(eventHandler);
1868
1869        int cmdId = mWifiVendorHal.mScan.cmdId;
1870
1871        mWifiVendorHal.pauseBgScan(TEST_IFACE_NAME);
1872        mWifiVendorHal.restartBgScan(TEST_IFACE_NAME);
1873        verify(mIWifiStaIface).stopBackgroundScan(cmdId); // Should be called just once
1874        verify(mIWifiStaIface, times(2)).startBackgroundScan(eq(cmdId), any());
1875    }
1876
1877    /**
1878     * Test the handling of log handler set.
1879     */
1880    @Test
1881    public void testSetLogHandler() throws Exception {
1882        when(mIWifiChip.enableDebugErrorAlerts(anyBoolean())).thenReturn(mWifiStatusSuccess);
1883
1884        WifiNative.WifiLoggerEventHandler eventHandler =
1885                mock(WifiNative.WifiLoggerEventHandler.class);
1886
1887        assertFalse(mWifiVendorHal.setLoggingEventHandler(eventHandler));
1888        verify(mIWifiChip, never()).enableDebugErrorAlerts(anyBoolean());
1889
1890        assertTrue(mWifiVendorHal.startVendorHalSta());
1891
1892        assertTrue(mWifiVendorHal.setLoggingEventHandler(eventHandler));
1893        verify(mIWifiChip).enableDebugErrorAlerts(eq(true));
1894        reset(mIWifiChip);
1895
1896        // Second call should fail.
1897        assertFalse(mWifiVendorHal.setLoggingEventHandler(eventHandler));
1898        verify(mIWifiChip, never()).enableDebugErrorAlerts(anyBoolean());
1899    }
1900
1901    /**
1902     * Test the handling of log handler reset.
1903     */
1904    @Test
1905    public void testResetLogHandler() throws Exception {
1906        when(mIWifiChip.enableDebugErrorAlerts(anyBoolean())).thenReturn(mWifiStatusSuccess);
1907        when(mIWifiChip.stopLoggingToDebugRingBuffer()).thenReturn(mWifiStatusSuccess);
1908
1909        assertFalse(mWifiVendorHal.resetLogHandler());
1910        verify(mIWifiChip, never()).enableDebugErrorAlerts(anyBoolean());
1911        verify(mIWifiChip, never()).stopLoggingToDebugRingBuffer();
1912
1913        assertTrue(mWifiVendorHal.startVendorHalSta());
1914
1915        // Not set, so this should fail.
1916        assertFalse(mWifiVendorHal.resetLogHandler());
1917        verify(mIWifiChip, never()).enableDebugErrorAlerts(anyBoolean());
1918        verify(mIWifiChip, never()).stopLoggingToDebugRingBuffer();
1919
1920        // Now set and then reset.
1921        assertTrue(mWifiVendorHal.setLoggingEventHandler(
1922                mock(WifiNative.WifiLoggerEventHandler.class)));
1923        assertTrue(mWifiVendorHal.resetLogHandler());
1924        verify(mIWifiChip).enableDebugErrorAlerts(eq(false));
1925        verify(mIWifiChip).stopLoggingToDebugRingBuffer();
1926        reset(mIWifiChip);
1927
1928        // Second reset should fail.
1929        assertFalse(mWifiVendorHal.resetLogHandler());
1930        verify(mIWifiChip, never()).enableDebugErrorAlerts(anyBoolean());
1931        verify(mIWifiChip, never()).stopLoggingToDebugRingBuffer();
1932    }
1933
1934    /**
1935     * Test the handling of alert callback.
1936     */
1937    @Test
1938    public void testAlertCallback() throws Exception {
1939        assertTrue(mWifiVendorHal.startVendorHalSta());
1940        assertNotNull(mIWifiChipEventCallback);
1941
1942        testAlertCallbackUsingProvidedCallback(mIWifiChipEventCallback);
1943    }
1944
1945    /**
1946     * Test the handling of ring buffer callback.
1947     */
1948    @Test
1949    public void testRingBufferDataCallback() throws Exception {
1950        when(mIWifiChip.enableDebugErrorAlerts(anyBoolean())).thenReturn(mWifiStatusSuccess);
1951        when(mIWifiChip.stopLoggingToDebugRingBuffer()).thenReturn(mWifiStatusSuccess);
1952
1953        assertTrue(mWifiVendorHal.startVendorHalSta());
1954        assertNotNull(mIWifiChipEventCallback);
1955
1956        byte[] errorData = new byte[45];
1957        new Random().nextBytes(errorData);
1958
1959        // Randomly raise the HIDL callback before we register for the log callback.
1960        // This should be safely ignored. (Not trigger NPE.)
1961        mIWifiChipEventCallback.onDebugRingBufferDataAvailable(
1962                new WifiDebugRingBufferStatus(), NativeUtil.byteArrayToArrayList(errorData));
1963        mLooper.dispatchAll();
1964
1965        WifiNative.WifiLoggerEventHandler eventHandler =
1966                mock(WifiNative.WifiLoggerEventHandler.class);
1967        assertTrue(mWifiVendorHal.setLoggingEventHandler(eventHandler));
1968        verify(mIWifiChip).enableDebugErrorAlerts(eq(true));
1969
1970        // Now raise the HIDL callback, this should be properly handled.
1971        mIWifiChipEventCallback.onDebugRingBufferDataAvailable(
1972                new WifiDebugRingBufferStatus(), NativeUtil.byteArrayToArrayList(errorData));
1973        mLooper.dispatchAll();
1974        verify(eventHandler).onRingBufferData(
1975                any(WifiNative.RingBufferStatus.class), eq(errorData));
1976
1977        // Now stop the logging and invoke the callback. This should be ignored.
1978        reset(eventHandler);
1979        assertTrue(mWifiVendorHal.resetLogHandler());
1980        mIWifiChipEventCallback.onDebugRingBufferDataAvailable(
1981                new WifiDebugRingBufferStatus(), NativeUtil.byteArrayToArrayList(errorData));
1982        mLooper.dispatchAll();
1983        verify(eventHandler, never()).onRingBufferData(anyObject(), anyObject());
1984    }
1985
1986    /**
1987     * Test the handling of Vendor HAL death.
1988     */
1989    @Test
1990    public void testVendorHalDeath() {
1991        // Invoke the HAL device manager status callback with ready set to false to indicate the
1992        // death of the HAL.
1993        when(mHalDeviceManager.isReady()).thenReturn(false);
1994        mHalDeviceManagerStatusCallbacks.onStatusChanged();
1995
1996        verify(mVendorHalDeathHandler).onDeath();
1997    }
1998
1999    /**
2000     * Test the new selectTxPowerScenario HIDL method invocation. This should return failure if the
2001     * HAL service is exposing the 1.0 interface.
2002     */
2003    @Test
2004    public void testSelectTxPowerScenario() throws RemoteException {
2005        assertTrue(mWifiVendorHal.startVendorHalSta());
2006        // Should fail because we exposed the 1.0 IWifiChip.
2007        assertFalse(
2008                mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2009        verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
2010        mWifiVendorHal.stopVendorHal();
2011
2012        // Now expose the 1.1 IWifiChip.
2013        mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
2014        when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
2015
2016        assertTrue(mWifiVendorHal.startVendorHalSta());
2017        assertTrue(
2018                mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
2019        verify(mIWifiChipV11).selectTxPowerScenario(
2020                eq(android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL));
2021        verify(mIWifiChipV11, never()).resetTxPowerScenario();
2022        mWifiVendorHal.stopVendorHal();
2023    }
2024
2025    /**
2026     * Test the new resetTxPowerScenario HIDL method invocation. This should return failure if the
2027     * HAL service is exposing the 1.0 interface.
2028     */
2029    @Test
2030    public void testResetTxPowerScenario() throws RemoteException {
2031        assertTrue(mWifiVendorHal.startVendorHalSta());
2032        // Should fail because we exposed the 1.0 IWifiChip.
2033        assertFalse(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
2034        verify(mIWifiChipV11, never()).resetTxPowerScenario();
2035        mWifiVendorHal.stopVendorHal();
2036
2037        // Now expose the 1.1 IWifiChip.
2038        mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
2039        when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
2040
2041        assertTrue(mWifiVendorHal.startVendorHalSta());
2042        assertTrue(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
2043        verify(mIWifiChipV11).resetTxPowerScenario();
2044        verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
2045        mWifiVendorHal.stopVendorHal();
2046    }
2047
2048    /**
2049     * Test the new selectTxPowerScenario HIDL method invocation with a bad scenario index.
2050     */
2051    @Test
2052    public void testInvalidSelectTxPowerScenario() throws RemoteException {
2053        // Expose the 1.1 IWifiChip.
2054        mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
2055        when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
2056
2057        assertTrue(mWifiVendorHal.startVendorHalSta());
2058        assertFalse(mWifiVendorHal.selectTxPowerScenario(-6));
2059        verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
2060        verify(mIWifiChipV11, never()).resetTxPowerScenario();
2061        mWifiVendorHal.stopVendorHal();
2062    }
2063
2064    /**
2065     * Test the STA Iface creation failure due to iface name retrieval failure.
2066     */
2067    @Test
2068    public void testCreateStaIfaceFailureInIfaceName() throws RemoteException {
2069        doAnswer(new AnswerWithArguments() {
2070            public void answer(IWifiIface.getNameCallback cb)
2071                    throws RemoteException {
2072                cb.onValues(mWifiStatusFailure, "wlan0");
2073            }
2074        }).when(mIWifiStaIface).getName(any(IWifiIface.getNameCallback.class));
2075
2076        assertTrue(mWifiVendorHal.startVendorHal());
2077        assertNull(mWifiVendorHal.createStaIface(true, null));
2078        verify(mHalDeviceManager).createStaIface(eq(true), any(), eq(null));
2079    }
2080
2081    /**
2082     * Test the STA Iface creation failure due to iface name retrieval failure.
2083     */
2084    @Test
2085    public void testCreateApIfaceFailureInIfaceName() throws RemoteException {
2086        doAnswer(new AnswerWithArguments() {
2087            public void answer(IWifiIface.getNameCallback cb)
2088                    throws RemoteException {
2089                cb.onValues(mWifiStatusFailure, "wlan0");
2090            }
2091        }).when(mIWifiApIface).getName(any(IWifiIface.getNameCallback.class));
2092
2093        assertTrue(mWifiVendorHal.startVendorHal());
2094        assertNull(mWifiVendorHal.createApIface(null));
2095        verify(mHalDeviceManager).createApIface(any(), eq(null));
2096    }
2097
2098    /**
2099     * Test the creation and removal of STA Iface.
2100     */
2101    @Test
2102    public void testCreateRemoveStaIface() throws RemoteException {
2103        assertTrue(mWifiVendorHal.startVendorHal());
2104        String ifaceName = mWifiVendorHal.createStaIface(false, null);
2105        verify(mHalDeviceManager).createStaIface(eq(false), any(), eq(null));
2106        assertEquals(TEST_IFACE_NAME, ifaceName);
2107        assertTrue(mWifiVendorHal.removeStaIface(ifaceName));
2108        verify(mHalDeviceManager).removeIface(eq(mIWifiStaIface));
2109    }
2110
2111    /**
2112     * Test the creation and removal of Ap Iface.
2113     */
2114    @Test
2115    public void testCreateRemoveApIface() throws RemoteException {
2116        assertTrue(mWifiVendorHal.startVendorHal());
2117        String ifaceName = mWifiVendorHal.createApIface(null);
2118        verify(mHalDeviceManager).createApIface(any(), eq(null));
2119        assertEquals(TEST_IFACE_NAME, ifaceName);
2120        assertTrue(mWifiVendorHal.removeApIface(ifaceName));
2121        verify(mHalDeviceManager).removeIface(eq(mIWifiApIface));
2122    }
2123
2124    /**
2125     * Test the callback handling for the 1.2 HAL.
2126     */
2127    @Test
2128    public void testAlertCallbackUsing_1_2_EventCallback() throws Exception {
2129        // Expose the 1.2 IWifiChip.
2130        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
2131
2132        assertTrue(mWifiVendorHal.startVendorHalSta());
2133        assertNotNull(mIWifiChipEventCallbackV12);
2134
2135        testAlertCallbackUsingProvidedCallback(mIWifiChipEventCallbackV12);
2136    }
2137
2138    /**
2139     * Verifies setMacAddress() success.
2140     */
2141    @Test
2142    public void testSetMacAddressSuccess() throws Exception {
2143        // Expose the 1.2 IWifiStaIface.
2144        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
2145        byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
2146        when(mIWifiStaIfaceV12.setMacAddress(macByteArray)).thenReturn(mWifiStatusSuccess);
2147
2148        assertTrue(mWifiVendorHal.setMacAddress(TEST_IFACE_NAME, TEST_MAC_ADDRESS));
2149        verify(mIWifiStaIfaceV12).setMacAddress(macByteArray);
2150    }
2151
2152    /**
2153     * Verifies setMacAddress() can handle failure status.
2154     */
2155    @Test
2156    public void testSetMacAddressFailDueToStatusFailure() throws Exception {
2157        // Expose the 1.2 IWifiStaIface.
2158        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
2159        byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
2160        when(mIWifiStaIfaceV12.setMacAddress(macByteArray)).thenReturn(mWifiStatusFailure);
2161
2162        assertFalse(mWifiVendorHal.setMacAddress(TEST_IFACE_NAME, TEST_MAC_ADDRESS));
2163        verify(mIWifiStaIfaceV12).setMacAddress(macByteArray);
2164    }
2165
2166    /**
2167     * Verifies setMacAddress() can handle RemoteException.
2168     */
2169    @Test
2170    public void testSetMacAddressFailDueToRemoteException() throws Exception {
2171        // Expose the 1.2 IWifiStaIface.
2172        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
2173        byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
2174        doThrow(new RemoteException()).when(mIWifiStaIfaceV12).setMacAddress(macByteArray);
2175
2176        assertFalse(mWifiVendorHal.setMacAddress(TEST_IFACE_NAME, TEST_MAC_ADDRESS));
2177        verify(mIWifiStaIfaceV12).setMacAddress(macByteArray);
2178    }
2179
2180    /**
2181     * Verifies setMacAddress() does not crash with older HALs.
2182     */
2183    @Test
2184    public void testSetMacAddressDoesNotCrashOnOlderHal() throws Exception {
2185        byte[] macByteArray = TEST_MAC_ADDRESS.toByteArray();
2186        assertFalse(mWifiVendorHal.setMacAddress(TEST_IFACE_NAME, TEST_MAC_ADDRESS));
2187    }
2188
2189    /**
2190     * Verifies radio mode change callback to indicate DBS mode.
2191     */
2192    @Test
2193    public void testRadioModeChangeCallbackToDbsMode() throws Exception {
2194        startHalInStaModeAndRegisterRadioModeChangeCallback();
2195
2196        RadioModeInfo radioModeInfo0 = new RadioModeInfo();
2197        radioModeInfo0.bandInfo = WifiScanner.WIFI_BAND_5_GHZ;
2198        RadioModeInfo radioModeInfo1 = new RadioModeInfo();
2199        radioModeInfo1.bandInfo = WifiScanner.WIFI_BAND_24_GHZ;
2200
2201        IfaceInfo ifaceInfo0 = new IfaceInfo();
2202        ifaceInfo0.name = TEST_IFACE_NAME;
2203        ifaceInfo0.channel = 34;
2204        IfaceInfo ifaceInfo1 = new IfaceInfo();
2205        ifaceInfo1.name = TEST_IFACE_NAME_1;
2206        ifaceInfo1.channel = 1;
2207
2208        radioModeInfo0.ifaceInfos.add(ifaceInfo0);
2209        radioModeInfo1.ifaceInfos.add(ifaceInfo1);
2210
2211        ArrayList<RadioModeInfo> radioModeInfos = new ArrayList<>();
2212        radioModeInfos.add(radioModeInfo0);
2213        radioModeInfos.add(radioModeInfo1);
2214
2215        mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfos);
2216        verify(mVendorHalRadioModeChangeHandler).onDbs();
2217
2218        verifyNoMoreInteractions(mVendorHalRadioModeChangeHandler);
2219    }
2220
2221    /**
2222     * Verifies radio mode change callback to indicate SBS mode.
2223     */
2224    @Test
2225    public void testRadioModeChangeCallbackToSbsMode() throws Exception {
2226        startHalInStaModeAndRegisterRadioModeChangeCallback();
2227
2228        RadioModeInfo radioModeInfo0 = new RadioModeInfo();
2229        radioModeInfo0.bandInfo = WifiScanner.WIFI_BAND_5_GHZ;
2230        RadioModeInfo radioModeInfo1 = new RadioModeInfo();
2231        radioModeInfo1.bandInfo = WifiScanner.WIFI_BAND_5_GHZ;
2232
2233        IfaceInfo ifaceInfo0 = new IfaceInfo();
2234        ifaceInfo0.name = TEST_IFACE_NAME;
2235        ifaceInfo0.channel = 34;
2236        IfaceInfo ifaceInfo1 = new IfaceInfo();
2237        ifaceInfo1.name = TEST_IFACE_NAME_1;
2238        ifaceInfo1.channel = 36;
2239
2240        radioModeInfo0.ifaceInfos.add(ifaceInfo0);
2241        radioModeInfo1.ifaceInfos.add(ifaceInfo1);
2242
2243        ArrayList<RadioModeInfo> radioModeInfos = new ArrayList<>();
2244        radioModeInfos.add(radioModeInfo0);
2245        radioModeInfos.add(radioModeInfo1);
2246
2247        mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfos);
2248        verify(mVendorHalRadioModeChangeHandler).onSbs(WifiScanner.WIFI_BAND_5_GHZ);
2249
2250        verifyNoMoreInteractions(mVendorHalRadioModeChangeHandler);
2251    }
2252
2253    /**
2254     * Verifies radio mode change callback to indicate SCC mode.
2255     */
2256    @Test
2257    public void testRadioModeChangeCallbackToSccMode() throws Exception {
2258        startHalInStaModeAndRegisterRadioModeChangeCallback();
2259
2260        RadioModeInfo radioModeInfo0 = new RadioModeInfo();
2261        radioModeInfo0.bandInfo = WifiScanner.WIFI_BAND_5_GHZ;
2262
2263        IfaceInfo ifaceInfo0 = new IfaceInfo();
2264        ifaceInfo0.name = TEST_IFACE_NAME;
2265        ifaceInfo0.channel = 34;
2266        IfaceInfo ifaceInfo1 = new IfaceInfo();
2267        ifaceInfo1.name = TEST_IFACE_NAME_1;
2268        ifaceInfo1.channel = 34;
2269
2270        radioModeInfo0.ifaceInfos.add(ifaceInfo0);
2271        radioModeInfo0.ifaceInfos.add(ifaceInfo1);
2272
2273        ArrayList<RadioModeInfo> radioModeInfos = new ArrayList<>();
2274        radioModeInfos.add(radioModeInfo0);
2275
2276        mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfos);
2277        verify(mVendorHalRadioModeChangeHandler).onScc(WifiScanner.WIFI_BAND_5_GHZ);
2278
2279        verifyNoMoreInteractions(mVendorHalRadioModeChangeHandler);
2280    }
2281
2282    /**
2283     * Verifies radio mode change callback to indicate MCC mode.
2284     */
2285    @Test
2286    public void testRadioModeChangeCallbackToMccMode() throws Exception {
2287        startHalInStaModeAndRegisterRadioModeChangeCallback();
2288
2289        RadioModeInfo radioModeInfo0 = new RadioModeInfo();
2290        radioModeInfo0.bandInfo = WifiScanner.WIFI_BAND_BOTH;
2291
2292        IfaceInfo ifaceInfo0 = new IfaceInfo();
2293        ifaceInfo0.name = TEST_IFACE_NAME;
2294        ifaceInfo0.channel = 1;
2295        IfaceInfo ifaceInfo1 = new IfaceInfo();
2296        ifaceInfo1.name = TEST_IFACE_NAME_1;
2297        ifaceInfo1.channel = 36;
2298
2299        radioModeInfo0.ifaceInfos.add(ifaceInfo0);
2300        radioModeInfo0.ifaceInfos.add(ifaceInfo1);
2301
2302        ArrayList<RadioModeInfo> radioModeInfos = new ArrayList<>();
2303        radioModeInfos.add(radioModeInfo0);
2304
2305        mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfos);
2306        verify(mVendorHalRadioModeChangeHandler).onMcc(WifiScanner.WIFI_BAND_BOTH);
2307
2308        verifyNoMoreInteractions(mVendorHalRadioModeChangeHandler);
2309    }
2310
2311    /**
2312     * Verifies radio mode change callback error cases.
2313     */
2314    @Test
2315    public void testRadioModeChangeCallbackErrorSimultaneousWithSameIfaceOnBothRadios()
2316            throws Exception {
2317        startHalInStaModeAndRegisterRadioModeChangeCallback();
2318
2319        RadioModeInfo radioModeInfo0 = new RadioModeInfo();
2320        radioModeInfo0.bandInfo = WifiScanner.WIFI_BAND_24_GHZ;
2321        RadioModeInfo radioModeInfo1 = new RadioModeInfo();
2322        radioModeInfo1.bandInfo = WifiScanner.WIFI_BAND_5_GHZ;
2323
2324        IfaceInfo ifaceInfo0 = new IfaceInfo();
2325        ifaceInfo0.name = TEST_IFACE_NAME;
2326        ifaceInfo0.channel = 34;
2327
2328        radioModeInfo0.ifaceInfos.add(ifaceInfo0);
2329        radioModeInfo1.ifaceInfos.add(ifaceInfo0);
2330
2331        ArrayList<RadioModeInfo> radioModeInfos = new ArrayList<>();
2332        radioModeInfos.add(radioModeInfo0);
2333        radioModeInfos.add(radioModeInfo1);
2334
2335        mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfos);
2336        // Ignored....
2337
2338        verifyNoMoreInteractions(mVendorHalRadioModeChangeHandler);
2339    }
2340
2341    private void startHalInStaModeAndRegisterRadioModeChangeCallback() {
2342        // Expose the 1.2 IWifiChip.
2343        mWifiVendorHal = new WifiVendorHalSpyV1_2(mHalDeviceManager, mLooper.getLooper());
2344        mWifiVendorHal.registerRadioModeChangeHandler(mVendorHalRadioModeChangeHandler);
2345        assertTrue(mWifiVendorHal.startVendorHalSta());
2346        assertNotNull(mIWifiChipEventCallbackV12);
2347    }
2348
2349    private void testAlertCallbackUsingProvidedCallback(IWifiChipEventCallback chipCallback)
2350            throws Exception {
2351        when(mIWifiChip.enableDebugErrorAlerts(anyBoolean())).thenReturn(mWifiStatusSuccess);
2352        when(mIWifiChip.stopLoggingToDebugRingBuffer()).thenReturn(mWifiStatusSuccess);
2353
2354        int errorCode = 5;
2355        byte[] errorData = new byte[45];
2356        new Random().nextBytes(errorData);
2357
2358        // Randomly raise the HIDL callback before we register for the log callback.
2359        // This should be safely ignored. (Not trigger NPE.)
2360        chipCallback.onDebugErrorAlert(
2361                errorCode, NativeUtil.byteArrayToArrayList(errorData));
2362        mLooper.dispatchAll();
2363
2364        WifiNative.WifiLoggerEventHandler eventHandler =
2365                mock(WifiNative.WifiLoggerEventHandler.class);
2366        assertTrue(mWifiVendorHal.setLoggingEventHandler(eventHandler));
2367        verify(mIWifiChip).enableDebugErrorAlerts(eq(true));
2368
2369        // Now raise the HIDL callback, this should be properly handled.
2370        chipCallback.onDebugErrorAlert(
2371                errorCode, NativeUtil.byteArrayToArrayList(errorData));
2372        mLooper.dispatchAll();
2373        verify(eventHandler).onWifiAlert(eq(errorCode), eq(errorData));
2374
2375        // Now stop the logging and invoke the callback. This should be ignored.
2376        reset(eventHandler);
2377        assertTrue(mWifiVendorHal.resetLogHandler());
2378        chipCallback.onDebugErrorAlert(
2379                errorCode, NativeUtil.byteArrayToArrayList(errorData));
2380        mLooper.dispatchAll();
2381        verify(eventHandler, never()).onWifiAlert(anyInt(), anyObject());
2382    }
2383
2384    private void startBgScan(WifiNative.ScanEventHandler eventHandler) throws Exception {
2385        when(mIWifiStaIface.startBackgroundScan(
2386                anyInt(), any(StaBackgroundScanParameters.class))).thenReturn(mWifiStatusSuccess);
2387        WifiNative.ScanSettings settings = new WifiNative.ScanSettings();
2388        settings.num_buckets = 1;
2389        WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
2390        bucketSettings.bucket = 0;
2391        bucketSettings.period_ms = 16000;
2392        bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
2393        settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};
2394        assertTrue(mWifiVendorHal.startBgScan(TEST_IFACE_NAME, settings, eventHandler));
2395    }
2396
2397    // Create a pair of HIDL scan result and its corresponding framework scan result for
2398    // comparison.
2399    private Pair<StaScanResult, ScanResult> createHidlAndFrameworkBgScanResult() {
2400        StaScanResult staScanResult = new StaScanResult();
2401        Random random = new Random();
2402        byte[] ssid = new byte[8];
2403        random.nextBytes(ssid);
2404        staScanResult.ssid.addAll(NativeUtil.byteArrayToArrayList(ssid));
2405        random.nextBytes(staScanResult.bssid);
2406        staScanResult.frequency = 2432;
2407        staScanResult.rssi = -45;
2408        staScanResult.timeStampInUs = 5;
2409        WifiInformationElement ie1 = new WifiInformationElement();
2410        byte[] ie1_data = new byte[56];
2411        random.nextBytes(ie1_data);
2412        ie1.id = 1;
2413        ie1.data.addAll(NativeUtil.byteArrayToArrayList(ie1_data));
2414        staScanResult.informationElements.add(ie1);
2415
2416        // Now create the corresponding Scan result structure.
2417        ScanResult scanResult = new ScanResult();
2418        scanResult.SSID = NativeUtil.encodeSsid(staScanResult.ssid);
2419        scanResult.BSSID = NativeUtil.macAddressFromByteArray(staScanResult.bssid);
2420        scanResult.wifiSsid = WifiSsid.createFromByteArray(ssid);
2421        scanResult.frequency = staScanResult.frequency;
2422        scanResult.level = staScanResult.rssi;
2423        scanResult.timestamp = staScanResult.timeStampInUs;
2424
2425        return Pair.create(staScanResult, scanResult);
2426    }
2427
2428    // Create a pair of HIDL scan datas and its corresponding framework scan datas for
2429    // comparison.
2430    private Pair<ArrayList<StaScanData>, ArrayList<WifiScanner.ScanData>>
2431            createHidlAndFrameworkBgScanDatas() {
2432        ArrayList<StaScanData> staScanDatas = new ArrayList<>();
2433        StaScanData staScanData = new StaScanData();
2434
2435        Pair<StaScanResult, ScanResult> result = createHidlAndFrameworkBgScanResult();
2436        staScanData.results.add(result.first);
2437        staScanData.bucketsScanned = 5;
2438        staScanData.flags = StaScanDataFlagMask.INTERRUPTED;
2439        staScanDatas.add(staScanData);
2440
2441        ArrayList<WifiScanner.ScanData> scanDatas = new ArrayList<>();
2442        ScanResult[] scanResults = new ScanResult[1];
2443        scanResults[0] = result.second;
2444        WifiScanner.ScanData scanData =
2445                new WifiScanner.ScanData(mWifiVendorHal.mScan.cmdId, 1,
2446                        staScanData.bucketsScanned, false, scanResults);
2447        scanDatas.add(scanData);
2448        return Pair.create(staScanDatas, scanDatas);
2449    }
2450
2451    private void assertScanResultEqual(ScanResult expected, ScanResult actual) {
2452        assertEquals(expected.SSID, actual.SSID);
2453        assertEquals(expected.wifiSsid.getHexString(), actual.wifiSsid.getHexString());
2454        assertEquals(expected.BSSID, actual.BSSID);
2455        assertEquals(expected.frequency, actual.frequency);
2456        assertEquals(expected.level, actual.level);
2457        assertEquals(expected.timestamp, actual.timestamp);
2458    }
2459
2460    private void assertScanResultsEqual(ScanResult[] expected, ScanResult[] actual) {
2461        assertEquals(expected.length, actual.length);
2462        for (int i = 0; i < expected.length; i++) {
2463            assertScanResultEqual(expected[i], actual[i]);
2464        }
2465    }
2466
2467    private void assertScanDataEqual(WifiScanner.ScanData expected, WifiScanner.ScanData actual) {
2468        assertEquals(expected.getId(), actual.getId());
2469        assertEquals(expected.getFlags(), actual.getFlags());
2470        assertEquals(expected.getBucketsScanned(), actual.getBucketsScanned());
2471        assertScanResultsEqual(expected.getResults(), actual.getResults());
2472    }
2473
2474    private void assertScanDatasEqual(
2475            List<WifiScanner.ScanData> expected, List<WifiScanner.ScanData> actual) {
2476        assertEquals(expected.size(), actual.size());
2477        for (int i = 0; i < expected.size(); i++) {
2478            assertScanDataEqual(expected.get(i), actual.get(i));
2479        }
2480    }
2481}
2482