| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi; |
| |
| import static junit.framework.Assert.assertEquals; |
| |
| import static org.hamcrest.core.IsEqual.equalTo; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Matchers.anyInt; |
| import static org.mockito.Matchers.anyLong; |
| import static org.mockito.Matchers.anyString; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Mockito.doAnswer; |
| import static org.mockito.Mockito.inOrder; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.when; |
| |
| import android.app.test.MockAnswerUtil; |
| import android.hardware.wifi.V1_0.IWifi; |
| import android.hardware.wifi.V1_0.IWifiApIface; |
| import android.hardware.wifi.V1_0.IWifiChip; |
| import android.hardware.wifi.V1_0.IWifiChipEventCallback; |
| import android.hardware.wifi.V1_0.IWifiEventCallback; |
| import android.hardware.wifi.V1_0.IWifiIface; |
| import android.hardware.wifi.V1_0.IWifiNanIface; |
| import android.hardware.wifi.V1_0.IWifiP2pIface; |
| import android.hardware.wifi.V1_0.IWifiStaIface; |
| import android.hardware.wifi.V1_0.IfaceType; |
| import android.hardware.wifi.V1_0.WifiStatus; |
| import android.hardware.wifi.V1_0.WifiStatusCode; |
| import android.hidl.manager.V1_0.IServiceManager; |
| import android.hidl.manager.V1_0.IServiceNotification; |
| import android.os.IHwBinder; |
| import android.os.test.TestLooper; |
| import android.util.Log; |
| |
| import org.hamcrest.core.IsNull; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ErrorCollector; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.InOrder; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Unit test harness for HalDeviceManagerTest. |
| */ |
| public class HalDeviceManagerTest { |
| private HalDeviceManager mDut; |
| @Mock IServiceManager mServiceManagerMock; |
| @Mock IWifi mWifiMock; |
| @Mock HalDeviceManager.ManagerStatusListener mManagerStatusListenerMock; |
| private TestLooper mTestLooper; |
| private ArgumentCaptor<IHwBinder.DeathRecipient> mDeathRecipientCaptor = |
| ArgumentCaptor.forClass(IHwBinder.DeathRecipient.class); |
| private ArgumentCaptor<IServiceNotification.Stub> mServiceNotificationCaptor = |
| ArgumentCaptor.forClass(IServiceNotification.Stub.class); |
| private ArgumentCaptor<IWifiEventCallback> mWifiEventCallbackCaptor = ArgumentCaptor.forClass( |
| IWifiEventCallback.class); |
| private InOrder mInOrder; |
| @Rule public ErrorCollector collector = new ErrorCollector(); |
| private WifiStatus mStatusOk; |
| private WifiStatus mStatusFail; |
| |
| private class HalDeviceManagerSpy extends HalDeviceManager { |
| @Override |
| protected IWifi getWifiServiceMockable() { |
| return mWifiMock; |
| } |
| |
| @Override |
| protected IServiceManager getServiceManagerMockable() { |
| return mServiceManagerMock; |
| } |
| } |
| |
| @Before |
| public void before() throws Exception { |
| MockitoAnnotations.initMocks(this); |
| |
| mTestLooper = new TestLooper(); |
| |
| // initialize dummy status objects |
| mStatusOk = getStatus(WifiStatusCode.SUCCESS); |
| mStatusFail = getStatus(WifiStatusCode.ERROR_UNKNOWN); |
| |
| when(mServiceManagerMock.linkToDeath(any(IHwBinder.DeathRecipient.class), |
| anyLong())).thenReturn(true); |
| when(mServiceManagerMock.registerForNotifications(anyString(), anyString(), |
| any(IServiceNotification.Stub.class))).thenReturn(true); |
| when(mWifiMock.linkToDeath(any(IHwBinder.DeathRecipient.class), anyLong())).thenReturn( |
| true); |
| when(mWifiMock.registerEventCallback(any(IWifiEventCallback.class))).thenReturn(mStatusOk); |
| when(mWifiMock.start()).thenReturn(mStatusOk); |
| when(mWifiMock.stop()).thenReturn(mStatusOk); |
| |
| mDut = new HalDeviceManagerSpy(); |
| } |
| |
| /** |
| * Print out the dump of the device manager after each test. Not used in test validation |
| * (internal state) - but can help in debugging failed tests. |
| */ |
| @After |
| public void after() throws Exception { |
| dumpDut("after: "); |
| } |
| |
| /** |
| * Test basic startup flow: |
| * - IServiceManager registrations |
| * - IWifi registrations |
| * - IWifi startup delayed |
| * - Start Wi-Fi -> onStart |
| * - Stop Wi-Fi -> onStop |
| */ |
| @Test |
| public void testStartStopFlow() throws Exception { |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| // act: stop Wi-Fi |
| mDut.stop(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: onStop called |
| mInOrder.verify(mWifiMock).stop(); |
| mInOrder.verify(mManagerStatusListenerMock).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock); |
| } |
| |
| /** |
| * Validate that multiple callback registrations are called and that duplicate ones are |
| * only called once. |
| */ |
| @Test |
| public void testMultipleCallbackRegistrations() throws Exception { |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| |
| // register another 2 callbacks - one of them twice |
| HalDeviceManager.ManagerStatusListener callback1 = mock( |
| HalDeviceManager.ManagerStatusListener.class); |
| HalDeviceManager.ManagerStatusListener callback2 = mock( |
| HalDeviceManager.ManagerStatusListener.class); |
| mDut.registerStatusListener(callback2, mTestLooper.getLooper()); |
| mDut.registerStatusListener(callback1, mTestLooper.getLooper()); |
| mDut.registerStatusListener(callback2, mTestLooper.getLooper()); |
| |
| // startup |
| executeAndValidateStartupSequence(); |
| |
| // verify |
| verify(callback1).onStatusChanged(); |
| verify(callback2).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, callback1, callback2); |
| } |
| |
| /** |
| * Validate IWifi death listener and registration flow. |
| */ |
| @Test |
| public void testWifiDeathAndRegistration() throws Exception { |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| // act: IWifi service death |
| mDeathRecipientCaptor.getValue().serviceDied(0); |
| mTestLooper.dispatchAll(); |
| |
| // verify: getting onStop |
| mInOrder.verify(mManagerStatusListenerMock).onStatusChanged(); |
| |
| // act: service startup |
| mServiceNotificationCaptor.getValue().onRegistration(IWifi.kInterfaceName, "", false); |
| |
| // verify: initialization of IWifi |
| mInOrder.verify(mWifiMock).linkToDeath(mDeathRecipientCaptor.capture(), anyLong()); |
| mInOrder.verify(mWifiMock).registerEventCallback(mWifiEventCallbackCaptor.capture()); |
| |
| // act: start |
| mDut.start(); |
| mWifiEventCallbackCaptor.getValue().onStart(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: service and callback calls |
| mInOrder.verify(mWifiMock).start(); |
| mInOrder.verify(mManagerStatusListenerMock, times(3)).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock); |
| } |
| |
| /** |
| * Validate IWifi onFailure causes notification |
| */ |
| @Test |
| public void testWifiFail() throws Exception { |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| // act: IWifi failure |
| mWifiEventCallbackCaptor.getValue().onFailure(mStatusFail); |
| mTestLooper.dispatchAll(); |
| |
| // verify: getting onStop |
| mInOrder.verify(mManagerStatusListenerMock).onStatusChanged(); |
| |
| // act: start again |
| mDut.start(); |
| mWifiEventCallbackCaptor.getValue().onStart(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: service and callback calls |
| mInOrder.verify(mWifiMock).start(); |
| mInOrder.verify(mManagerStatusListenerMock).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock); |
| } |
| |
| /** |
| * Validate creation of STA interface from blank start-up. The remove interface. |
| */ |
| @Test |
| public void testCreateStaInterfaceNoInitMode() throws Exception { |
| final String name = "sta0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiStaIface iface = (IWifiStaIface) validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: remove interface |
| mDut.removeIface(iface); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| mInOrder.verify(chipMock.chip).removeStaIface(name); |
| verify(idl).onDestroyed(); |
| verify(iafrl).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate creation of AP interface from blank start-up. The remove interface. |
| */ |
| @Test |
| public void testCreateApInterfaceNoInitMode() throws Exception { |
| final String name = "ap0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.AP, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.AP_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: remove interface |
| mDut.removeIface(iface); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| mInOrder.verify(chipMock.chip).removeApIface(name); |
| verify(idl).onDestroyed(); |
| verify(iafrl).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate creation of P2P interface from blank start-up. The remove interface. |
| */ |
| @Test |
| public void testCreateP2pInterfaceNoInitMode() throws Exception { |
| final String name = "p2p0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiP2pIface iface = (IWifiP2pIface) validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.P2P, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: remove interface |
| mDut.removeIface(iface); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| mInOrder.verify(chipMock.chip).removeP2pIface(name); |
| verify(idl).onDestroyed(); |
| verify(iafrl).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate creation of NAN interface from blank start-up. The remove interface. |
| */ |
| @Test |
| public void testCreateNanInterfaceNoInitMode() throws Exception { |
| final String name = "nan0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiNanIface iface = (IWifiNanIface) validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.NAN, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: remove interface |
| mDut.removeIface(iface); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| mInOrder.verify(chipMock.chip).removeNanIface(name); |
| verify(idl).onDestroyed(); |
| verify(iafrl).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate creation of AP interface when in STA mode - but with no interface created. Expect |
| * a change in chip mode. |
| */ |
| @Test |
| public void testCreateApWithStaModeUp() throws Exception { |
| final String name = "ap0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.AP, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.AP_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: stop Wi-Fi |
| mDut.stop(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| verify(idl).onDestroyed(); |
| verify(mManagerStatusListenerMock, times(2)).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate creation of AP interface when in AP mode - but with no interface created. Expect |
| * no change in chip mode. |
| */ |
| @Test |
| public void testCreateApWithApModeUp() throws Exception { |
| final String name = "ap0"; |
| |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener idl = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.AP_CHIP_MODE_ID, // chipModeId |
| IfaceType.AP, // ifaceTypeToCreate |
| name, // ifaceName |
| BaselineChip.AP_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| idl, // destroyedListener |
| iafrl // availableListener |
| ); |
| collector.checkThat("allocated interface", iface, IsNull.notNullValue()); |
| |
| // act: stop Wi-Fi |
| mDut.stop(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: callback triggered |
| verify(idl).onDestroyed(); |
| verify(mManagerStatusListenerMock, times(2)).onStatusChanged(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl); |
| } |
| |
| /** |
| * Validate AP up/down creation of AP interface when a STA already created. Expect: |
| * - STA created |
| * - P2P created |
| * - When AP requested: |
| * - STA & P2P torn down |
| * - AP created |
| * - P2P creation refused |
| * - Request STA: will tear down AP |
| * - When AP destroyed: |
| * - Get p2p available listener callback |
| * - Can create P2P when requested |
| * - Create P2P |
| * - Request NAN: will get refused |
| * - Tear down P2P: |
| * - should get nan available listener callback |
| * - Can create NAN when requested |
| */ |
| @Test |
| public void testCreateSameAndDiffPriorities() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener2 = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener apDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener2 = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| // Request STA |
| IWifiIface staIface = validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| staDestroyedListener, // destroyedListener |
| staAvailListener // availableListener |
| ); |
| collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue()); |
| |
| // register additional InterfaceDestroyedListeners - including a duplicate (verify that |
| // only called once!) |
| mDut.registerDestroyedListener(staIface, staDestroyedListener2, mTestLooper.getLooper()); |
| mDut.registerDestroyedListener(staIface, staDestroyedListener, mTestLooper.getLooper()); |
| |
| // Request P2P |
| IWifiIface p2pIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.P2P, // ifaceTypeToCreate |
| "p2p0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| p2pDestroyedListener, // destroyedListener |
| p2pAvailListener // availableListener |
| ); |
| collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue()); |
| |
| // Request AP |
| IWifiIface apIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.AP, // ifaceTypeToCreate |
| "ap0", // ifaceName |
| BaselineChip.AP_CHIP_MODE_ID, // finalChipMode |
| new IWifiIface[]{staIface, p2pIface}, // tearDownList |
| apDestroyedListener, // destroyedListener |
| apAvailListener, // availableListener |
| // destroyedInterfacesDestroyedListeners... |
| staDestroyedListener, staDestroyedListener2, p2pDestroyedListener |
| ); |
| collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue()); |
| |
| // Request P2P: expect failure |
| p2pIface = mDut.createP2pIface(p2pDestroyedListener, mTestLooper.getLooper()); |
| collector.checkThat("P2P can't be created", p2pIface, IsNull.nullValue()); |
| |
| // Request STA: expect success |
| staIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.AP_CHIP_MODE_ID, // chipModeId |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| staDestroyedListener, // destroyedListener |
| staAvailListener, // availableListener |
| apDestroyedListener // destroyedInterfacesDestroyedListeners... |
| ); |
| collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue()); |
| |
| mTestLooper.dispatchAll(); |
| verify(apDestroyedListener).onDestroyed(); |
| |
| // Request P2P: expect success now |
| p2pIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.P2P, // ifaceTypeToCreate |
| "p2p0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| p2pDestroyedListener2, // destroyedListener |
| p2pAvailListener // availableListener |
| ); |
| |
| // Request NAN: should fail |
| IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper()); |
| mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener, |
| mTestLooper.getLooper()); |
| collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue()); |
| |
| // Tear down P2P |
| mDut.removeIface(p2pIface); |
| mTestLooper.dispatchAll(); |
| |
| verify(chipMock.chip, times(2)).removeP2pIface("p2p0"); |
| verify(p2pDestroyedListener2).onDestroyed(); |
| |
| // Should now be able to request and get NAN |
| nanIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.NAN, // ifaceTypeToCreate |
| "nan0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| nanDestroyedListener, // destroyedListener |
| nanAvailListener // availableListener |
| ); |
| collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue()); |
| |
| // available callback verification |
| verify(staAvailListener).onAvailableForRequest(); |
| verify(apAvailListener, times(4)).onAvailableForRequest(); |
| verify(p2pAvailListener, times(3)).onAvailableForRequest(); |
| verify(nanAvailListener).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener, |
| staDestroyedListener2, apDestroyedListener, apAvailListener, p2pDestroyedListener, |
| nanDestroyedListener, nanAvailListener, p2pDestroyedListener2); |
| } |
| |
| /** |
| * Validate P2P and NAN interactions. Expect: |
| * - STA created |
| * - NAN created |
| * - When P2P requested: |
| * - NAN torn down |
| * - P2P created |
| * - NAN creation refused |
| * - When P2P destroyed: |
| * - get nan available listener |
| * - Can create NAN when requested |
| */ |
| @Test |
| public void testP2pAndNanInteractions() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = null; |
| |
| // Request STA |
| IWifiIface staIface = validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| staDestroyedListener, // destroyedListener |
| staAvailListener // availableListener |
| ); |
| |
| // Request NAN |
| IWifiIface nanIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.NAN, // ifaceTypeToCreate |
| "nan0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| nanDestroyedListener, // destroyedListener |
| nanAvailListener // availableListener |
| ); |
| |
| // Request P2P |
| IWifiIface p2pIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.P2P, // ifaceTypeToCreate |
| "p2p0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| new IWifiIface[]{nanIface}, // tearDownList |
| p2pDestroyedListener, // destroyedListener |
| p2pAvailListener, // availableListener |
| nanDestroyedListener // destroyedInterfacesDestroyedListeners... |
| ); |
| |
| // Request NAN: expect failure |
| nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper()); |
| mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener, |
| mTestLooper.getLooper()); |
| collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue()); |
| |
| // Destroy P2P interface |
| boolean status = mDut.removeIface(p2pIface); |
| mInOrder.verify(chipMock.chip).removeP2pIface("p2p0"); |
| collector.checkThat("P2P removal success", status, equalTo(true)); |
| |
| mTestLooper.dispatchAll(); |
| verify(p2pDestroyedListener).onDestroyed(); |
| verify(nanAvailListener).onAvailableForRequest(); |
| |
| // Request NAN: expect success now |
| nanIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.NAN, // ifaceTypeToCreate |
| "nan0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| nanDestroyedListener, // destroyedListener |
| nanAvailListener // availableListener |
| ); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener, |
| nanDestroyedListener, nanAvailListener, p2pDestroyedListener); |
| } |
| |
| /** |
| * Validates that when (for some reason) the cache is out-of-sync with the actual chip status |
| * then Wi-Fi is shut-down. |
| */ |
| @Test |
| public void testCacheMismatchError() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| // Request STA |
| IWifiIface staIface = validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| staDestroyedListener, // destroyedListener |
| staAvailListener // availableListener |
| ); |
| |
| // Request NAN |
| IWifiIface nanIface = validateInterfaceSequence(chipMock, |
| true, // chipModeValid |
| BaselineChip.STA_CHIP_MODE_ID, // chipModeId |
| IfaceType.NAN, // ifaceTypeToCreate |
| "nan0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| nanDestroyedListener, // destroyedListener |
| nanAvailListener // availableListener |
| ); |
| |
| // fiddle with the "chip" by removing the STA |
| chipMock.interfaceNames.get(IfaceType.STA).remove("sta0"); |
| |
| // now try to request another NAN |
| nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper()); |
| mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener, |
| mTestLooper.getLooper()); |
| collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue()); |
| |
| // verify that Wi-Fi is shut-down: should also get all onDestroyed messages that are |
| // registered (even if they seem out-of-sync to chip) |
| mTestLooper.dispatchAll(); |
| verify(mWifiMock, times(2)).stop(); |
| verify(mManagerStatusListenerMock, times(2)).onStatusChanged(); |
| verify(staDestroyedListener).onDestroyed(); |
| verify(nanDestroyedListener).onDestroyed(); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener, |
| nanDestroyedListener, nanAvailListener); |
| } |
| |
| /** |
| * Validates that trying to allocate a STA and then another STA fails. Only one STA at a time |
| * is permitted (by baseline chip). |
| */ |
| @Test |
| public void testDuplicateStaRequests() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener1 = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener1 = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| HalDeviceManager.InterfaceDestroyedListener staDestroyedListener2 = mock( |
| HalDeviceManager.InterfaceDestroyedListener.class); |
| |
| // get STA interface |
| IWifiIface staIface1 = validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| staDestroyedListener1, // destroyedListener |
| staAvailListener1 // availableListener |
| ); |
| collector.checkThat("STA created", staIface1, IsNull.notNullValue()); |
| |
| // get STA interface again |
| IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mTestLooper.getLooper()); |
| collector.checkThat("STA created", staIface2, IsNull.nullValue()); |
| |
| verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener1, |
| staAvailListener1, staDestroyedListener2); |
| } |
| |
| /** |
| * Validates that a duplicate registration of the same InterfaceAvailableForRequestListener |
| * listener will result in a single callback. |
| * |
| * Also validates that get an immediate call on registration if available. |
| */ |
| @Test |
| public void testDuplicateAvailableRegistrations() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock( |
| HalDeviceManager.InterfaceAvailableForRequestListener.class); |
| |
| // get STA interface |
| IWifiIface staIface = validateInterfaceSequence(chipMock, |
| false, // chipModeValid |
| -1000, // chipModeId (only used if chipModeValid is true) |
| IfaceType.STA, // ifaceTypeToCreate |
| "sta0", // ifaceName |
| BaselineChip.STA_CHIP_MODE_ID, // finalChipMode |
| null, // tearDownList |
| null, // destroyedListener |
| null // availableListener |
| ); |
| collector.checkThat("STA created", staIface, IsNull.notNullValue()); |
| |
| // act: register the same listener twice |
| mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener, |
| mTestLooper.getLooper()); |
| mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener, |
| mTestLooper.getLooper()); |
| mTestLooper.dispatchAll(); |
| |
| // remove STA interface -> should trigger callbacks |
| mDut.removeIface(staIface); |
| mTestLooper.dispatchAll(); |
| |
| // verify: only a single trigger |
| verify(staAvailListener).onAvailableForRequest(); |
| |
| verifyNoMoreInteractions(staAvailListener); |
| } |
| |
| /** |
| * Validate that the getSupportedIfaceTypes API works when requesting for all chips. |
| */ |
| @Test |
| public void testGetSupportedIfaceTypesAll() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| // try API |
| Set<Integer> results = mDut.getSupportedIfaceTypes(); |
| |
| // verify results |
| Set<Integer> correctResults = new HashSet<>(); |
| correctResults.add(IfaceType.AP); |
| correctResults.add(IfaceType.STA); |
| correctResults.add(IfaceType.P2P); |
| correctResults.add(IfaceType.NAN); |
| |
| assertEquals(correctResults, results); |
| } |
| |
| /** |
| * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip. |
| */ |
| @Test |
| public void testGetSupportedIfaceTypesOneChip() throws Exception { |
| BaselineChip chipMock = new BaselineChip(); |
| chipMock.initialize(); |
| mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip, |
| mManagerStatusListenerMock); |
| executeAndValidateInitializationSequence(); |
| executeAndValidateStartupSequence(); |
| |
| // try API |
| Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip); |
| |
| // verify results |
| Set<Integer> correctResults = new HashSet<>(); |
| correctResults.add(IfaceType.AP); |
| correctResults.add(IfaceType.STA); |
| correctResults.add(IfaceType.P2P); |
| correctResults.add(IfaceType.NAN); |
| |
| assertEquals(correctResults, results); |
| } |
| |
| /** |
| * Validate that when no chip info is found an empty list is returned. |
| */ |
| @Test |
| public void testGetSupportedIfaceTypesError() throws Exception { |
| // try API |
| Set<Integer> results = mDut.getSupportedIfaceTypes(); |
| |
| // verify results |
| assertEquals(0, results.size()); |
| } |
| |
| // utilities |
| private void dumpDut(String prefix) { |
| StringWriter sw = new StringWriter(); |
| mDut.dump(null, new PrintWriter(sw), null); |
| Log.e("HalDeviceManager", prefix + sw.toString()); |
| } |
| |
| private void executeAndValidateInitializationSequence() throws Exception { |
| // act: |
| mDut.initialize(); |
| |
| // verify: service manager initialization sequence |
| mInOrder.verify(mServiceManagerMock).linkToDeath(any(IHwBinder.DeathRecipient.class), |
| anyLong()); |
| mInOrder.verify(mServiceManagerMock).registerForNotifications(eq(IWifi.kInterfaceName), |
| eq(""), mServiceNotificationCaptor.capture()); |
| |
| // act: get the service started (which happens even when service was already up) |
| mServiceNotificationCaptor.getValue().onRegistration(IWifi.kInterfaceName, "", true); |
| |
| // verify: wifi initialization sequence |
| mInOrder.verify(mWifiMock).linkToDeath(mDeathRecipientCaptor.capture(), anyLong()); |
| mInOrder.verify(mWifiMock).registerEventCallback(mWifiEventCallbackCaptor.capture()); |
| collector.checkThat("isReady is true", mDut.isReady(), equalTo(true)); |
| } |
| |
| private void executeAndValidateStartupSequence() throws Exception { |
| // act: register listener & start Wi-Fi |
| mDut.registerStatusListener(mManagerStatusListenerMock, mTestLooper.getLooper()); |
| mDut.start(); |
| |
| // verify |
| mInOrder.verify(mWifiMock).start(); |
| |
| // act: trigger onStart callback of IWifiEventCallback |
| mWifiEventCallbackCaptor.getValue().onStart(); |
| mTestLooper.dispatchAll(); |
| |
| // verify: onStart called on registered listener |
| mInOrder.verify(mManagerStatusListenerMock).onStatusChanged(); |
| } |
| |
| private IWifiIface validateInterfaceSequence(ChipMockBase chipMock, |
| boolean chipModeValid, int chipModeId, |
| int ifaceTypeToCreate, String ifaceName, int finalChipMode, IWifiIface[] tearDownList, |
| HalDeviceManager.InterfaceDestroyedListener destroyedListener, |
| HalDeviceManager.InterfaceAvailableForRequestListener availableListener, |
| HalDeviceManager.InterfaceDestroyedListener... destroyedInterfacesDestroyedListeners) |
| throws Exception { |
| // configure chip mode response |
| chipMock.chipModeValid = chipModeValid; |
| chipMock.chipModeId = chipModeId; |
| |
| IWifiIface iface = null; |
| |
| // configure: interface to be created |
| // act: request the interface |
| switch (ifaceTypeToCreate) { |
| case IfaceType.STA: |
| iface = mock(IWifiStaIface.class); |
| doAnswer(new GetNameAnswer(ifaceName)).when(iface).getName( |
| any(IWifiIface.getNameCallback.class)); |
| doAnswer(new GetTypeAnswer(IfaceType.STA)).when(iface).getType( |
| any(IWifiIface.getTypeCallback.class)); |
| doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when( |
| chipMock.chip).createStaIface(any(IWifiChip.createStaIfaceCallback.class)); |
| |
| mDut.createStaIface(destroyedListener, mTestLooper.getLooper()); |
| break; |
| case IfaceType.AP: |
| iface = mock(IWifiApIface.class); |
| doAnswer(new GetNameAnswer(ifaceName)).when(iface).getName( |
| any(IWifiIface.getNameCallback.class)); |
| doAnswer(new GetTypeAnswer(IfaceType.AP)).when(iface).getType( |
| any(IWifiIface.getTypeCallback.class)); |
| doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when( |
| chipMock.chip).createApIface(any(IWifiChip.createApIfaceCallback.class)); |
| |
| mDut.createApIface(destroyedListener, mTestLooper.getLooper()); |
| break; |
| case IfaceType.P2P: |
| iface = mock(IWifiP2pIface.class); |
| doAnswer(new GetNameAnswer(ifaceName)).when(iface).getName( |
| any(IWifiIface.getNameCallback.class)); |
| doAnswer(new GetTypeAnswer(IfaceType.P2P)).when(iface).getType( |
| any(IWifiIface.getTypeCallback.class)); |
| doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when( |
| chipMock.chip).createP2pIface(any(IWifiChip.createP2pIfaceCallback.class)); |
| |
| mDut.createP2pIface(destroyedListener, mTestLooper.getLooper()); |
| break; |
| case IfaceType.NAN: |
| iface = mock(IWifiNanIface.class); |
| doAnswer(new GetNameAnswer(ifaceName)).when(iface).getName( |
| any(IWifiIface.getNameCallback.class)); |
| doAnswer(new GetTypeAnswer(IfaceType.NAN)).when(iface).getType( |
| any(IWifiIface.getTypeCallback.class)); |
| doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when( |
| chipMock.chip).createNanIface(any(IWifiChip.createNanIfaceCallback.class)); |
| |
| mDut.createNanIface(destroyedListener, mTestLooper.getLooper()); |
| break; |
| } |
| if (availableListener != null) { |
| mDut.registerInterfaceAvailableForRequestListener(ifaceTypeToCreate, availableListener, |
| mTestLooper.getLooper()); |
| } |
| |
| // validate: optional tear down of interfaces |
| if (tearDownList != null) { |
| for (IWifiIface tearDownIface: tearDownList) { |
| switch (getType(tearDownIface)) { |
| case IfaceType.STA: |
| mInOrder.verify(chipMock.chip).removeStaIface(getName(tearDownIface)); |
| break; |
| case IfaceType.AP: |
| mInOrder.verify(chipMock.chip).removeApIface(getName(tearDownIface)); |
| break; |
| case IfaceType.P2P: |
| mInOrder.verify(chipMock.chip).removeP2pIface(getName(tearDownIface)); |
| break; |
| case IfaceType.NAN: |
| mInOrder.verify(chipMock.chip).removeNanIface(getName(tearDownIface)); |
| break; |
| } |
| } |
| } |
| |
| // validate: optional switch to the requested mode |
| if (!chipModeValid || chipModeId != finalChipMode) { |
| mInOrder.verify(chipMock.chip).configureChip(finalChipMode); |
| } else { |
| mInOrder.verify(chipMock.chip, times(0)).configureChip(anyInt()); |
| } |
| |
| // validate: create interface |
| switch (ifaceTypeToCreate) { |
| case IfaceType.STA: |
| mInOrder.verify(chipMock.chip).createStaIface( |
| any(IWifiChip.createStaIfaceCallback.class)); |
| break; |
| case IfaceType.AP: |
| mInOrder.verify(chipMock.chip).createApIface( |
| any(IWifiChip.createApIfaceCallback.class)); |
| break; |
| case IfaceType.P2P: |
| mInOrder.verify(chipMock.chip).createP2pIface( |
| any(IWifiChip.createP2pIfaceCallback.class)); |
| break; |
| case IfaceType.NAN: |
| mInOrder.verify(chipMock.chip).createNanIface( |
| any(IWifiChip.createNanIfaceCallback.class)); |
| break; |
| } |
| |
| // verify: callbacks on deleted interfaces |
| mTestLooper.dispatchAll(); |
| for (int i = 0; i < destroyedInterfacesDestroyedListeners.length; ++i) { |
| verify(destroyedInterfacesDestroyedListeners[i]).onDestroyed(); |
| } |
| |
| return iface; |
| } |
| |
| private int getType(IWifiIface iface) throws Exception { |
| Mutable<Integer> typeResp = new Mutable<>(); |
| iface.getType((WifiStatus status, int type) -> { |
| typeResp.value = type; |
| }); |
| return typeResp.value; |
| } |
| |
| private String getName(IWifiIface iface) throws Exception { |
| Mutable<String> nameResp = new Mutable<>(); |
| iface.getName((WifiStatus status, String name) -> { |
| nameResp.value = name; |
| }); |
| return nameResp.value; |
| } |
| |
| private WifiStatus getStatus(int code) { |
| WifiStatus status = new WifiStatus(); |
| status.code = code; |
| return status; |
| } |
| |
| private static class Mutable<E> { |
| public E value; |
| |
| Mutable() { |
| value = null; |
| } |
| |
| Mutable(E value) { |
| this.value = value; |
| } |
| } |
| |
| // Answer objects |
| private class GetChipIdsAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private WifiStatus mStatus; |
| private ArrayList<Integer> mChipIds; |
| |
| GetChipIdsAnswer(WifiStatus status, ArrayList<Integer> chipIds) { |
| mStatus = status; |
| mChipIds = chipIds; |
| } |
| |
| public void answer(IWifi.getChipIdsCallback cb) { |
| cb.onValues(mStatus, mChipIds); |
| } |
| } |
| |
| private class GetChipAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private WifiStatus mStatus; |
| private IWifiChip mChip; |
| |
| GetChipAnswer(WifiStatus status, IWifiChip chip) { |
| mStatus = status; |
| mChip = chip; |
| } |
| |
| public void answer(int chipId, IWifi.getChipCallback cb) { |
| cb.onValues(mStatus, mChip); |
| } |
| } |
| |
| private class GetIdAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| GetIdAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public void answer(IWifiChip.getIdCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.chipId); |
| } |
| } |
| |
| private class GetAvailableModesAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| GetAvailableModesAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public void answer(IWifiChip.getAvailableModesCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.availableModes); |
| } |
| } |
| |
| private class GetModeAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| GetModeAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public void answer(IWifiChip.getModeCallback cb) { |
| cb.onValues(mChipMockBase.chipModeValid ? mStatusOk |
| : getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE), mChipMockBase.chipModeId); |
| } |
| } |
| |
| private class ConfigureChipAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| ConfigureChipAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public WifiStatus answer(int chipMode) { |
| mChipMockBase.chipModeId = chipMode; |
| return mStatusOk; |
| } |
| } |
| |
| private class GetXxxIfaceNamesAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| GetXxxIfaceNamesAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public void answer(IWifiChip.getStaIfaceNamesCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.interfaceNames.get(IfaceType.STA)); |
| } |
| |
| public void answer(IWifiChip.getApIfaceNamesCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.interfaceNames.get(IfaceType.AP)); |
| } |
| |
| public void answer(IWifiChip.getP2pIfaceNamesCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.interfaceNames.get(IfaceType.P2P)); |
| } |
| |
| public void answer(IWifiChip.getNanIfaceNamesCallback cb) { |
| cb.onValues(mStatusOk, mChipMockBase.interfaceNames.get(IfaceType.NAN)); |
| } |
| } |
| |
| private class GetXxxIfaceAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| |
| GetXxxIfaceAnswer(ChipMockBase chipMockBase) { |
| mChipMockBase = chipMockBase; |
| } |
| |
| public void answer(String name, IWifiChip.getStaIfaceCallback cb) { |
| IWifiIface iface = mChipMockBase.interfacesByName.get(IfaceType.STA).get(name); |
| cb.onValues(iface != null ? mStatusOk : mStatusFail, (IWifiStaIface) iface); |
| } |
| |
| public void answer(String name, IWifiChip.getApIfaceCallback cb) { |
| IWifiIface iface = mChipMockBase.interfacesByName.get(IfaceType.AP).get(name); |
| cb.onValues(iface != null ? mStatusOk : mStatusFail, (IWifiApIface) iface); |
| } |
| |
| public void answer(String name, IWifiChip.getP2pIfaceCallback cb) { |
| IWifiIface iface = mChipMockBase.interfacesByName.get(IfaceType.P2P).get(name); |
| cb.onValues(iface != null ? mStatusOk : mStatusFail, (IWifiP2pIface) iface); |
| } |
| |
| public void answer(String name, IWifiChip.getNanIfaceCallback cb) { |
| IWifiIface iface = mChipMockBase.interfacesByName.get(IfaceType.NAN).get(name); |
| cb.onValues(iface != null ? mStatusOk : mStatusFail, (IWifiNanIface) iface); |
| } |
| } |
| |
| private class CreateXxxIfaceAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| private WifiStatus mStatus; |
| private IWifiIface mWifiIface; |
| |
| CreateXxxIfaceAnswer(ChipMockBase chipMockBase, WifiStatus status, IWifiIface wifiIface) { |
| mChipMockBase = chipMockBase; |
| mStatus = status; |
| mWifiIface = wifiIface; |
| } |
| |
| private void addInterfaceInfo(int type) { |
| if (mStatus.code == WifiStatusCode.SUCCESS) { |
| try { |
| mChipMockBase.interfaceNames.get(type).add(getName(mWifiIface)); |
| mChipMockBase.interfacesByName.get(type).put(getName(mWifiIface), mWifiIface); |
| } catch (Exception e) { |
| // do nothing |
| } |
| } |
| } |
| |
| public void answer(IWifiChip.createStaIfaceCallback cb) { |
| cb.onValues(mStatus, (IWifiStaIface) mWifiIface); |
| addInterfaceInfo(IfaceType.STA); |
| } |
| |
| public void answer(IWifiChip.createApIfaceCallback cb) { |
| cb.onValues(mStatus, (IWifiApIface) mWifiIface); |
| addInterfaceInfo(IfaceType.AP); |
| } |
| |
| public void answer(IWifiChip.createP2pIfaceCallback cb) { |
| cb.onValues(mStatus, (IWifiP2pIface) mWifiIface); |
| addInterfaceInfo(IfaceType.P2P); |
| } |
| |
| public void answer(IWifiChip.createNanIfaceCallback cb) { |
| cb.onValues(mStatus, (IWifiNanIface) mWifiIface); |
| addInterfaceInfo(IfaceType.NAN); |
| } |
| } |
| |
| private class RemoveXxxIfaceAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private ChipMockBase mChipMockBase; |
| private int mType; |
| |
| RemoveXxxIfaceAnswer(ChipMockBase chipMockBase, int type) { |
| mChipMockBase = chipMockBase; |
| mType = type; |
| } |
| |
| private WifiStatus removeIface(int type, String ifname) { |
| try { |
| if (!mChipMockBase.interfaceNames.get(type).remove(ifname)) { |
| return mStatusFail; |
| } |
| if (mChipMockBase.interfacesByName.get(type).remove(ifname) == null) { |
| return mStatusFail; |
| } |
| } catch (Exception e) { |
| return mStatusFail; |
| } |
| return mStatusOk; |
| } |
| |
| public WifiStatus answer(String ifname) { |
| return removeIface(mType, ifname); |
| } |
| } |
| |
| private class GetNameAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private String mName; |
| |
| GetNameAnswer(String name) { |
| mName = name; |
| } |
| |
| public void answer(IWifiIface.getNameCallback cb) { |
| cb.onValues(mStatusOk, mName); |
| } |
| } |
| |
| private class GetTypeAnswer extends MockAnswerUtil.AnswerWithArguments { |
| private int mType; |
| |
| GetTypeAnswer(int type) { |
| mType = type; |
| } |
| |
| public void answer(IWifiIface.getTypeCallback cb) { |
| cb.onValues(mStatusOk, mType); |
| } |
| } |
| |
| // chip configuration |
| |
| private class ChipMockBase { |
| public IWifiChip chip; |
| public int chipId; |
| public boolean chipModeValid = false; |
| public int chipModeId = -1000; |
| public Map<Integer, ArrayList<String>> interfaceNames = new HashMap<>(); |
| public Map<Integer, Map<String, IWifiIface>> interfacesByName = new HashMap<>(); |
| |
| public ArrayList<IWifiChip.ChipMode> availableModes; |
| |
| void initialize() throws Exception { |
| chip = mock(IWifiChip.class); |
| |
| interfaceNames.put(IfaceType.STA, new ArrayList<>()); |
| interfaceNames.put(IfaceType.AP, new ArrayList<>()); |
| interfaceNames.put(IfaceType.P2P, new ArrayList<>()); |
| interfaceNames.put(IfaceType.NAN, new ArrayList<>()); |
| |
| interfacesByName.put(IfaceType.STA, new HashMap<>()); |
| interfacesByName.put(IfaceType.AP, new HashMap<>()); |
| interfacesByName.put(IfaceType.P2P, new HashMap<>()); |
| interfacesByName.put(IfaceType.NAN, new HashMap<>()); |
| |
| when(chip.registerEventCallback(any(IWifiChipEventCallback.class))).thenReturn( |
| mStatusOk); |
| when(chip.configureChip(anyInt())).thenAnswer(new ConfigureChipAnswer(this)); |
| doAnswer(new GetIdAnswer(this)).when(chip).getId(any(IWifiChip.getIdCallback.class)); |
| doAnswer(new GetModeAnswer(this)).when(chip).getMode( |
| any(IWifiChip.getModeCallback.class)); |
| GetXxxIfaceNamesAnswer getXxxIfaceNamesAnswer = new GetXxxIfaceNamesAnswer(this); |
| doAnswer(getXxxIfaceNamesAnswer).when(chip).getStaIfaceNames( |
| any(IWifiChip.getStaIfaceNamesCallback.class)); |
| doAnswer(getXxxIfaceNamesAnswer).when(chip).getApIfaceNames( |
| any(IWifiChip.getApIfaceNamesCallback.class)); |
| doAnswer(getXxxIfaceNamesAnswer).when(chip).getP2pIfaceNames( |
| any(IWifiChip.getP2pIfaceNamesCallback.class)); |
| doAnswer(getXxxIfaceNamesAnswer).when(chip).getNanIfaceNames( |
| any(IWifiChip.getNanIfaceNamesCallback.class)); |
| GetXxxIfaceAnswer getXxxIfaceAnswer = new GetXxxIfaceAnswer(this); |
| doAnswer(getXxxIfaceAnswer).when(chip).getStaIface(anyString(), |
| any(IWifiChip.getStaIfaceCallback.class)); |
| doAnswer(getXxxIfaceAnswer).when(chip).getApIface(anyString(), |
| any(IWifiChip.getApIfaceCallback.class)); |
| doAnswer(getXxxIfaceAnswer).when(chip).getP2pIface(anyString(), |
| any(IWifiChip.getP2pIfaceCallback.class)); |
| doAnswer(getXxxIfaceAnswer).when(chip).getNanIface(anyString(), |
| any(IWifiChip.getNanIfaceCallback.class)); |
| doAnswer(new RemoveXxxIfaceAnswer(this, IfaceType.STA)).when(chip).removeStaIface( |
| anyString()); |
| doAnswer(new RemoveXxxIfaceAnswer(this, IfaceType.AP)).when(chip).removeApIface( |
| anyString()); |
| doAnswer(new RemoveXxxIfaceAnswer(this, IfaceType.P2P)).when(chip).removeP2pIface( |
| anyString()); |
| doAnswer(new RemoveXxxIfaceAnswer(this, IfaceType.NAN)).when(chip).removeNanIface( |
| anyString()); |
| } |
| } |
| |
| // emulate baseline/legacy config: |
| // mode: STA + NAN || P2P |
| // mode: NAN |
| private class BaselineChip extends ChipMockBase { |
| static final int STA_CHIP_MODE_ID = 0; |
| static final int AP_CHIP_MODE_ID = 1; |
| |
| void initialize() throws Exception { |
| super.initialize(); |
| |
| // chip Id configuration |
| ArrayList<Integer> chipIds; |
| chipId = 10; |
| chipIds = new ArrayList<>(); |
| chipIds.add(chipId); |
| doAnswer(new GetChipIdsAnswer(mStatusOk, chipIds)).when(mWifiMock).getChipIds( |
| any(IWifi.getChipIdsCallback.class)); |
| |
| doAnswer(new GetChipAnswer(mStatusOk, chip)).when(mWifiMock).getChip(eq(10), |
| any(IWifi.getChipCallback.class)); |
| |
| // initialize dummy chip modes |
| IWifiChip.ChipMode cm; |
| IWifiChip.ChipIfaceCombination cic; |
| IWifiChip.ChipIfaceCombinationLimit cicl; |
| |
| // Mode 0: 1xSTA + 1x{P2P,NAN} |
| // Mode 1: 1xAP |
| availableModes = new ArrayList<>(); |
| cm = new IWifiChip.ChipMode(); |
| cm.id = STA_CHIP_MODE_ID; |
| |
| cic = new IWifiChip.ChipIfaceCombination(); |
| |
| cicl = new IWifiChip.ChipIfaceCombinationLimit(); |
| cicl.maxIfaces = 1; |
| cicl.types.add(IfaceType.STA); |
| cic.limits.add(cicl); |
| |
| cicl = new IWifiChip.ChipIfaceCombinationLimit(); |
| cicl.maxIfaces = 1; |
| cicl.types.add(IfaceType.P2P); |
| cicl.types.add(IfaceType.NAN); |
| cic.limits.add(cicl); |
| cm.availableCombinations.add(cic); |
| availableModes.add(cm); |
| |
| cm = new IWifiChip.ChipMode(); |
| cm.id = AP_CHIP_MODE_ID; |
| cic = new IWifiChip.ChipIfaceCombination(); |
| cicl = new IWifiChip.ChipIfaceCombinationLimit(); |
| cicl.maxIfaces = 1; |
| cicl.types.add(IfaceType.AP); |
| cic.limits.add(cicl); |
| cm.availableCombinations.add(cic); |
| availableModes.add(cm); |
| |
| doAnswer(new GetAvailableModesAnswer(this)).when(chip) |
| .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class)); |
| } |
| } |
| } |