1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.wifi.cts; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import java.nio.ByteBuffer; 23 import java.util.List; 24 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.net.wifi.ScanResult; 30 import android.net.wifi.ScanResult.InformationElement; 31 import android.net.wifi.WifiInfo; 32 import android.net.wifi.WifiManager; 33 import android.net.wifi.WifiManager.WifiLock; 34 import android.platform.test.annotations.AppModeFull; 35 import android.test.AndroidTestCase; 36 37 import com.android.compatibility.common.util.PollingCheck; 38 import com.android.compatibility.common.util.ShellIdentityUtils; 39 import com.android.compatibility.common.util.SystemUtil; 40 41 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 42 public class ScanResultTest extends WifiJUnit3TestBase { 43 private static class MySync { 44 int expectedState = STATE_NULL; 45 } 46 47 private WifiManager mWifiManager; 48 private WifiLock mWifiLock; 49 private static MySync mMySync; 50 private boolean mWasVerboseLoggingEnabled; 51 private boolean mWasScanThrottleEnabled; 52 53 private static final int STATE_NULL = 0; 54 private static final int STATE_WIFI_CHANGING = 1; 55 private static final int STATE_WIFI_CHANGED = 2; 56 private static final int STATE_START_SCAN = 3; 57 private static final int STATE_SCAN_RESULTS_AVAILABLE = 4; 58 private static final int STATE_SCAN_FAILURE = 5; 59 60 private static final String TAG = "WifiInfoTest"; 61 private static final int TIMEOUT_MSEC = 6000; 62 private static final int WAIT_MSEC = 60; 63 private static final int ENABLE_WAIT_MSEC = 10000; 64 private static final int SCAN_WAIT_MSEC = 10000; 65 private static final int SCAN_MAX_RETRY_COUNT = 6; 66 private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5; 67 private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L; 68 private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000; 69 70 private static final String TEST_SSID = "TEST_SSID"; 71 public static final String TEST_BSSID = "04:ac:fe:45:34:10"; 72 public static final String TEST_CAPS = "CCMP"; 73 public static final int TEST_LEVEL = -56; 74 public static final int TEST_FREQUENCY = 2412; 75 public static final long TEST_TIMESTAMP = 4660L; 76 77 private IntentFilter mIntentFilter; 78 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 79 @Override 80 public void onReceive(Context context, Intent intent) { 81 final String action = intent.getAction(); 82 if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { 83 synchronized (mMySync) { 84 mMySync.expectedState = STATE_WIFI_CHANGED; 85 mMySync.notify(); 86 } 87 } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 88 synchronized (mMySync) { 89 if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { 90 mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE; 91 } else { 92 mMySync.expectedState = STATE_SCAN_FAILURE; 93 } 94 mMySync.notify(); 95 } 96 } 97 } 98 }; 99 100 @Override setUp()101 protected void setUp() throws Exception { 102 super.setUp(); 103 if (!WifiFeature.isWifiSupported(getContext())) { 104 // skip the test if WiFi is not supported 105 return; 106 } 107 mMySync = new MySync(); 108 mIntentFilter = new IntentFilter(); 109 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 110 mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 111 mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 112 mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 113 mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 114 mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 115 mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); 116 mIntentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); 117 118 mContext.registerReceiver(mReceiver, mIntentFilter); 119 mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); 120 assertThat(mWifiManager).isNotNull(); 121 122 // turn on verbose logging for tests 123 mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( 124 () -> mWifiManager.isVerboseLoggingEnabled()); 125 ShellIdentityUtils.invokeWithShellPermissions( 126 () -> mWifiManager.setVerboseLoggingEnabled(true)); 127 // Disable scan throttling for tests. 128 mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( 129 () -> mWifiManager.isScanThrottleEnabled()); 130 ShellIdentityUtils.invokeWithShellPermissions( 131 () -> mWifiManager.setScanThrottleEnabled(false)); 132 133 mWifiLock = mWifiManager.createWifiLock(TAG); 134 mWifiLock.acquire(); 135 136 // enable Wifi 137 if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); 138 PollingCheck.check("Wifi not enabled", ENABLE_WAIT_MSEC, 139 () -> mWifiManager.isWifiEnabled()); 140 141 mMySync.expectedState = STATE_NULL; 142 } 143 144 @Override tearDown()145 protected void tearDown() throws Exception { 146 if (!WifiFeature.isWifiSupported(getContext())) { 147 // skip the test if WiFi is not supported 148 super.tearDown(); 149 return; 150 } 151 mWifiLock.release(); 152 mContext.unregisterReceiver(mReceiver); 153 if (!mWifiManager.isWifiEnabled()) 154 setWifiEnabled(true); 155 ShellIdentityUtils.invokeWithShellPermissions( 156 () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled)); 157 ShellIdentityUtils.invokeWithShellPermissions( 158 () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled)); 159 Thread.sleep(ENABLE_WAIT_MSEC); 160 super.tearDown(); 161 } 162 setWifiEnabled(boolean enable)163 private void setWifiEnabled(boolean enable) throws Exception { 164 synchronized (mMySync) { 165 mMySync.expectedState = STATE_WIFI_CHANGING; 166 if (enable) { 167 SystemUtil.runShellCommand("svc wifi enable"); 168 } else { 169 SystemUtil.runShellCommand("svc wifi disable"); 170 } 171 waitForBroadcast(TIMEOUT_MSEC, STATE_WIFI_CHANGED); 172 } 173 } 174 waitForBroadcast(long timeout, int expectedState)175 private boolean waitForBroadcast(long timeout, int expectedState) throws Exception { 176 long waitTime = System.currentTimeMillis() + timeout; 177 while (System.currentTimeMillis() < waitTime 178 && mMySync.expectedState != expectedState) 179 mMySync.wait(WAIT_MSEC); 180 return mMySync.expectedState == expectedState; 181 } 182 testScanResultProperties()183 public void testScanResultProperties() { 184 if (!WifiFeature.isWifiSupported(getContext())) { 185 // skip the test if WiFi is not supported 186 return; 187 } 188 // this test case should in Wifi environment 189 for (ScanResult scanResult : mWifiManager.getScanResults()) { 190 assertThat(scanResult.toString()).isNotNull(); 191 192 for (InformationElement ie : scanResult.getInformationElements()) { 193 testInformationElementCopyConstructor(ie); 194 testInformationElementFields(ie); 195 } 196 197 assertThat(scanResult.getWifiStandard()).isAnyOf( 198 ScanResult.WIFI_STANDARD_UNKNOWN, 199 ScanResult.WIFI_STANDARD_LEGACY, 200 ScanResult.WIFI_STANDARD_11N, 201 ScanResult.WIFI_STANDARD_11AC, 202 ScanResult.WIFI_STANDARD_11AX 203 ); 204 205 scanResult.isPasspointNetwork(); 206 } 207 } 208 testInformationElementCopyConstructor(InformationElement ie)209 private void testInformationElementCopyConstructor(InformationElement ie) { 210 InformationElement copy = new InformationElement(ie); 211 212 assertThat(copy.getId()).isEqualTo(ie.getId()); 213 assertThat(copy.getIdExt()).isEqualTo(ie.getIdExt()); 214 assertThat(copy.getBytes()).isEqualTo(ie.getBytes()); 215 } 216 testInformationElementFields(InformationElement ie)217 private void testInformationElementFields(InformationElement ie) { 218 // id is 1 octet 219 int id = ie.getId(); 220 assertThat(id).isAtLeast(0); 221 assertThat(id).isAtMost(255); 222 223 // idExt is 0 or 1 octet 224 int idExt = ie.getIdExt(); 225 assertThat(idExt).isAtLeast(0); 226 assertThat(idExt).isAtMost(255); 227 228 ByteBuffer bytes = ie.getBytes(); 229 assertThat(bytes).isNotNull(); 230 } 231 232 /* Multiple scans to ensure bssid is updated */ scanAndWait()233 private void scanAndWait() throws Exception { 234 synchronized (mMySync) { 235 for (int retry = 0; retry < SCAN_MAX_RETRY_COUNT; retry++) { 236 mMySync.expectedState = STATE_START_SCAN; 237 mWifiManager.startScan(); 238 if (waitForBroadcast(SCAN_WAIT_MSEC, STATE_SCAN_RESULTS_AVAILABLE)) { 239 break; 240 } 241 } 242 } 243 } 244 245 @VirtualDeviceNotSupported testScanResultTimeStamp()246 public void testScanResultTimeStamp() throws Exception { 247 if (!WifiFeature.isWifiSupported(getContext())) { 248 // skip the test if WiFi is not supported 249 return; 250 } 251 252 long timestamp = 0; 253 String BSSID = null; 254 255 scanAndWait(); 256 257 List<ScanResult> scanResults = mWifiManager.getScanResults(); 258 for (ScanResult result : scanResults) { 259 BSSID = result.BSSID; 260 timestamp = result.timestamp; 261 assertThat(timestamp).isNotEqualTo(0); 262 break; 263 } 264 265 scanAndWait(); 266 267 scanResults = mWifiManager.getScanResults(); 268 for (ScanResult result : scanResults) { 269 if (result.BSSID.equals(BSSID)) { 270 long timeDiff = (result.timestamp - timestamp) / 1000; 271 assertThat(timeDiff).isGreaterThan(0L); 272 assertThat(timeDiff).isLessThan(6L * SCAN_WAIT_MSEC); 273 } 274 } 275 } 276 277 /** Test that the copy constructor copies fields correctly. */ testScanResultConstructors()278 public void testScanResultConstructors() throws Exception { 279 if (!WifiFeature.isWifiSupported(getContext())) { 280 // skip the test if WiFi is not supported 281 return; 282 } 283 284 ScanResult scanResult = new ScanResult(); 285 scanResult.SSID = TEST_SSID; 286 scanResult.BSSID = TEST_BSSID; 287 scanResult.capabilities = TEST_CAPS; 288 scanResult.level = TEST_LEVEL; 289 scanResult.frequency = TEST_FREQUENCY; 290 scanResult.timestamp = TEST_TIMESTAMP; 291 292 ScanResult scanResult2 = new ScanResult(scanResult); 293 assertThat(scanResult2.SSID).isEqualTo(TEST_SSID); 294 assertThat(scanResult2.BSSID).isEqualTo(TEST_BSSID); 295 assertThat(scanResult2.capabilities).isEqualTo(TEST_CAPS); 296 assertThat(scanResult2.level).isEqualTo(TEST_LEVEL); 297 assertThat(scanResult2.frequency).isEqualTo(TEST_FREQUENCY); 298 assertThat(scanResult2.timestamp).isEqualTo(TEST_TIMESTAMP); 299 } 300 testScanResultMatchesWifiInfo()301 public void testScanResultMatchesWifiInfo() throws Exception { 302 if (!WifiFeature.isWifiSupported(getContext())) { 303 // skip the test if WiFi is not supported 304 return; 305 } 306 307 // ensure Wifi is connected 308 ShellIdentityUtils.invokeWithShellPermissions(() -> mWifiManager.reconnect()); 309 PollingCheck.check( 310 "Wifi not connected", 311 WIFI_CONNECT_TIMEOUT_MILLIS, 312 () -> mWifiManager.getConnectionInfo().getNetworkId() != -1); 313 314 final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 315 assertThat(wifiInfo).isNotNull(); 316 317 ScanResult currentNetwork = null; 318 for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) { 319 scanAndWait(); 320 final List<ScanResult> scanResults = mWifiManager.getScanResults(); 321 currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID())) 322 .findAny().orElse(null); 323 324 if (currentNetwork != null) { 325 break; 326 } 327 Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC); 328 } 329 assertWithMessage("Current network not found in scan results") 330 .that(currentNetwork).isNotNull(); 331 332 String wifiInfoSsidQuoted = wifiInfo.getSSID(); 333 String scanResultSsidUnquoted = currentNetwork.SSID; 334 335 assertWithMessage( 336 "SSID mismatch: make sure this isn't a hidden network or an SSID containing " 337 + "non-UTF-8 characters - neither is supported by this CTS test.") 338 .that("\"" + scanResultSsidUnquoted + "\"") 339 .isEqualTo(wifiInfoSsidQuoted); 340 assertThat(currentNetwork.frequency).isEqualTo(wifiInfo.getFrequency()); 341 } 342 } 343