1/* 2 * Copyright (C) 2016 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.mockito.Mockito.any; 20import static org.mockito.Mockito.anyBoolean; 21import static org.mockito.Mockito.anyInt; 22import static org.mockito.Mockito.eq; 23import static org.mockito.Mockito.inOrder; 24import static org.mockito.Mockito.never; 25import static org.mockito.Mockito.verify; 26import static org.mockito.Mockito.when; 27 28import android.net.InterfaceConfiguration; 29import android.net.wifi.IApInterface; 30import android.net.wifi.WifiConfiguration; 31import android.net.wifi.WifiManager; 32import android.os.IBinder; 33import android.os.IBinder.DeathRecipient; 34import android.os.INetworkManagementService; 35import android.os.test.TestLooper; 36import android.test.suitebuilder.annotation.SmallTest; 37 38import com.android.server.net.BaseNetworkObserver; 39 40import org.junit.Before; 41import org.junit.Test; 42import org.mockito.ArgumentCaptor; 43import org.mockito.InOrder; 44import org.mockito.Mock; 45import org.mockito.MockitoAnnotations; 46 47import java.nio.charset.StandardCharsets; 48import java.util.ArrayList; 49import java.util.Arrays; 50import java.util.Locale; 51 52/** Unit tests for {@link SoftApManager}. */ 53@SmallTest 54public class SoftApManagerTest { 55 56 private static final String TAG = "SoftApManagerTest"; 57 58 private static final String DEFAULT_SSID = "DefaultTestSSID"; 59 private static final String TEST_SSID = "TestSSID"; 60 private static final String TEST_COUNTRY_CODE = "TestCountry"; 61 private static final Integer[] ALLOWED_2G_CHANNELS = {1, 2, 3, 4}; 62 private static final String TEST_INTERFACE_NAME = "testif0"; 63 64 private final ArrayList<Integer> mAllowed2GChannels = 65 new ArrayList<>(Arrays.asList(ALLOWED_2G_CHANNELS)); 66 67 private final WifiConfiguration mDefaultApConfig = createDefaultApConfig(); 68 69 TestLooper mLooper; 70 @Mock WifiNative mWifiNative; 71 @Mock SoftApManager.Listener mListener; 72 @Mock InterfaceConfiguration mInterfaceConfiguration; 73 @Mock IBinder mApInterfaceBinder; 74 @Mock IApInterface mApInterface; 75 @Mock INetworkManagementService mNmService; 76 @Mock WifiApConfigStore mWifiApConfigStore; 77 @Mock WifiMetrics mWifiMetrics; 78 final ArgumentCaptor<DeathRecipient> mDeathListenerCaptor = 79 ArgumentCaptor.forClass(DeathRecipient.class); 80 final ArgumentCaptor<BaseNetworkObserver> mNetworkObserverCaptor = 81 ArgumentCaptor.forClass(BaseNetworkObserver.class); 82 83 SoftApManager mSoftApManager; 84 85 /** Sets up test. */ 86 @Before 87 public void setUp() throws Exception { 88 MockitoAnnotations.initMocks(this); 89 mLooper = new TestLooper(); 90 91 when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder); 92 when(mApInterface.startHostapd()).thenReturn(true); 93 when(mApInterface.stopHostapd()).thenReturn(true); 94 when(mApInterface.writeHostapdConfig( 95 any(), anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true); 96 when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME); 97 } 98 99 private WifiConfiguration createDefaultApConfig() { 100 WifiConfiguration defaultConfig = new WifiConfiguration(); 101 defaultConfig.SSID = DEFAULT_SSID; 102 return defaultConfig; 103 } 104 105 private SoftApManager createSoftApManager(WifiConfiguration config) throws Exception { 106 when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder); 107 when(mApInterface.startHostapd()).thenReturn(true); 108 when(mApInterface.stopHostapd()).thenReturn(true); 109 if (config == null) { 110 when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig); 111 } 112 SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(), 113 mWifiNative, 114 TEST_COUNTRY_CODE, 115 mListener, 116 mApInterface, 117 mNmService, 118 mWifiApConfigStore, 119 config, 120 mWifiMetrics); 121 mLooper.dispatchAll(); 122 return newSoftApManager; 123 } 124 125 /** Verifies startSoftAp will use default config if AP configuration is not provided. */ 126 @Test 127 public void startSoftApWithoutConfig() throws Exception { 128 startSoftApAndVerifyEnabled(null); 129 } 130 131 /** Verifies startSoftAp will use provided config and start AP. */ 132 @Test 133 public void startSoftApWithConfig() throws Exception { 134 WifiConfiguration config = new WifiConfiguration(); 135 config.apBand = WifiConfiguration.AP_BAND_2GHZ; 136 config.SSID = TEST_SSID; 137 startSoftApAndVerifyEnabled(config); 138 } 139 140 /** Tests softap startup if default config fails to load. **/ 141 @Test 142 public void startSoftApDefaultConfigFailedToLoad() throws Exception { 143 when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder); 144 when(mApInterface.startHostapd()).thenReturn(true); 145 when(mApInterface.stopHostapd()).thenReturn(true); 146 when(mWifiApConfigStore.getApConfiguration()).thenReturn(null); 147 SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(), 148 mWifiNative, 149 TEST_COUNTRY_CODE, 150 mListener, 151 mApInterface, 152 mNmService, 153 mWifiApConfigStore, 154 null, 155 mWifiMetrics); 156 mLooper.dispatchAll(); 157 newSoftApManager.start(); 158 mLooper.dispatchAll(); 159 verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 160 WifiManager.SAP_START_FAILURE_GENERAL); 161 } 162 163 /** Tests the handling of stop command when soft AP is not started. */ 164 @Test 165 public void stopWhenNotStarted() throws Exception { 166 mSoftApManager = createSoftApManager(null); 167 mSoftApManager.stop(); 168 mLooper.dispatchAll(); 169 /* Verify no state changes. */ 170 verify(mListener, never()).onStateChanged(anyInt(), anyInt()); 171 } 172 173 /** Tests the handling of stop command when soft AP is started. */ 174 @Test 175 public void stopWhenStarted() throws Exception { 176 startSoftApAndVerifyEnabled(null); 177 178 InOrder order = inOrder(mListener); 179 180 mSoftApManager.stop(); 181 mLooper.dispatchAll(); 182 183 verify(mApInterface).stopHostapd(); 184 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 185 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 186 } 187 188 @Test 189 public void handlesWificondInterfaceDeath() throws Exception { 190 startSoftApAndVerifyEnabled(null); 191 192 mDeathListenerCaptor.getValue().binderDied(); 193 mLooper.dispatchAll(); 194 InOrder order = inOrder(mListener); 195 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 196 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 197 WifiManager.SAP_START_FAILURE_GENERAL); 198 } 199 200 /** Starts soft AP and verifies that it is enabled successfully. */ 201 protected void startSoftApAndVerifyEnabled(WifiConfiguration config) throws Exception { 202 String expectedSSID; 203 InOrder order = inOrder(mListener, mApInterfaceBinder, mApInterface, mNmService); 204 205 when(mWifiNative.isHalStarted()).thenReturn(false); 206 when(mWifiNative.setCountryCodeHal(TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) 207 .thenReturn(true); 208 209 mSoftApManager = createSoftApManager(config); 210 if (config == null) { 211 when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig); 212 expectedSSID = mDefaultApConfig.SSID; 213 } else { 214 expectedSSID = config.SSID; 215 } 216 mSoftApManager.start(); 217 mLooper.dispatchAll(); 218 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); 219 order.verify(mApInterfaceBinder).linkToDeath(mDeathListenerCaptor.capture(), eq(0)); 220 order.verify(mNmService).registerObserver(mNetworkObserverCaptor.capture()); 221 order.verify(mApInterface).writeHostapdConfig( 222 eq(expectedSSID.getBytes(StandardCharsets.UTF_8)), anyBoolean(), 223 anyInt(), anyInt(), any()); 224 order.verify(mApInterface).startHostapd(); 225 mNetworkObserverCaptor.getValue().interfaceLinkStateChanged(TEST_INTERFACE_NAME, true); 226 mLooper.dispatchAll(); 227 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); 228 } 229 230 /** Verifies that soft AP was not disabled. */ 231 protected void verifySoftApNotDisabled() throws Exception { 232 verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 233 verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 234 } 235} 236