1 /* 2 * Copyright (C) 2009 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 android.content.Context.RECEIVER_EXPORTED; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; 21 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 22 import static android.net.wifi.SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD; 23 import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP; 24 import static android.net.wifi.WifiAvailableChannel.OP_MODE_STA; 25 import static android.net.wifi.WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO; 26 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID; 27 import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP; 28 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE; 29 import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT; 30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 31 import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; 32 import static android.os.Process.myUid; 33 34 import static com.google.common.truth.Truth.assertThat; 35 import static com.google.common.truth.Truth.assertWithMessage; 36 37 import static org.junit.Assert.assertArrayEquals; 38 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertFalse; 40 import static org.junit.Assert.assertNotEquals; 41 import static org.junit.Assert.assertNotNull; 42 import static org.junit.Assert.assertNull; 43 import static org.junit.Assert.assertThrows; 44 import static org.junit.Assert.assertTrue; 45 import static org.junit.Assert.fail; 46 import static org.junit.Assume.assumeTrue; 47 48 import android.annotation.NonNull; 49 import android.app.UiAutomation; 50 import android.app.admin.DevicePolicyManager; 51 import android.app.admin.WifiSsidPolicy; 52 import android.content.BroadcastReceiver; 53 import android.content.Context; 54 import android.content.Intent; 55 import android.content.IntentFilter; 56 import android.content.pm.PackageInfo; 57 import android.content.pm.PackageManager; 58 import android.content.pm.ResolveInfo; 59 import android.net.ConnectivityManager; 60 import android.net.MacAddress; 61 import android.net.Network; 62 import android.net.NetworkCapabilities; 63 import android.net.NetworkInfo; 64 import android.net.NetworkRequest; 65 import android.net.TetheringManager; 66 import android.net.Uri; 67 import android.net.wifi.CoexUnsafeChannel; 68 import android.net.wifi.MloLink; 69 import android.net.wifi.MscsParams; 70 import android.net.wifi.OuiKeyedData; 71 import android.net.wifi.QosCharacteristics; 72 import android.net.wifi.QosPolicyParams; 73 import android.net.wifi.ScanResult; 74 import android.net.wifi.SoftApCapability; 75 import android.net.wifi.SoftApConfiguration; 76 import android.net.wifi.SoftApInfo; 77 import android.net.wifi.SoftApState; 78 import android.net.wifi.UriParserResults; 79 import android.net.wifi.WifiAvailableChannel; 80 import android.net.wifi.WifiClient; 81 import android.net.wifi.WifiConfiguration; 82 import android.net.wifi.WifiEnterpriseConfig; 83 import android.net.wifi.WifiInfo; 84 import android.net.wifi.WifiManager; 85 import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback; 86 import android.net.wifi.WifiManager.WifiLock; 87 import android.net.wifi.WifiNetworkConnectionStatistics; 88 import android.net.wifi.WifiNetworkSelectionConfig; 89 import android.net.wifi.WifiNetworkSuggestion; 90 import android.net.wifi.WifiScanner; 91 import android.net.wifi.WifiSsid; 92 import android.net.wifi.WifiUriParser; 93 import android.net.wifi.hotspot2.ConfigParser; 94 import android.net.wifi.hotspot2.OsuProvider; 95 import android.net.wifi.hotspot2.PasspointConfiguration; 96 import android.net.wifi.hotspot2.ProvisioningCallback; 97 import android.net.wifi.hotspot2.pps.Credential; 98 import android.net.wifi.hotspot2.pps.HomeSp; 99 import android.net.wifi.twt.TwtRequest; 100 import android.net.wifi.twt.TwtSession; 101 import android.net.wifi.twt.TwtSessionCallback; 102 import android.os.Build; 103 import android.os.Bundle; 104 import android.os.Handler; 105 import android.os.HandlerExecutor; 106 import android.os.HandlerThread; 107 import android.os.PersistableBundle; 108 import android.os.PowerManager; 109 import android.os.Process; 110 import android.os.SystemClock; 111 import android.os.SystemProperties; 112 import android.os.UserHandle; 113 import android.platform.test.annotations.AppModeFull; 114 import android.platform.test.annotations.AsbSecurityTest; 115 import android.platform.test.annotations.RequiresDevice; 116 import android.platform.test.annotations.RequiresFlagsEnabled; 117 import android.platform.test.flag.junit.CheckFlagsRule; 118 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 119 import android.provider.DeviceConfig; 120 import android.provider.Settings; 121 import android.support.test.uiautomator.UiDevice; 122 import android.telephony.TelephonyManager; 123 import android.text.TextUtils; 124 import android.util.ArraySet; 125 import android.util.Log; 126 import android.util.SparseArray; 127 import android.util.SparseIntArray; 128 129 import androidx.test.ext.junit.runners.AndroidJUnit4; 130 import androidx.test.filters.SdkSuppress; 131 import androidx.test.platform.app.InstrumentationRegistry; 132 133 import com.android.compatibility.common.util.ApiLevelUtil; 134 import com.android.compatibility.common.util.ApiTest; 135 import com.android.compatibility.common.util.FeatureUtil; 136 import com.android.compatibility.common.util.PollingCheck; 137 import com.android.compatibility.common.util.PropertyUtil; 138 import com.android.compatibility.common.util.ShellIdentityUtils; 139 import com.android.compatibility.common.util.SystemUtil; 140 import com.android.compatibility.common.util.ThrowingRunnable; 141 import com.android.modules.utils.build.SdkLevel; 142 import com.android.net.module.util.MacAddressUtils; 143 import com.android.wifi.flags.Flags; 144 145 import com.google.common.collect.Range; 146 147 import org.junit.AfterClass; 148 import org.junit.Before; 149 import org.junit.BeforeClass; 150 import org.junit.Rule; 151 import org.junit.Test; 152 import org.junit.runner.RunWith; 153 154 import java.io.BufferedReader; 155 import java.io.IOException; 156 import java.io.InputStream; 157 import java.io.InputStreamReader; 158 import java.lang.reflect.Constructor; 159 import java.net.HttpURLConnection; 160 import java.net.InetAddress; 161 import java.net.URL; 162 import java.nio.charset.StandardCharsets; 163 import java.time.Duration; 164 import java.util.ArrayList; 165 import java.util.Arrays; 166 import java.util.Collections; 167 import java.util.HashMap; 168 import java.util.HashSet; 169 import java.util.List; 170 import java.util.Locale; 171 import java.util.Map; 172 import java.util.Objects; 173 import java.util.Set; 174 import java.util.concurrent.ConcurrentLinkedQueue; 175 import java.util.concurrent.CountDownLatch; 176 import java.util.concurrent.Executor; 177 import java.util.concurrent.Executors; 178 import java.util.concurrent.TimeUnit; 179 import java.util.concurrent.atomic.AtomicBoolean; 180 import java.util.concurrent.atomic.AtomicInteger; 181 import java.util.concurrent.atomic.AtomicReference; 182 import java.util.function.BiConsumer; 183 import java.util.function.Consumer; 184 import java.util.function.IntConsumer; 185 import java.util.stream.Collectors; 186 187 @RunWith(AndroidJUnit4.class) 188 @AppModeFull(reason = "Cannot get WifiManager in instant app mode") 189 public class WifiManagerTest extends WifiJUnit4TestBase { 190 private static Context sContext; 191 private static boolean sShouldRunTest = false; 192 193 private static class MySync { 194 int expectedState = STATE_NULL; 195 } 196 197 private static WifiManager sWifiManager; 198 private static ConnectivityManager sConnectivityManager; 199 private static TetheringManager sTetheringManager; 200 private static MySync sMySync; 201 private static List<ScanResult> sScanResults = null; 202 private static NetworkInfo sNetworkInfo = 203 new NetworkInfo(ConnectivityManager.TYPE_WIFI, TelephonyManager.NETWORK_TYPE_UNKNOWN, 204 "wifi", "unknown"); 205 private final Object mLock = new Object(); 206 private static UiDevice sUiDevice; 207 private static boolean sWasVerboseLoggingEnabled; 208 private static boolean sWasScanThrottleEnabled; 209 private static SoftApConfiguration sOriginalSoftApConfig = null; 210 private static PowerManager sPowerManager; 211 private static PowerManager.WakeLock sWakeLock; 212 // Please refer to WifiManager 213 private static final int MIN_RSSI = -100; 214 private static final int MAX_RSSI = -55; 215 216 private static final int STATE_NULL = 0; 217 private static final int STATE_WIFI_CHANGING = 1; 218 private static final int STATE_WIFI_ENABLED = 2; 219 private static final int STATE_WIFI_DISABLED = 3; 220 private static final int STATE_SCANNING = 4; 221 private static final int STATE_SCAN_DONE = 5; 222 223 private static final String TAG = "WifiManagerTest"; 224 private static final String SSID1 = "\"WifiManagerTest\""; 225 private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode"; 226 // A full single scan duration is typically about 6-7 seconds, but 227 // depending on devices it takes more time (9-11 seconds). For a 228 // safety margin, the test waits for 15 seconds. 229 private static final int SCAN_TEST_WAIT_DURATION_MS = 15_000; 230 private static final int TEST_WAIT_DURATION_MS = 10_000; 231 private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000; 232 private static final int WIFI_OFF_ON_TIMEOUT_MILLIS = 5_000; 233 private static final int WIFI_PNO_CONNECT_TIMEOUT_MILLIS = 90_000; 234 private static final int WAIT_MSEC = 60; 235 private static final int DURATION_SCREEN_TOGGLE = 2000; 236 private static final int DURATION_SETTINGS_TOGGLE = 1_000; 237 private static final int DURATION_SOFTAP_START_MS = 6_000; 238 private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; 239 private static final String DEVICE_CONFIG_NAMESPACE = "wifi"; 240 241 private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; 242 243 private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; 244 private static final String MANAGED_PROVISIONING_PACKAGE_NAME 245 = "com.android.managedprovisioning"; 246 247 private static final String TEST_SSID_UNQUOTED = "testSsid1"; 248 private static final String TEST_IP_ADDRESS = "192.168.5.5"; 249 private static final String TEST_MAC_ADDRESS = "aa:bb:cc:dd:ee:ff"; 250 private static final MacAddress TEST_MAC = MacAddress.fromString(TEST_MAC_ADDRESS); 251 private static final String TEST_PASSPHRASE = "passphrase"; 252 private static final String PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT = 253 "assets/ValidPasspointProfile.base64"; 254 private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config"; 255 private static final String TEST_PSK_CAP = "[RSN-PSK-CCMP]"; 256 private static final String TEST_BSSID = "00:01:02:03:04:05"; 257 private static final String TEST_COUNTRY_CODE = "JP"; 258 private static final String TEST_DOM_SUBJECT_MATCH = "domSubjectMatch"; 259 private static final int TEST_SUB_ID = 2; 260 private static final int EID_VSA = 221; // Copied from ScanResult.InformationElement 261 262 private static final int TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS = 1000; 263 private static final List<ScanResult.InformationElement> TEST_VENDOR_ELEMENTS = 264 new ArrayList<>(Arrays.asList( 265 new ScanResult.InformationElement(221, 0, new byte[]{ 1, 2, 3, 4 }), 266 new ScanResult.InformationElement( 267 221, 268 0, 269 new byte[]{ (byte) 170, (byte) 187, (byte) 204, (byte) 221 }) 270 )); 271 private static final int[] TEST_RSSI2_THRESHOLDS = {-81, -79, -73, -60}; 272 private static final int[] TEST_RSSI5_THRESHOLDS = {-80, -77, -71, -55}; 273 private static final int[] TEST_RSSI6_THRESHOLDS = {-79, -72, -65, -55}; 274 private static final SparseArray<Integer> TEST_FREQUENCY_WEIGHTS = new SparseArray<>(); 275 276 private IntentFilter mIntentFilter; 277 278 @Rule 279 public final CheckFlagsRule mCheckFlagsRule = 280 DeviceFlagsValueProvider.createCheckFlagsRule(); 281 private static final BroadcastReceiver sReceiver = new BroadcastReceiver() { 282 @Override 283 public void onReceive(Context context, Intent intent) { 284 final String action = intent.getAction(); 285 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 286 synchronized (sMySync) { 287 if (intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) { 288 sScanResults = sWifiManager.getScanResults(); 289 } else { 290 sScanResults = null; 291 } 292 sMySync.expectedState = STATE_SCAN_DONE; 293 sMySync.notifyAll(); 294 } 295 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 296 int newState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 297 WifiManager.WIFI_STATE_UNKNOWN); 298 synchronized (sMySync) { 299 if (newState == WifiManager.WIFI_STATE_ENABLED) { 300 Log.d(TAG, "*** New WiFi state is ENABLED ***"); 301 sMySync.expectedState = STATE_WIFI_ENABLED; 302 sMySync.notifyAll(); 303 } else if (newState == WifiManager.WIFI_STATE_DISABLED) { 304 Log.d(TAG, "*** New WiFi state is DISABLED ***"); 305 sMySync.expectedState = STATE_WIFI_DISABLED; 306 sMySync.notifyAll(); 307 } 308 } 309 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 310 synchronized (sMySync) { 311 sNetworkInfo = 312 (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 313 if (sNetworkInfo.getState() == NetworkInfo.State.CONNECTED) { 314 sMySync.notifyAll(); 315 } 316 } 317 } 318 } 319 }; 320 321 private static class TestProvisioningCallback extends ProvisioningCallback { 322 private final Object mObject; 323 // Initialize with an invalid status value (0) 324 public int mProvisioningStatus = 0; 325 // Initialize with an invalid status value (0) 326 public int mProvisioningFailureStatus = 0; 327 public boolean mProvisioningComplete = false; 328 329 TestProvisioningCallback(Object lock)330 TestProvisioningCallback(Object lock) { 331 mObject = lock; 332 } 333 334 @Override onProvisioningFailure(int status)335 public void onProvisioningFailure(int status) { 336 synchronized (mObject) { 337 mProvisioningFailureStatus = status; 338 mObject.notify(); 339 } 340 } 341 342 @Override onProvisioningStatus(int status)343 public void onProvisioningStatus(int status) { 344 synchronized (mObject) { 345 mProvisioningStatus = status; 346 mObject.notify(); 347 } 348 } 349 350 @Override onProvisioningComplete()351 public void onProvisioningComplete() { 352 mProvisioningComplete = true; 353 } 354 } 355 356 private static class TestSubsystemRestartTrackingCallback 357 extends SubsystemRestartTrackingCallback { 358 private final Object mObject; 359 360 public int mSubsystemRestartStatus = 0; // 0: nada, 1: restarting, 2: restarted 361 TestSubsystemRestartTrackingCallback(Object lock)362 TestSubsystemRestartTrackingCallback(Object lock) { 363 mObject = lock; 364 } 365 @Override onSubsystemRestarting()366 public void onSubsystemRestarting() { 367 synchronized (mObject) { 368 mSubsystemRestartStatus = 1; 369 mObject.notify(); 370 } 371 } 372 373 @Override onSubsystemRestarted()374 public void onSubsystemRestarted() { 375 synchronized (mObject) { 376 mSubsystemRestartStatus = 2; 377 mObject.notify(); 378 379 } 380 } 381 } 382 383 private static final String TEST_SSID = "TEST SSID"; 384 private static final String TEST_FRIENDLY_NAME = "Friendly Name"; 385 private static final Map<String, String> TEST_FRIENDLY_NAMES = new HashMap<>(); 386 static { 387 TEST_FRIENDLY_NAMES.put("en", TEST_FRIENDLY_NAME); 388 TEST_FRIENDLY_NAMES.put("kr", TEST_FRIENDLY_NAME + 2); 389 TEST_FRIENDLY_NAMES.put("jp", TEST_FRIENDLY_NAME + 3); 390 } 391 392 private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service"; 393 private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com"); 394 private static final String TEST_NAI = "test.access.com"; 395 private static final List<Integer> TEST_METHOD_LIST = 396 Arrays.asList(1 /* METHOD_SOAP_XML_SPP */); 397 private final HandlerThread mHandlerThread = new HandlerThread("WifiManagerTest"); 398 protected final Executor mExecutor; 399 { mHandlerThread.start()400 mHandlerThread.start(); 401 mExecutor = new HandlerExecutor(new Handler(mHandlerThread.getLooper())); 402 } 403 404 /** 405 * Class which can be used to fetch an object out of a lambda. Fetching an object 406 * out of a local scope with HIDL is a common operation (although usually it can 407 * and should be avoided). 408 * 409 * @param <E> Inner object type. 410 */ 411 public static final class Mutable<E> { 412 public E value; 413 Mutable()414 public Mutable() { 415 value = null; 416 } 417 Mutable(E value)418 public Mutable(E value) { 419 this.value = value; 420 } 421 } 422 423 @BeforeClass setUpClass()424 public static void setUpClass() throws Exception { 425 sContext = InstrumentationRegistry.getInstrumentation().getContext(); 426 if (!WifiFeature.isWifiSupported(sContext)) { 427 // skip the test if WiFi is not supported 428 return; 429 } 430 sShouldRunTest = true; 431 sPowerManager = sContext.getSystemService(PowerManager.class); 432 sWakeLock = sPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 433 sMySync = new MySync(); 434 IntentFilter intentFilter = new IntentFilter(); 435 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 436 intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 437 intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 438 intentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 439 intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 440 intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 441 intentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); 442 intentFilter.addAction(WifiManager.ACTION_PICK_WIFI_NETWORK); 443 intentFilter.setPriority(999); 444 445 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) { 446 sContext.registerReceiver(sReceiver, intentFilter, RECEIVER_EXPORTED); 447 } else { 448 sContext.registerReceiver(sReceiver, intentFilter); 449 } 450 sWifiManager = sContext.getSystemService(WifiManager.class); 451 sConnectivityManager = sContext.getSystemService(ConnectivityManager.class); 452 sTetheringManager = sContext.getSystemService(TetheringManager.class); 453 assertThat(sWifiManager).isNotNull(); 454 assertThat(sTetheringManager).isNotNull(); 455 456 // turn on verbose logging for tests 457 sWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions( 458 () -> sWifiManager.isVerboseLoggingEnabled()); 459 ShellIdentityUtils.invokeWithShellPermissions( 460 () -> sWifiManager.setVerboseLoggingEnabled(true)); 461 // Disable scan throttling for tests. 462 sWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions( 463 () -> sWifiManager.isScanThrottleEnabled()); 464 ShellIdentityUtils.invokeWithShellPermissions( 465 () -> sWifiManager.setScanThrottleEnabled(false)); 466 467 sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 468 turnScreenOnNoDelay(); 469 470 synchronized (sMySync) { 471 sMySync.expectedState = STATE_NULL; 472 } 473 474 List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( 475 sWifiManager::getConfiguredNetworks); 476 assertThat(savedNetworks.isEmpty()).isFalse(); 477 478 // Get original config for restore 479 sOriginalSoftApConfig = ShellIdentityUtils.invokeWithShellPermissions( 480 sWifiManager::getSoftApConfiguration); 481 } 482 483 @AfterClass tearDownClass()484 public static void tearDownClass() throws Exception { 485 if (!sShouldRunTest) { 486 return; 487 } 488 if (!sWifiManager.isWifiEnabled()) { 489 setWifiEnabled(true); 490 } 491 sContext.unregisterReceiver(sReceiver); 492 ShellIdentityUtils.invokeWithShellPermissions( 493 () -> sWifiManager.setScanThrottleEnabled(sWasScanThrottleEnabled)); 494 ShellIdentityUtils.invokeWithShellPermissions( 495 () -> sWifiManager.setVerboseLoggingEnabled(sWasVerboseLoggingEnabled)); 496 // restore original softap config 497 ShellIdentityUtils.invokeWithShellPermissions( 498 () -> sWifiManager.setSoftApConfiguration(sOriginalSoftApConfig)); 499 Thread.sleep(TEST_WAIT_DURATION_MS); 500 if (sWakeLock.isHeld()) { 501 sWakeLock.release(); 502 } 503 } 504 505 @Before setUp()506 public void setUp() throws Exception { 507 assumeTrue(sShouldRunTest); 508 // enable Wifi 509 if (!sWifiManager.isWifiEnabled()) { 510 setWifiEnabled(true); 511 startScan(); 512 } 513 PollingCheck.check("Wifi not enabled", TEST_WAIT_DURATION_MS, 514 () -> sWifiManager.isWifiEnabled()); 515 516 waitForConnection(); 517 } 518 setWifiEnabled(boolean enable)519 private static void setWifiEnabled(boolean enable) throws Exception { 520 synchronized (sMySync) { 521 if (sWifiManager.isWifiEnabled() != enable) { 522 // the new state is different, we expect it to change 523 sMySync.expectedState = STATE_WIFI_CHANGING; 524 } else { 525 sMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); 526 } 527 ShellIdentityUtils.invokeWithShellPermissions( 528 () -> sWifiManager.setWifiEnabled(enable)); 529 waitForExpectedWifiState(enable); 530 } 531 } 532 waitForExpectedWifiState(boolean enabled)533 private static void waitForExpectedWifiState(boolean enabled) throws InterruptedException { 534 synchronized (sMySync) { 535 long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS; 536 int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); 537 while (System.currentTimeMillis() < timeout 538 && sMySync.expectedState != expected) { 539 sMySync.wait(WAIT_MSEC); 540 } 541 } 542 } 543 544 // Get the current scan status from sticky broadcast. isScanCurrentlyAvailable()545 private boolean isScanCurrentlyAvailable() { 546 IntentFilter intentFilter = new IntentFilter(); 547 intentFilter.addAction(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED); 548 Intent intent = sContext.registerReceiver(null, intentFilter); 549 assertNotNull(intent); 550 if (intent.getAction().equals(WifiManager.ACTION_WIFI_SCAN_AVAILABILITY_CHANGED)) { 551 return intent.getBooleanExtra(WifiManager.EXTRA_SCAN_AVAILABLE, false); 552 } 553 return false; 554 } 555 startScan()556 private void startScan() throws Exception { 557 synchronized (sMySync) { 558 sMySync.expectedState = STATE_SCANNING; 559 sScanResults = null; 560 assertTrue(sWifiManager.startScan()); 561 long timeout = System.currentTimeMillis() + SCAN_TEST_WAIT_DURATION_MS; 562 while (System.currentTimeMillis() < timeout 563 && sMySync.expectedState == STATE_SCANNING) { 564 sMySync.wait(WAIT_MSEC); 565 } 566 } 567 } 568 waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis)569 private void waitForNetworkInfoState(NetworkInfo.State state, int timeoutMillis) 570 throws Exception { 571 synchronized (sMySync) { 572 if (sNetworkInfo.getState() == state) return; 573 long timeout = System.currentTimeMillis() + timeoutMillis; 574 while (System.currentTimeMillis() < timeout 575 && sNetworkInfo.getState() != state) 576 sMySync.wait(WAIT_MSEC); 577 assertEquals(state, sNetworkInfo.getState()); 578 } 579 } 580 waitForConnection(int timeoutMillis)581 private void waitForConnection(int timeoutMillis) throws Exception { 582 waitForNetworkInfoState(NetworkInfo.State.CONNECTED, timeoutMillis); 583 } 584 waitForConnection()585 private void waitForConnection() throws Exception { 586 waitForNetworkInfoState(NetworkInfo.State.CONNECTED, WIFI_CONNECT_TIMEOUT_MILLIS); 587 } 588 waitForDisconnection()589 private void waitForDisconnection() throws Exception { 590 waitForNetworkInfoState(NetworkInfo.State.DISCONNECTED, TEST_WAIT_DURATION_MS); 591 } 592 ensureNotNetworkInfoState(NetworkInfo.State state)593 private void ensureNotNetworkInfoState(NetworkInfo.State state) throws Exception { 594 synchronized (sMySync) { 595 long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS + WAIT_MSEC; 596 while (System.currentTimeMillis() < timeout) { 597 assertNotEquals(state, sNetworkInfo.getState()); 598 sMySync.wait(WAIT_MSEC); 599 } 600 } 601 } 602 ensureNotConnected()603 private void ensureNotConnected() throws Exception { 604 ensureNotNetworkInfoState(NetworkInfo.State.CONNECTED); 605 } 606 ensureNotDisconnected()607 private void ensureNotDisconnected() throws Exception { 608 ensureNotNetworkInfoState(NetworkInfo.State.DISCONNECTED); 609 } 610 existSSID(String ssid)611 private boolean existSSID(String ssid) { 612 for (final WifiConfiguration w : sWifiManager.getConfiguredNetworks()) { 613 if (w.SSID.equals(ssid)) 614 return true; 615 } 616 return false; 617 } 618 findConfiguredNetworks(String SSID, List<WifiConfiguration> networks)619 private int findConfiguredNetworks(String SSID, List<WifiConfiguration> networks) { 620 for (final WifiConfiguration w : networks) { 621 if (w.SSID.equals(SSID)) 622 return networks.indexOf(w); 623 } 624 return -1; 625 } 626 627 /** 628 * Test creation of WifiManager Lock. 629 */ 630 @Test testWifiManagerLock()631 public void testWifiManagerLock() throws Exception { 632 final String TAG = "Test"; 633 assertNotNull(sWifiManager.createWifiLock(TAG)); 634 assertNotNull(sWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); 635 } 636 637 /** 638 * Test wifi scanning when Wifi is off and location scanning is turned on. 639 */ 640 @Test testWifiManagerScanWhenWifiOffLocationTurnedOn()641 public void testWifiManagerScanWhenWifiOffLocationTurnedOn() throws Exception { 642 if (!hasLocationFeature()) { 643 Log.d(TAG, "Skipping test as location is not supported"); 644 return; 645 } 646 if (!isLocationEnabled()) { 647 fail("Please enable location for this test - since Marshmallow WiFi scan results are" 648 + " empty when location is disabled!"); 649 } 650 runWithScanning(() -> { 651 setWifiEnabled(false); 652 Thread.sleep(TEST_WAIT_DURATION_MS); 653 startScan(); 654 if (sWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { 655 // Make sure at least one AP is found. 656 assertNotNull("mScanResult should not be null!", sScanResults); 657 assertFalse("empty scan results!", sScanResults.isEmpty()); 658 } else { 659 // Make sure no scan results are available. 660 assertNull("mScanResult should be null!", sScanResults); 661 } 662 final String TAG = "Test"; 663 assertNotNull(sWifiManager.createWifiLock(TAG)); 664 assertNotNull(sWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); 665 }, true /* run with enabled*/); 666 } 667 668 /** 669 * Restart WiFi subsystem - verify that privileged call fails. 670 */ 671 @Test 672 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) testRestartWifiSubsystemShouldFailNoPermission()673 public void testRestartWifiSubsystemShouldFailNoPermission() throws Exception { 674 try { 675 sWifiManager.restartWifiSubsystem(); 676 fail("The restartWifiSubsystem should not succeed - privileged call"); 677 } catch (SecurityException e) { 678 // expected 679 } 680 } 681 682 /** 683 * Restart WiFi subsystem and verify transition through states. 684 */ 685 @Test 686 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) testRestartWifiSubsystem()687 public void testRestartWifiSubsystem() throws Exception { 688 TestSubsystemRestartTrackingCallback callback = 689 new TestSubsystemRestartTrackingCallback(mLock); 690 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 691 try { 692 uiAutomation.adoptShellPermissionIdentity(); 693 sWifiManager.registerSubsystemRestartTrackingCallback(mExecutor, callback); 694 synchronized (mLock) { 695 sWifiManager.restartWifiSubsystem(); 696 mLock.wait(TEST_WAIT_DURATION_MS); 697 } 698 assertEquals(callback.mSubsystemRestartStatus, 1); // 1: restarting 699 waitForExpectedWifiState(false); 700 assertFalse(sWifiManager.isWifiEnabled()); 701 synchronized (mLock) { 702 mLock.wait(TEST_WAIT_DURATION_MS); 703 assertEquals(callback.mSubsystemRestartStatus, 2); // 2: restarted 704 } 705 waitForExpectedWifiState(true); 706 assertTrue(sWifiManager.isWifiEnabled()); 707 } finally { 708 // cleanup 709 sWifiManager.unregisterSubsystemRestartTrackingCallback(callback); 710 uiAutomation.dropShellPermissionIdentity(); 711 } 712 } 713 714 /** 715 * test point of wifiManager properties: 716 * 1.enable properties 717 * 2.DhcpInfo properties 718 * 3.wifi state 719 * 4.ConnectionInfo 720 */ 721 @Test testWifiManagerProperties()722 public void testWifiManagerProperties() throws Exception { 723 setWifiEnabled(true); 724 assertTrue(sWifiManager.isWifiEnabled()); 725 assertNotNull(sWifiManager.getDhcpInfo()); 726 assertEquals(WifiManager.WIFI_STATE_ENABLED, sWifiManager.getWifiState()); 727 sWifiManager.getConnectionInfo(); 728 setWifiEnabled(false); 729 assertFalse(sWifiManager.isWifiEnabled()); 730 } 731 732 /** 733 * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with 734 * {@link SystemClock#elapsedRealtime()} on device.<p> 735 * To run this test in cts-tradefed: 736 * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp 737 */ 738 @Test 739 @RequiresDevice testWifiScanTimestamp()740 public void testWifiScanTimestamp() throws Exception { 741 if (!hasLocationFeature()) { 742 Log.d(TAG, "Skipping test as location is not supported"); 743 return; 744 } 745 if (!isLocationEnabled()) { 746 fail("Please enable location for this test - since Marshmallow WiFi scan results are" 747 + " empty when location is disabled!"); 748 } 749 if (!sWifiManager.isWifiEnabled()) { 750 setWifiEnabled(true); 751 } 752 // Make sure the scan timestamps are consistent with the device timestamp within the range 753 // of WIFI_SCAN_TEST_CACHE_DELAY_MILLIS. 754 startScan(); 755 // Make sure at least one AP is found. 756 assertTrue("mScanResult should not be null. This may be due to a scan timeout", 757 sScanResults != null); 758 assertFalse("empty scan results!", sScanResults.isEmpty()); 759 long nowMillis = SystemClock.elapsedRealtime(); 760 // Keep track of how many APs are fresh in one scan. 761 int numFreshAps = 0; 762 for (ScanResult result : sScanResults) { 763 long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp); 764 if (Math.abs(nowMillis - scanTimeMillis) < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) { 765 numFreshAps++; 766 } 767 } 768 // At least half of the APs in the scan should be fresh. 769 int numTotalAps = sScanResults.size(); 770 String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: " 771 + numFreshAps; 772 assertTrue(msg, numFreshAps * 2 >= sScanResults.size()); 773 } 774 775 @Test testConvertBetweenChannelFrequencyMhz()776 public void testConvertBetweenChannelFrequencyMhz() throws Exception { 777 int[] testFrequency_2G = {2412, 2437, 2462, 2484}; 778 int[] testFrequency_5G = {5180, 5220, 5540, 5745}; 779 int[] testFrequency_6G = {5955, 6435, 6535, 7115}; 780 int[] testFrequency_60G = {58320, 64800}; 781 SparseArray<int[]> testData = new SparseArray<>() {{ 782 put(ScanResult.WIFI_BAND_24_GHZ, testFrequency_2G); 783 put(ScanResult.WIFI_BAND_5_GHZ, testFrequency_5G); 784 put(ScanResult.WIFI_BAND_6_GHZ, testFrequency_6G); 785 put(ScanResult.WIFI_BAND_60_GHZ, testFrequency_60G); 786 }}; 787 788 for (int i = 0; i < testData.size(); i++) { 789 for (int frequency : testData.valueAt(i)) { 790 assertEquals(frequency, ScanResult.convertChannelToFrequencyMhzIfSupported( 791 ScanResult.convertFrequencyMhzToChannelIfSupported(frequency), testData.keyAt(i))); 792 } 793 } 794 } 795 796 // Return true if location is enabled. isLocationEnabled()797 private boolean isLocationEnabled() { 798 return Settings.Secure.getInt(sContext.getContentResolver(), 799 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) != 800 Settings.Secure.LOCATION_MODE_OFF; 801 } 802 803 // Returns true if the device has location feature. hasLocationFeature()804 private boolean hasLocationFeature() { 805 return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); 806 } 807 hasAutomotiveFeature()808 private boolean hasAutomotiveFeature() { 809 return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 810 } 811 hasWifiDirect()812 private boolean hasWifiDirect() { 813 return sContext.getPackageManager().hasSystemFeature( 814 PackageManager.FEATURE_WIFI_DIRECT); 815 } 816 hasWifiAware()817 private boolean hasWifiAware() { 818 return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE); 819 } 820 821 @Test testSignal()822 public void testSignal() { 823 final int numLevels = 9; 824 int expectLevel = 0; 825 assertEquals(expectLevel, WifiManager.calculateSignalLevel(MIN_RSSI, numLevels)); 826 assertEquals(numLevels - 1, WifiManager.calculateSignalLevel(MAX_RSSI, numLevels)); 827 expectLevel = 4; 828 assertEquals(expectLevel, WifiManager.calculateSignalLevel((MIN_RSSI + MAX_RSSI) / 2, 829 numLevels)); 830 int rssiA = 4; 831 int rssiB = 5; 832 assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) < 0); 833 rssiB = 4; 834 assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) == 0); 835 rssiA = 5; 836 rssiB = 4; 837 assertTrue(WifiManager.compareSignalLevel(rssiA, rssiB) > 0); 838 } 839 840 /** 841 * Test that {@link WifiManager#calculateSignalLevel(int)} returns a value in the range 842 * [0, {@link WifiManager#getMaxSignalLevel()}], and its value is monotonically increasing as 843 * the RSSI increases. 844 */ 845 @Test testCalculateSignalLevel()846 public void testCalculateSignalLevel() { 847 int maxSignalLevel = sWifiManager.getMaxSignalLevel(); 848 849 int prevSignalLevel = 0; 850 for (int rssi = -150; rssi <= 50; rssi++) { 851 int signalLevel = sWifiManager.calculateSignalLevel(rssi); 852 853 // between [0, maxSignalLevel] 854 assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(0); 855 assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtMost(maxSignalLevel); 856 857 // calculateSignalLevel(rssi) <= calculateSignalLevel(rssi + 1) 858 assertWithMessage("For RSSI=%s", rssi).that(signalLevel).isAtLeast(prevSignalLevel); 859 prevSignalLevel = signalLevel; 860 } 861 } 862 863 public class TestWifiVerboseLoggingStatusChangedListener implements 864 WifiManager.WifiVerboseLoggingStatusChangedListener { 865 public int numCalls; 866 public boolean status; 867 868 @Override onWifiVerboseLoggingStatusChanged(boolean enabled)869 public void onWifiVerboseLoggingStatusChanged(boolean enabled) { 870 numCalls++; 871 status = enabled; 872 } 873 } 874 875 public class TestSoftApCallback implements WifiManager.SoftApCallback { 876 final Object mSoftApLock; 877 SoftApState mCurrentSoftApState; 878 int currentState; 879 int currentFailureReason; 880 List<SoftApInfo> apInfoList = new ArrayList<>(); 881 SoftApInfo apInfoOnSingleApMode; 882 Map<SoftApInfo, List<WifiClient>> apInfoClients = new HashMap<>(); 883 List<WifiClient> currentClientList; 884 SoftApCapability currentSoftApCapability; 885 MacAddress lastBlockedClientMacAddress; 886 int lastBlockedClientReason; 887 boolean onStateChangedCalled = false; 888 boolean mOnSoftApStateChangedCalled = false; 889 boolean onSoftApCapabilityChangedCalled = false; 890 boolean onConnectedClientCalled = false; 891 boolean onConnectedClientChangedWithInfoCalled = false; 892 boolean onBlockedClientConnectingCalled = false; 893 int onSoftapInfoChangedCalledCount = 0; 894 int onSoftapInfoChangedWithListCalledCount = 0; 895 TestSoftApCallback(Object lock)896 TestSoftApCallback(Object lock) { 897 mSoftApLock = lock; 898 } 899 getOnStateChangedCalled()900 public boolean getOnStateChangedCalled() { 901 synchronized (mSoftApLock) { 902 return onStateChangedCalled; 903 } 904 } 905 906 /** 907 * Returns {@code true} if #onStateChanged(SoftApstate) was called, else {@code false}. 908 */ getOnSoftApStateChangedCalled()909 public boolean getOnSoftApStateChangedCalled() { 910 synchronized (mSoftApLock) { 911 return mOnSoftApStateChangedCalled; 912 } 913 } 914 getOnSoftapInfoChangedCalledCount()915 public int getOnSoftapInfoChangedCalledCount() { 916 synchronized (mSoftApLock) { 917 return onSoftapInfoChangedCalledCount; 918 } 919 } 920 getOnSoftApInfoChangedWithListCalledCount()921 public int getOnSoftApInfoChangedWithListCalledCount() { 922 synchronized (mSoftApLock) { 923 return onSoftapInfoChangedWithListCalledCount; 924 } 925 } 926 getOnSoftApCapabilityChangedCalled()927 public boolean getOnSoftApCapabilityChangedCalled() { 928 synchronized (mSoftApLock) { 929 return onSoftApCapabilityChangedCalled; 930 } 931 } 932 getOnConnectedClientChangedWithInfoCalled()933 public boolean getOnConnectedClientChangedWithInfoCalled() { 934 synchronized (mSoftApLock) { 935 return onConnectedClientChangedWithInfoCalled; 936 } 937 } 938 getOnConnectedClientCalled()939 public boolean getOnConnectedClientCalled() { 940 synchronized (mSoftApLock) { 941 return onConnectedClientCalled; 942 } 943 } 944 getOnBlockedClientConnectingCalled()945 public boolean getOnBlockedClientConnectingCalled() { 946 synchronized (mSoftApLock) { 947 return onBlockedClientConnectingCalled; 948 } 949 } 950 951 /** 952 * Returns the latest SoftApState passed into #onStateChanged(SoftApState). 953 */ getCurrentSoftApState()954 public SoftApState getCurrentSoftApState() { 955 synchronized (mSoftApLock) { 956 return mCurrentSoftApState; 957 } 958 } 959 getCurrentState()960 public int getCurrentState() { 961 synchronized (mSoftApLock) { 962 return currentState; 963 } 964 } 965 getCurrentStateFailureReason()966 public int getCurrentStateFailureReason() { 967 synchronized (mSoftApLock) { 968 return currentFailureReason; 969 } 970 } 971 getCurrentClientList()972 public List<WifiClient> getCurrentClientList() { 973 synchronized (mSoftApLock) { 974 return new ArrayList<>(currentClientList); 975 } 976 } 977 getCurrentSoftApInfo()978 public SoftApInfo getCurrentSoftApInfo() { 979 synchronized (mSoftApLock) { 980 return apInfoOnSingleApMode; 981 } 982 } 983 getCurrentSoftApInfoList()984 public List<SoftApInfo> getCurrentSoftApInfoList() { 985 synchronized (mSoftApLock) { 986 return new ArrayList<>(apInfoList); 987 } 988 } 989 getCurrentSoftApCapability()990 public SoftApCapability getCurrentSoftApCapability() { 991 synchronized (mSoftApLock) { 992 return currentSoftApCapability; 993 } 994 } 995 getLastBlockedClientMacAddress()996 public MacAddress getLastBlockedClientMacAddress() { 997 synchronized (mSoftApLock) { 998 return lastBlockedClientMacAddress; 999 } 1000 } 1001 getLastBlockedClientReason()1002 public int getLastBlockedClientReason() { 1003 synchronized (mSoftApLock) { 1004 return lastBlockedClientReason; 1005 } 1006 } 1007 1008 @Override onStateChanged(int state, int failureReason)1009 public void onStateChanged(int state, int failureReason) { 1010 synchronized (mSoftApLock) { 1011 currentState = state; 1012 currentFailureReason = failureReason; 1013 onStateChangedCalled = true; 1014 } 1015 } 1016 1017 @Override onStateChanged(SoftApState state)1018 public void onStateChanged(SoftApState state) { 1019 synchronized (mSoftApLock) { 1020 mCurrentSoftApState = state; 1021 mOnSoftApStateChangedCalled = true; 1022 onStateChanged(state.getState(), 1023 state.getState() == WIFI_AP_STATE_FAILED ? state.getFailureReason() : 0); 1024 } 1025 } 1026 1027 @Override onConnectedClientsChanged(List<WifiClient> clients)1028 public void onConnectedClientsChanged(List<WifiClient> clients) { 1029 synchronized (mSoftApLock) { 1030 currentClientList = new ArrayList<>(clients); 1031 onConnectedClientCalled = true; 1032 } 1033 } 1034 1035 @Override onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients)1036 public void onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients) { 1037 synchronized (mSoftApLock) { 1038 apInfoClients.put(info, clients); 1039 onConnectedClientChangedWithInfoCalled = true; 1040 } 1041 } 1042 1043 @Override onInfoChanged(List<SoftApInfo> infoList)1044 public void onInfoChanged(List<SoftApInfo> infoList) { 1045 synchronized (mSoftApLock) { 1046 apInfoList = new ArrayList<>(infoList); 1047 onSoftapInfoChangedWithListCalledCount++; 1048 } 1049 } 1050 1051 @Override onInfoChanged(SoftApInfo softApInfo)1052 public void onInfoChanged(SoftApInfo softApInfo) { 1053 synchronized (mSoftApLock) { 1054 apInfoOnSingleApMode = softApInfo; 1055 onSoftapInfoChangedCalledCount++; 1056 } 1057 } 1058 1059 @Override onCapabilityChanged(SoftApCapability softApCapability)1060 public void onCapabilityChanged(SoftApCapability softApCapability) { 1061 synchronized (mSoftApLock) { 1062 currentSoftApCapability = softApCapability; 1063 onSoftApCapabilityChangedCalled = true; 1064 } 1065 } 1066 1067 @Override onBlockedClientConnecting(WifiClient client, int blockedReason)1068 public void onBlockedClientConnecting(WifiClient client, int blockedReason) { 1069 synchronized (mSoftApLock) { 1070 lastBlockedClientMacAddress = client.getMacAddress(); 1071 lastBlockedClientReason = blockedReason; 1072 onBlockedClientConnectingCalled = true; 1073 } 1074 } 1075 } 1076 1077 private static class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { 1078 Object hotspotLock; 1079 WifiManager.LocalOnlyHotspotReservation reservation = null; 1080 boolean onStartedCalled = false; 1081 boolean onStoppedCalled = false; 1082 boolean onFailedCalled = false; 1083 int failureReason = -1; 1084 TestLocalOnlyHotspotCallback(Object lock)1085 TestLocalOnlyHotspotCallback(Object lock) { 1086 hotspotLock = lock; 1087 } 1088 1089 @Override onStarted(WifiManager.LocalOnlyHotspotReservation r)1090 public void onStarted(WifiManager.LocalOnlyHotspotReservation r) { 1091 synchronized (hotspotLock) { 1092 reservation = r; 1093 onStartedCalled = true; 1094 hotspotLock.notify(); 1095 } 1096 } 1097 1098 @Override onStopped()1099 public void onStopped() { 1100 synchronized (hotspotLock) { 1101 onStoppedCalled = true; 1102 hotspotLock.notify(); 1103 } 1104 } 1105 1106 @Override onFailed(int reason)1107 public void onFailed(int reason) { 1108 synchronized (hotspotLock) { 1109 onFailedCalled = true; 1110 failureReason = reason; 1111 hotspotLock.notify(); 1112 } 1113 } 1114 } 1115 getSupportedSoftApBand(SoftApCapability capability)1116 private List<Integer> getSupportedSoftApBand(SoftApCapability capability) { 1117 List<Integer> supportedApBands = new ArrayList<>(); 1118 if (sWifiManager.is24GHzBandSupported() && capability.areFeaturesSupported( 1119 SoftApCapability.SOFTAP_FEATURE_BAND_24G_SUPPORTED)) { 1120 supportedApBands.add(SoftApConfiguration.BAND_2GHZ); 1121 } 1122 if (sWifiManager.is5GHzBandSupported() && capability.areFeaturesSupported( 1123 SoftApCapability.SOFTAP_FEATURE_BAND_5G_SUPPORTED)) { 1124 supportedApBands.add(SoftApConfiguration.BAND_5GHZ); 1125 } 1126 if (sWifiManager.is6GHzBandSupported() && capability.areFeaturesSupported( 1127 SoftApCapability.SOFTAP_FEATURE_BAND_6G_SUPPORTED)) { 1128 supportedApBands.add(SoftApConfiguration.BAND_6GHZ); 1129 } 1130 if (sWifiManager.is60GHzBandSupported() && capability.areFeaturesSupported( 1131 SoftApCapability.SOFTAP_FEATURE_BAND_60G_SUPPORTED)) { 1132 supportedApBands.add(SoftApConfiguration.BAND_60GHZ); 1133 } 1134 return supportedApBands; 1135 } 1136 startLocalOnlyHotspot()1137 private TestLocalOnlyHotspotCallback startLocalOnlyHotspot() { 1138 // Location mode must be enabled for this test 1139 if (!isLocationEnabled()) { 1140 fail("Please enable location for this test"); 1141 } 1142 1143 TestExecutor executor = new TestExecutor(); 1144 TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock); 1145 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 1146 List<Integer> supportedSoftApBands = new ArrayList<>(); 1147 try { 1148 uiAutomation.adoptShellPermissionIdentity(); 1149 verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback); 1150 supportedSoftApBands = getSupportedSoftApBand( 1151 lohsSoftApCallback.getCurrentSoftApCapability()); 1152 } catch (Exception ex) { 1153 } finally { 1154 // clean up 1155 unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback); 1156 uiAutomation.dropShellPermissionIdentity(); 1157 } 1158 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); 1159 synchronized (mLock) { 1160 try { 1161 sWifiManager.startLocalOnlyHotspot(callback, null); 1162 // now wait for callback 1163 mLock.wait(TEST_WAIT_DURATION_MS); 1164 } catch (InterruptedException e) { 1165 } 1166 // check if we got the callback 1167 assertTrue(callback.onStartedCalled); 1168 1169 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); 1170 assertNotNull(softApConfig); 1171 int securityType = softApConfig.getSecurityType(); 1172 if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN 1173 || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK 1174 || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) { 1175 assertNotNull(softApConfig.toWifiConfiguration()); 1176 } else { 1177 assertNull(softApConfig.toWifiConfiguration()); 1178 } 1179 if (!hasAutomotiveFeature()) { 1180 assertEquals(supportedSoftApBands.size() > 0 ? supportedSoftApBands.get(0) 1181 : SoftApConfiguration.BAND_2GHZ, 1182 callback.reservation.getSoftApConfiguration().getBand()); 1183 } 1184 assertFalse(callback.onFailedCalled); 1185 assertFalse(callback.onStoppedCalled); 1186 } 1187 return callback; 1188 } 1189 stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled)1190 private void stopLocalOnlyHotspot(TestLocalOnlyHotspotCallback callback, boolean wifiEnabled) { 1191 synchronized (sMySync) { 1192 // we are expecting a new state 1193 sMySync.expectedState = STATE_WIFI_CHANGING; 1194 1195 // now shut down LocalOnlyHotspot 1196 if (callback.reservation != null) { 1197 callback.reservation.close(); 1198 } 1199 1200 try { 1201 waitForExpectedWifiState(wifiEnabled); 1202 } catch (InterruptedException e) { } 1203 } 1204 } 1205 1206 /** 1207 * Verify that calls to startLocalOnlyHotspot succeed with proper permissions. 1208 * 1209 * Note: Location mode must be enabled for this test. 1210 */ 1211 @Test testStartLocalOnlyHotspotSuccess()1212 public void testStartLocalOnlyHotspotSuccess() throws Exception { 1213 // check that softap mode is supported by the device 1214 if (!sWifiManager.isPortableHotspotSupported()) { 1215 return; 1216 } 1217 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 1218 if (wifiEnabled) { 1219 // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's 1220 // no STA+AP concurrency. 1221 ShellIdentityUtils.invokeWithShellPermissions(() -> 1222 sWifiManager.setWifiEnabled(false)); 1223 PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 1224 () -> !sWifiManager.isWifiEnabled()); 1225 SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled"); 1226 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 1227 () -> sWifiManager.isWifiEnabled()); 1228 } 1229 runWithScanning(() -> { 1230 TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); 1231 1232 // add sleep to avoid calling stopLocalOnlyHotspot before TetherController 1233 // initialization. 1234 // TODO: remove this sleep as soon as b/124330089 is fixed. 1235 Log.d(TAG, "Sleeping for 2 seconds"); 1236 Thread.sleep(2000); 1237 1238 stopLocalOnlyHotspot(callback, wifiEnabled); 1239 1240 // wifi should either stay on, or come back on 1241 assertEquals(wifiEnabled, sWifiManager.isWifiEnabled()); 1242 }, false); 1243 } 1244 1245 /** 1246 * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. 1247 */ 1248 @Test testDeprecatedApis()1249 public void testDeprecatedApis() throws Exception { 1250 WifiConfiguration wifiConfiguration = new WifiConfiguration(); 1251 wifiConfiguration.SSID = SSID1; 1252 wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 1253 1254 assertEquals(INVALID_NETWORK_ID, 1255 sWifiManager.addNetwork(wifiConfiguration)); 1256 assertEquals(INVALID_NETWORK_ID, 1257 sWifiManager.updateNetwork(wifiConfiguration)); 1258 assertFalse(sWifiManager.enableNetwork(0, true)); 1259 assertFalse(sWifiManager.disableNetwork(0)); 1260 assertFalse(sWifiManager.removeNetwork(0)); 1261 assertFalse(sWifiManager.disconnect()); 1262 assertFalse(sWifiManager.reconnect()); 1263 assertFalse(sWifiManager.reassociate()); 1264 assertTrue(sWifiManager.getConfiguredNetworks().isEmpty()); 1265 1266 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 1267 // now we should fail to toggle wifi state. 1268 assertFalse(sWifiManager.setWifiEnabled(!wifiEnabled)); 1269 Thread.sleep(TEST_WAIT_DURATION_MS); 1270 assertEquals(wifiEnabled, sWifiManager.isWifiEnabled()); 1271 } 1272 1273 /** 1274 * Test the WifiManager APIs that return whether a feature is supported. 1275 */ 1276 @Test testGetSupportedFeatures()1277 public void testGetSupportedFeatures() { 1278 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1279 // Skip the test if wifi module version is older than S. 1280 return; 1281 } 1282 sWifiManager.isMakeBeforeBreakWifiSwitchingSupported(); 1283 sWifiManager.isStaBridgedApConcurrencySupported(); 1284 sWifiManager.isDualBandSimultaneousSupported(); 1285 sWifiManager.isTidToLinkMappingNegotiationSupported(); 1286 } 1287 1288 /** 1289 * Verify non DO apps cannot call removeNonCallerConfiguredNetworks. 1290 */ 1291 @Test testRemoveNonCallerConfiguredNetworksNotAllowed()1292 public void testRemoveNonCallerConfiguredNetworksNotAllowed() { 1293 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1294 // Skip the test if wifi module version is older than S. 1295 return; 1296 } 1297 try { 1298 sWifiManager.removeNonCallerConfiguredNetworks(); 1299 fail("Expected security exception for non DO app"); 1300 } catch (SecurityException e) { 1301 } 1302 } 1303 buildTestNetworkSelectionConfig()1304 private WifiNetworkSelectionConfig buildTestNetworkSelectionConfig() { 1305 TEST_FREQUENCY_WEIGHTS.put(2400, WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_LOW); 1306 TEST_FREQUENCY_WEIGHTS.put(6000, WifiNetworkSelectionConfig.FREQUENCY_WEIGHT_HIGH); 1307 1308 return new WifiNetworkSelectionConfig.Builder() 1309 .setAssociatedNetworkSelectionOverride( 1310 WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_ENABLED) 1311 .setSufficiencyCheckEnabledWhenScreenOff(false) 1312 .setSufficiencyCheckEnabledWhenScreenOn(false) 1313 .setUserConnectChoiceOverrideEnabled(false) 1314 .setLastSelectionWeightEnabled(false) 1315 .setRssiThresholds(ScanResult.WIFI_BAND_24_GHZ, TEST_RSSI2_THRESHOLDS) 1316 .setRssiThresholds(ScanResult.WIFI_BAND_5_GHZ, TEST_RSSI5_THRESHOLDS) 1317 .setRssiThresholds(ScanResult.WIFI_BAND_6_GHZ, TEST_RSSI6_THRESHOLDS) 1318 .setFrequencyWeights(TEST_FREQUENCY_WEIGHTS) 1319 .build(); 1320 } 1321 1322 /** 1323 * Verify the invalid and valid usages of {@code WifiManager#setNetworkSelectionConfig}. 1324 */ 1325 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1326 @Test testSetNetworkSelectionConfig()1327 public void testSetNetworkSelectionConfig() throws Exception { 1328 AtomicReference<WifiNetworkSelectionConfig> config = new AtomicReference<>(); 1329 Consumer<WifiNetworkSelectionConfig> listener = new Consumer<WifiNetworkSelectionConfig>() { 1330 @Override 1331 public void accept(WifiNetworkSelectionConfig value) { 1332 synchronized (mLock) { 1333 config.set(value); 1334 mLock.notify(); 1335 } 1336 } 1337 }; 1338 1339 // cache current WifiNetworkSelectionConfig 1340 ShellIdentityUtils.invokeWithShellPermissions( 1341 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener)); 1342 synchronized (mLock) { 1343 mLock.wait(TEST_WAIT_DURATION_MS); 1344 } 1345 WifiNetworkSelectionConfig currentConfig = config.get(); 1346 1347 try { 1348 WifiNetworkSelectionConfig nsConfig = buildTestNetworkSelectionConfig(); 1349 assertTrue(nsConfig.getAssociatedNetworkSelectionOverride() 1350 == WifiNetworkSelectionConfig.ASSOCIATED_NETWORK_SELECTION_OVERRIDE_ENABLED); 1351 assertFalse(nsConfig.isSufficiencyCheckEnabledWhenScreenOff()); 1352 assertFalse(nsConfig.isSufficiencyCheckEnabledWhenScreenOn()); 1353 assertFalse(nsConfig.isUserConnectChoiceOverrideEnabled()); 1354 assertFalse(nsConfig.isLastSelectionWeightEnabled()); 1355 assertArrayEquals(TEST_RSSI2_THRESHOLDS, 1356 nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_24_GHZ)); 1357 assertArrayEquals(TEST_RSSI5_THRESHOLDS, 1358 nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_5_GHZ)); 1359 assertArrayEquals(TEST_RSSI6_THRESHOLDS, 1360 nsConfig.getRssiThresholds(ScanResult.WIFI_BAND_6_GHZ)); 1361 assertTrue(TEST_FREQUENCY_WEIGHTS.contentEquals(nsConfig.getFrequencyWeights())); 1362 assertThrows(SecurityException.class, 1363 () -> sWifiManager.setNetworkSelectionConfig(nsConfig)); 1364 ShellIdentityUtils.invokeWithShellPermissions( 1365 () -> sWifiManager.setNetworkSelectionConfig(nsConfig)); 1366 ShellIdentityUtils.invokeWithShellPermissions( 1367 () -> sWifiManager.setNetworkSelectionConfig( 1368 new WifiNetworkSelectionConfig.Builder().build())); 1369 } finally { 1370 // restore WifiNetworkSelectionConfig 1371 ShellIdentityUtils.invokeWithShellPermissions( 1372 () -> sWifiManager.setNetworkSelectionConfig(currentConfig)); 1373 } 1374 } 1375 1376 /** 1377 * Verify the invalid and valid usages of {@code WifiManager#getNetworkSelectionConfig}. 1378 */ 1379 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU, codeName = "Tiramisu") 1380 @Test testGetNetworkSelectionConfig()1381 public void testGetNetworkSelectionConfig() throws Exception { 1382 AtomicReference<WifiNetworkSelectionConfig> config = new AtomicReference<>(); 1383 Consumer<WifiNetworkSelectionConfig> listener = new Consumer<WifiNetworkSelectionConfig>() { 1384 @Override 1385 public void accept(WifiNetworkSelectionConfig value) { 1386 synchronized (mLock) { 1387 config.set(value); 1388 mLock.notify(); 1389 } 1390 } 1391 }; 1392 1393 // cache current WifiNetworkSelectionConfig 1394 ShellIdentityUtils.invokeWithShellPermissions( 1395 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener)); 1396 synchronized (mLock) { 1397 mLock.wait(TEST_WAIT_DURATION_MS); 1398 } 1399 WifiNetworkSelectionConfig currentConfig = config.get(); 1400 1401 try { 1402 // Test invalid inputs trigger IllegalArgumentException 1403 assertThrows("null executor should trigger exception", NullPointerException.class, 1404 () -> sWifiManager.getNetworkSelectionConfig(null, listener)); 1405 assertThrows("null listener should trigger exception", NullPointerException.class, 1406 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, null)); 1407 1408 // Test caller with no permission triggers SecurityException. 1409 assertThrows("No permission should trigger SecurityException", SecurityException.class, 1410 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener)); 1411 1412 // Test get/set WifiNetworkSelectionConfig 1413 WifiNetworkSelectionConfig nsConfig = buildTestNetworkSelectionConfig(); 1414 ShellIdentityUtils.invokeWithShellPermissions( 1415 () -> sWifiManager.setNetworkSelectionConfig(nsConfig)); 1416 ShellIdentityUtils.invokeWithShellPermissions( 1417 () -> sWifiManager.getNetworkSelectionConfig(mExecutor, listener)); 1418 synchronized (mLock) { 1419 mLock.wait(TEST_WAIT_DURATION_MS); 1420 } 1421 assertTrue(config.get().equals(nsConfig)); 1422 } finally { 1423 // restore WifiNetworkSelectionConfig 1424 ShellIdentityUtils.invokeWithShellPermissions( 1425 () -> sWifiManager.setNetworkSelectionConfig(currentConfig)); 1426 } 1427 } 1428 1429 /** 1430 * Verify setting the screen-on connectivity scan delay. 1431 */ 1432 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1433 @Test testSetOneShotScreenOnConnectivityScanDelayMillis()1434 public void testSetOneShotScreenOnConnectivityScanDelayMillis() { 1435 assertThrows(SecurityException.class, 1436 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(100)); 1437 assertThrows(IllegalArgumentException.class, () -> { 1438 ShellIdentityUtils.invokeWithShellPermissions( 1439 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(-1)); 1440 }); 1441 ShellIdentityUtils.invokeWithShellPermissions( 1442 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(10000)); 1443 ShellIdentityUtils.invokeWithShellPermissions( 1444 () -> sWifiManager.setOneShotScreenOnConnectivityScanDelayMillis(0)); 1445 } 1446 1447 /** 1448 * Verify setting the scan schedule. 1449 */ 1450 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1451 @Test testSetScreenOnScanSchedule()1452 public void testSetScreenOnScanSchedule() { 1453 List<WifiManager.ScreenOnScanSchedule> schedules = new ArrayList<>(); 1454 schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(20), 1455 WifiScanner.SCAN_TYPE_HIGH_ACCURACY)); 1456 schedules.add(new WifiManager.ScreenOnScanSchedule(Duration.ofSeconds(40), 1457 WifiScanner.SCAN_TYPE_LOW_LATENCY)); 1458 assertEquals(20, schedules.get(0).getScanInterval().toSeconds()); 1459 assertEquals(40, schedules.get(1).getScanInterval().toSeconds()); 1460 assertEquals(WifiScanner.SCAN_TYPE_HIGH_ACCURACY, schedules.get(0).getScanType()); 1461 assertEquals(WifiScanner.SCAN_TYPE_LOW_LATENCY, schedules.get(1).getScanType()); 1462 ShellIdentityUtils.invokeWithShellPermissions( 1463 () -> sWifiManager.setScreenOnScanSchedule(schedules)); 1464 ShellIdentityUtils.invokeWithShellPermissions( 1465 () -> sWifiManager.setScreenOnScanSchedule(null)); 1466 1467 // Creating an invalid ScanSchedule should throw an exception 1468 assertThrows(IllegalArgumentException.class, () -> new WifiManager.ScreenOnScanSchedule( 1469 null, WifiScanner.SCAN_TYPE_HIGH_ACCURACY)); 1470 } 1471 1472 /** 1473 * Verify a normal app cannot set the scan schedule. 1474 */ 1475 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1476 @Test testSetScreenOnScanScheduleNoPermission()1477 public void testSetScreenOnScanScheduleNoPermission() { 1478 assertThrows(SecurityException.class, () -> sWifiManager.setScreenOnScanSchedule(null)); 1479 } 1480 1481 /** 1482 * Test coverage for the constructor of AddNetworkResult. 1483 */ 1484 @Test testAddNetworkResultCreation()1485 public void testAddNetworkResultCreation() { 1486 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1487 // Skip the test if wifi module version is older than S. 1488 return; 1489 } 1490 int statusCode = WifiManager.AddNetworkResult.STATUS_NO_PERMISSION; 1491 int networkId = 5; 1492 WifiManager.AddNetworkResult result = new WifiManager.AddNetworkResult( 1493 statusCode, networkId); 1494 assertEquals("statusCode should match", statusCode, result.statusCode); 1495 assertEquals("networkId should match", networkId, result.networkId); 1496 } 1497 1498 /** 1499 * Verify {@link WifiManager#setSsidsAllowlist(Set)} can be called with sufficient 1500 * privilege. 1501 */ 1502 @Test testGetAndSetSsidsAllowlist()1503 public void testGetAndSetSsidsAllowlist() { 1504 Set<WifiSsid> ssids = new ArraySet<>(); 1505 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1506 ShellIdentityUtils.invokeWithShellPermissions( 1507 () -> sWifiManager.setSsidsAllowlist(ssids)); 1508 1509 ShellIdentityUtils.invokeWithShellPermissions( 1510 () -> assertEquals("Ssids should match", ssids, 1511 sWifiManager.getSsidsAllowlist())); 1512 1513 ShellIdentityUtils.invokeWithShellPermissions( 1514 () -> sWifiManager.setSsidsAllowlist(Collections.EMPTY_SET)); 1515 ShellIdentityUtils.invokeWithShellPermissions( 1516 () -> assertEquals("Should equal to empty set", 1517 Collections.EMPTY_SET, 1518 sWifiManager.getSsidsAllowlist())); 1519 1520 try { 1521 sWifiManager.setSsidsAllowlist(Collections.EMPTY_SET); 1522 fail("Expected SecurityException when called without permission"); 1523 } catch (SecurityException e) { 1524 // expect the exception 1525 } 1526 } 1527 1528 class TestPnoScanResultsCallback implements WifiManager.PnoScanResultsCallback { 1529 public CountDownLatch latch = new CountDownLatch(1); 1530 private boolean mRegisterSuccess; 1531 private int mRegisterFailedReason = -1; 1532 private int mRemovedReason = -1; 1533 private List<ScanResult> mScanResults; 1534 1535 @Override onScanResultsAvailable(List<ScanResult> scanResults)1536 public void onScanResultsAvailable(List<ScanResult> scanResults) { 1537 mScanResults = scanResults; 1538 latch.countDown(); 1539 } 1540 1541 @Override onRegisterSuccess()1542 public void onRegisterSuccess() { 1543 mRegisterSuccess = true; 1544 latch.countDown(); 1545 } 1546 1547 @Override onRegisterFailed(int reason)1548 public void onRegisterFailed(int reason) { 1549 mRegisterFailedReason = reason; 1550 latch.countDown(); 1551 } 1552 1553 @Override onRemoved(int reason)1554 public void onRemoved(int reason) { 1555 mRemovedReason = reason; 1556 latch.countDown(); 1557 } 1558 isRegisterSuccess()1559 public boolean isRegisterSuccess() { 1560 return mRegisterSuccess; 1561 } 1562 getRemovedReason()1563 public int getRemovedReason() { 1564 return mRemovedReason; 1565 } 1566 getRegisterFailedReason()1567 public int getRegisterFailedReason() { 1568 return mRegisterFailedReason; 1569 } 1570 getScanResults()1571 public List<ScanResult> getScanResults() { 1572 return mScanResults; 1573 } 1574 } 1575 1576 /** 1577 * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor, 1578 * WifiManager.PnoScanResultsCallback)} can be called with proper permissions. 1579 */ 1580 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1581 @Test testSetExternalPnoScanRequestSuccess()1582 public void testSetExternalPnoScanRequestSuccess() throws Exception { 1583 TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback(); 1584 List<WifiSsid> ssids = new ArrayList<>(); 1585 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1586 int[] frequencies = new int[] {2412, 5180, 5805}; 1587 1588 assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess()); 1589 ShellIdentityUtils.invokeWithShellPermissions( 1590 () -> sWifiManager.setExternalPnoScanRequest( 1591 ssids, frequencies, Executors.newSingleThreadExecutor(), callback)); 1592 1593 callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS); 1594 if (sWifiManager.isPreferredNetworkOffloadSupported()) { 1595 assertTrue("Expect register success or failed due to resource busy", 1596 callback.isRegisterSuccess() 1597 || callback.getRegisterFailedReason() == WifiManager.PnoScanResultsCallback 1598 .REGISTER_PNO_CALLBACK_RESOURCE_BUSY); 1599 } else { 1600 assertEquals("Expect register fail due to not supported.", 1601 WifiManager.PnoScanResultsCallback.REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED, 1602 callback.getRegisterFailedReason()); 1603 } 1604 sWifiManager.clearExternalPnoScanRequest(); 1605 } 1606 1607 /** 1608 * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor, 1609 * WifiManager.PnoScanResultsCallback)} can be called with null frequency. 1610 */ 1611 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1612 @Test testSetExternalPnoScanRequestSuccessNullFrequency()1613 public void testSetExternalPnoScanRequestSuccessNullFrequency() throws Exception { 1614 TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback(); 1615 List<WifiSsid> ssids = new ArrayList<>(); 1616 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1617 1618 ShellIdentityUtils.invokeWithShellPermissions( 1619 () -> sWifiManager.setExternalPnoScanRequest( 1620 ssids, null, Executors.newSingleThreadExecutor(), callback)); 1621 sWifiManager.clearExternalPnoScanRequest(); 1622 } 1623 1624 /** 1625 * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor, 1626 * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many SSIDs. 1627 */ 1628 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1629 @Test testSetExternalPnoScanRequestTooManySsidsException()1630 public void testSetExternalPnoScanRequestTooManySsidsException() throws Exception { 1631 TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback(); 1632 List<WifiSsid> ssids = new ArrayList<>(); 1633 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1634 ssids.add(WifiSsid.fromBytes("TEST_SSID_2".getBytes(StandardCharsets.UTF_8))); 1635 ssids.add(WifiSsid.fromBytes("TEST_SSID_3".getBytes(StandardCharsets.UTF_8))); 1636 1637 assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess()); 1638 assertThrows(IllegalArgumentException.class, () -> { 1639 ShellIdentityUtils.invokeWithShellPermissions( 1640 () -> sWifiManager.setExternalPnoScanRequest( 1641 ssids, null, Executors.newSingleThreadExecutor(), callback)); 1642 }); 1643 } 1644 1645 /** 1646 * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor, 1647 * WifiManager.PnoScanResultsCallback)} throws an Exception if called with too many frequencies. 1648 */ 1649 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1650 @Test testSetExternalPnoScanRequestTooManyFrequenciesException()1651 public void testSetExternalPnoScanRequestTooManyFrequenciesException() throws Exception { 1652 TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback(); 1653 List<WifiSsid> ssids = new ArrayList<>(); 1654 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1655 int[] frequencies = new int[] {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452, 2457, 2462, 1656 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805}; 1657 1658 assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess()); 1659 assertThrows(IllegalArgumentException.class, () -> { 1660 ShellIdentityUtils.invokeWithShellPermissions( 1661 () -> sWifiManager.setExternalPnoScanRequest( 1662 ssids, frequencies, Executors.newSingleThreadExecutor(), callback)); 1663 }); 1664 } 1665 1666 /** 1667 * Verify {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor, 1668 * WifiManager.PnoScanResultsCallback)} cannot be called without permission. 1669 */ 1670 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 1671 @Test testSetExternalPnoScanRequestNoPermission()1672 public void testSetExternalPnoScanRequestNoPermission() throws Exception { 1673 TestExecutor executor = new TestExecutor(); 1674 TestPnoScanResultsCallback callback = new TestPnoScanResultsCallback(); 1675 List<WifiSsid> ssids = new ArrayList<>(); 1676 ssids.add(WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8))); 1677 1678 assertFalse("Callback should be initialized unregistered", callback.isRegisterSuccess()); 1679 assertThrows(SecurityException.class, 1680 () -> sWifiManager.setExternalPnoScanRequest(ssids, null, executor, callback)); 1681 } 1682 1683 /** 1684 * Verify the invalid and valid usages of {@code WifiManager#getLastCallerInfoForApi}. 1685 */ 1686 @Test testGetLastCallerInfoForApi()1687 public void testGetLastCallerInfoForApi() throws Exception { 1688 AtomicReference<String> packageName = new AtomicReference<>(); 1689 AtomicBoolean enabled = new AtomicBoolean(false); 1690 BiConsumer<String, Boolean> listener = new BiConsumer<String, Boolean>() { 1691 @Override 1692 public void accept(String caller, Boolean value) { 1693 synchronized (mLock) { 1694 packageName.set(caller); 1695 enabled.set(value); 1696 mLock.notify(); 1697 } 1698 } 1699 }; 1700 // Test invalid inputs trigger IllegalArgumentException 1701 assertThrows("Invalid apiType should trigger exception", IllegalArgumentException.class, 1702 () -> sWifiManager.getLastCallerInfoForApi(-1, mExecutor, listener)); 1703 assertThrows("null executor should trigger exception", IllegalArgumentException.class, 1704 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, null, 1705 listener)); 1706 assertThrows("null listener should trigger exception", IllegalArgumentException.class, 1707 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, mExecutor, 1708 null)); 1709 1710 // Test caller with no permission triggers SecurityException. 1711 assertThrows("No permission should trigger SecurityException", SecurityException.class, 1712 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_SOFT_AP, 1713 mExecutor, listener)); 1714 1715 String expectedPackage = "android.net.wifi.cts"; 1716 boolean isEnabledBefore = sWifiManager.isWifiEnabled(); 1717 // toggle wifi and verify getting last caller 1718 setWifiEnabled(!isEnabledBefore); 1719 ShellIdentityUtils.invokeWithShellPermissions( 1720 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor, 1721 listener)); 1722 synchronized (mLock) { 1723 mLock.wait(TEST_WAIT_DURATION_MS); 1724 } 1725 1726 assertEquals("package does not match", expectedPackage, packageName.get()); 1727 assertEquals("enabled does not match", !isEnabledBefore, enabled.get()); 1728 1729 // toggle wifi again and verify last caller 1730 packageName.set(null); 1731 setWifiEnabled(isEnabledBefore); 1732 ShellIdentityUtils.invokeWithShellPermissions( 1733 () -> sWifiManager.getLastCallerInfoForApi(WifiManager.API_WIFI_ENABLED, mExecutor, 1734 listener)); 1735 synchronized (mLock) { 1736 mLock.wait(TEST_WAIT_DURATION_MS); 1737 } 1738 assertEquals("package does not match", expectedPackage, packageName.get()); 1739 assertEquals("enabled does not match", isEnabledBefore, enabled.get()); 1740 } 1741 1742 /** 1743 * Verify that {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws a 1744 * SecurityException when called by a normal app. 1745 */ 1746 @Test testAddNetworkPrivilegedNotAllowedForNormalApps()1747 public void testAddNetworkPrivilegedNotAllowedForNormalApps() { 1748 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1749 // Skip the test if wifi module version is older than S. 1750 return; 1751 } 1752 try { 1753 WifiConfiguration newOpenNetwork = new WifiConfiguration(); 1754 newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\""; 1755 sWifiManager.addNetworkPrivileged(newOpenNetwork); 1756 fail("A normal app should not be able to call this API."); 1757 } catch (SecurityException e) { 1758 } 1759 } 1760 1761 /** 1762 * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} throws an exception when 1763 * null is the input. 1764 */ 1765 @Test testAddNetworkPrivilegedBadInput()1766 public void testAddNetworkPrivilegedBadInput() { 1767 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1768 // Skip the test if wifi module version is older than S. 1769 return; 1770 } 1771 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 1772 try { 1773 uiAutomation.adoptShellPermissionIdentity(); 1774 sWifiManager.addNetworkPrivileged(null); 1775 fail("Expected IllegalArgumentException"); 1776 } catch (IllegalArgumentException e) { 1777 } finally { 1778 uiAutomation.dropShellPermissionIdentity(); 1779 } 1780 } 1781 1782 /** 1783 * Verify {@link WifiManager#getPrivilegedConnectedNetwork()} returns the currently 1784 * connected WifiConfiguration with randomized MAC address filtered out. 1785 */ 1786 @Test testGetPrivilegedConnectedNetworkSuccess()1787 public void testGetPrivilegedConnectedNetworkSuccess() throws Exception { 1788 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 1789 try { 1790 uiAutomation.adoptShellPermissionIdentity(); 1791 sWifiManager.startScan(); 1792 1793 WifiInfo wifiInfo = sWifiManager.getConnectionInfo(); 1794 int curNetworkId = wifiInfo.getNetworkId(); 1795 assertNotEquals("Should be connected to valid networkId", INVALID_NETWORK_ID, 1796 curNetworkId); 1797 WifiConfiguration curConfig = sWifiManager.getPrivilegedConnectedNetwork(); 1798 assertEquals("NetworkId should match", curNetworkId, curConfig.networkId); 1799 assertEquals("SSID should match", wifiInfo.getSSID(), curConfig.SSID); 1800 assertEquals("Randomized MAC should be filtered out", WifiInfo.DEFAULT_MAC_ADDRESS, 1801 curConfig.getRandomizedMacAddress().toString()); 1802 } finally { 1803 uiAutomation.dropShellPermissionIdentity(); 1804 } 1805 } 1806 1807 /** 1808 * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works properly when the 1809 * calling app has permissions. 1810 */ 1811 @Test testAddNetworkPrivilegedSuccess()1812 public void testAddNetworkPrivilegedSuccess() { 1813 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1814 // Skip the test if wifi module version is older than S. 1815 return; 1816 } 1817 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 1818 WifiManager.AddNetworkResult result = null; 1819 try { 1820 uiAutomation.adoptShellPermissionIdentity(); 1821 WifiConfiguration newOpenNetwork = new WifiConfiguration(); 1822 newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\""; 1823 result = sWifiManager.addNetworkPrivileged(newOpenNetwork); 1824 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode); 1825 assertTrue(result.networkId >= 0); 1826 List<WifiConfiguration> configuredNetworks = sWifiManager.getConfiguredNetworks(); 1827 boolean found = false; 1828 for (WifiConfiguration config : configuredNetworks) { 1829 if (config.networkId == result.networkId 1830 && config.SSID.equals(newOpenNetwork.SSID)) { 1831 found = true; 1832 break; 1833 } 1834 } 1835 assertTrue("addNetworkPrivileged returns success" 1836 + "but the network is not found in getConfiguredNetworks", found); 1837 1838 List<WifiConfiguration> privilegedConfiguredNetworks = 1839 sWifiManager.getPrivilegedConfiguredNetworks(); 1840 found = false; 1841 for (WifiConfiguration config : privilegedConfiguredNetworks) { 1842 if (config.networkId == result.networkId 1843 && config.SSID.equals(newOpenNetwork.SSID)) { 1844 found = true; 1845 break; 1846 } 1847 } 1848 assertTrue("addNetworkPrivileged returns success" 1849 + "but the network is not found in getPrivilegedConfiguredNetworks", found); 1850 1851 List<WifiConfiguration> callerConfiguredNetworks = 1852 sWifiManager.getCallerConfiguredNetworks(); 1853 found = false; 1854 for (WifiConfiguration config : callerConfiguredNetworks) { 1855 if (config.networkId == result.networkId 1856 && config.SSID.equals(newOpenNetwork.SSID)) { 1857 found = true; 1858 break; 1859 } 1860 } 1861 assertTrue("addNetworkPrivileged returns success" 1862 + "but the network is not found in getCallerConfiguredNetworks", found); 1863 } finally { 1864 if (null != result) { 1865 sWifiManager.removeNetwork(result.networkId); 1866 } 1867 uiAutomation.dropShellPermissionIdentity(); 1868 } 1869 } 1870 createConfig( String ssid, int type)1871 private WifiConfiguration createConfig( 1872 String ssid, int type) { 1873 WifiConfiguration config = new WifiConfiguration(); 1874 config.SSID = "\"" + ssid + "\""; 1875 config.setSecurityParams(type); 1876 // set necessary fields for different types. 1877 switch (type) { 1878 case WifiConfiguration.SECURITY_TYPE_OPEN: 1879 case WifiConfiguration.SECURITY_TYPE_OWE: 1880 break; 1881 case WifiConfiguration.SECURITY_TYPE_PSK: 1882 case WifiConfiguration.SECURITY_TYPE_SAE: 1883 config.preSharedKey = "\"1qaz@WSX\""; 1884 break; 1885 case WifiConfiguration.SECURITY_TYPE_EAP: 1886 case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE: 1887 case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT: 1888 config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM); 1889 break; 1890 } 1891 return config; 1892 } 1893 assertConfigsAreFound( List<WifiConfiguration> expectedConfigs, List<WifiConfiguration> configs)1894 private void assertConfigsAreFound( 1895 List<WifiConfiguration> expectedConfigs, 1896 List<WifiConfiguration> configs) { 1897 for (WifiConfiguration expectedConfig: expectedConfigs) { 1898 boolean found = false; 1899 for (WifiConfiguration config : configs) { 1900 if (config.networkId == expectedConfig.networkId 1901 && config.getKey().equals(expectedConfig.getKey())) { 1902 found = true; 1903 break; 1904 } 1905 } 1906 assertTrue("the network " + expectedConfig.getKey() + " is not found", found); 1907 } 1908 } 1909 1910 /** 1911 * Verify {@link WifiManager#addNetworkPrivileged(WifiConfiguration)} works 1912 * with merging types properly when the calling app has permissions. 1913 */ 1914 @Test testAddNetworkPrivilegedMergingTypeSuccess()1915 public void testAddNetworkPrivilegedMergingTypeSuccess() { 1916 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 1917 // Skip the test if wifi module version is older than S. 1918 return; 1919 } 1920 List<WifiConfiguration> baseConfigs = new ArrayList<>(); 1921 baseConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OPEN)); 1922 baseConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_PSK)); 1923 baseConfigs.add(createConfig("test-wpa2e-wpa3e-plki", 1924 WifiConfiguration.SECURITY_TYPE_EAP)); 1925 List<WifiConfiguration> upgradeConfigs = new ArrayList<>(); 1926 upgradeConfigs.add(createConfig("test-open-owe-jdur", WifiConfiguration.SECURITY_TYPE_OWE)); 1927 upgradeConfigs.add(createConfig("test-psk-sae-ijfe", WifiConfiguration.SECURITY_TYPE_SAE)); 1928 upgradeConfigs.add(createConfig("test-wpa2e-wpa3e-plki", 1929 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE)); 1930 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 1931 try { 1932 uiAutomation.adoptShellPermissionIdentity(); 1933 final int originalConfiguredNetworksNumber = 1934 sWifiManager.getConfiguredNetworks().size(); 1935 final int originalPrivilegedConfiguredNetworksNumber = 1936 sWifiManager.getPrivilegedConfiguredNetworks().size(); 1937 final int originalCallerConfiguredNetworksNumber = 1938 sWifiManager.getCallerConfiguredNetworks().size(); 1939 for (WifiConfiguration c: baseConfigs) { 1940 WifiManager.AddNetworkResult result = sWifiManager.addNetworkPrivileged(c); 1941 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode); 1942 assertTrue(result.networkId >= 0); 1943 c.networkId = result.networkId; 1944 } 1945 for (WifiConfiguration c: upgradeConfigs) { 1946 WifiManager.AddNetworkResult result = sWifiManager.addNetworkPrivileged(c); 1947 assertEquals(WifiManager.AddNetworkResult.STATUS_SUCCESS, result.statusCode); 1948 assertTrue(result.networkId >= 0); 1949 c.networkId = result.networkId; 1950 } 1951 // open/owe, psk/sae, and wpa2e/wpa3e should be merged 1952 // so they should have the same network ID. 1953 for (int i = 0; i < baseConfigs.size(); i++) { 1954 assertEquals(baseConfigs.get(i).networkId, upgradeConfigs.get(i).networkId); 1955 } 1956 1957 int numAddedConfigs = baseConfigs.size(); 1958 List<WifiConfiguration> expectedConfigs = new ArrayList<>(baseConfigs); 1959 if (SdkLevel.isAtLeastS()) { 1960 // S devices and above will return one additional config per each security type 1961 // added, so we include the number of both base and upgrade configs. 1962 numAddedConfigs += upgradeConfigs.size(); 1963 expectedConfigs.addAll(upgradeConfigs); 1964 } 1965 List<WifiConfiguration> configuredNetworks = sWifiManager.getConfiguredNetworks(); 1966 assertEquals(originalConfiguredNetworksNumber + numAddedConfigs, 1967 configuredNetworks.size()); 1968 assertConfigsAreFound(expectedConfigs, configuredNetworks); 1969 1970 List<WifiConfiguration> privilegedConfiguredNetworks = 1971 sWifiManager.getPrivilegedConfiguredNetworks(); 1972 assertEquals(originalPrivilegedConfiguredNetworksNumber + numAddedConfigs, 1973 privilegedConfiguredNetworks.size()); 1974 assertConfigsAreFound(expectedConfigs, privilegedConfiguredNetworks); 1975 1976 List<WifiConfiguration> callerConfiguredNetworks = 1977 sWifiManager.getCallerConfiguredNetworks(); 1978 assertEquals(originalCallerConfiguredNetworksNumber + numAddedConfigs, 1979 callerConfiguredNetworks.size()); 1980 assertConfigsAreFound(expectedConfigs, callerConfiguredNetworks); 1981 1982 } finally { 1983 for (WifiConfiguration c: baseConfigs) { 1984 if (c.networkId >= 0) { 1985 sWifiManager.removeNetwork(c.networkId); 1986 } 1987 } 1988 uiAutomation.dropShellPermissionIdentity(); 1989 } 1990 } 1991 1992 /** 1993 * Verify that applications can only have one registered LocalOnlyHotspot request at a time. 1994 * 1995 * Note: Location mode must be enabled for this test. 1996 */ 1997 @Test testStartLocalOnlyHotspotSingleRequestByApps()1998 public void testStartLocalOnlyHotspotSingleRequestByApps() throws Exception { 1999 // check that softap mode is supported by the device 2000 assumeTrue(sWifiManager.isPortableHotspotSupported()); 2001 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 2002 if (wifiEnabled) { 2003 // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's 2004 // no STA+AP concurrency. 2005 ShellIdentityUtils.invokeWithShellPermissions(() -> 2006 sWifiManager.setWifiEnabled(false)); 2007 PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 2008 () -> !sWifiManager.isWifiEnabled()); 2009 SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled"); 2010 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 2011 () -> sWifiManager.isWifiEnabled()); 2012 } 2013 2014 runWithScanning(() -> { 2015 boolean caughtException = false; 2016 TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); 2017 2018 // now make a second request - this should fail. 2019 TestLocalOnlyHotspotCallback callback2 = new TestLocalOnlyHotspotCallback(mLock); 2020 try { 2021 sWifiManager.startLocalOnlyHotspot(callback2, null); 2022 } catch (IllegalStateException e) { 2023 Log.d(TAG, "Caught the IllegalStateException we expected: called startLOHS twice"); 2024 caughtException = true; 2025 } 2026 if (!caughtException) { 2027 // second start did not fail, should clean up the hotspot. 2028 2029 // add sleep to avoid calling stopLocalOnlyHotspot before TetherController 2030 // initialization. 2031 // TODO: remove this sleep as soon as b/124330089 is fixed. 2032 Log.d(TAG, "Sleeping for 2 seconds"); 2033 Thread.sleep(2000); 2034 2035 stopLocalOnlyHotspot(callback2, wifiEnabled); 2036 } 2037 assertTrue(caughtException); 2038 2039 // add sleep to avoid calling stopLocalOnlyHotspot before TetherController 2040 // initialization. 2041 // TODO: remove this sleep as soon as b/124330089 is fixed. 2042 Log.d(TAG, "Sleeping for 2 seconds"); 2043 Thread.sleep(2000); 2044 2045 stopLocalOnlyHotspot(callback, wifiEnabled); 2046 }, false); 2047 } 2048 2049 private static class TestExecutor implements Executor { 2050 private ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>(); 2051 2052 @Override execute(Runnable task)2053 public void execute(Runnable task) { 2054 tasks.add(task); 2055 } 2056 runAll()2057 private void runAll() { 2058 Runnable task = tasks.poll(); 2059 while (task != null) { 2060 task.run(); 2061 task = tasks.poll(); 2062 } 2063 } 2064 } 2065 generateSoftApConfigBuilderWithSsid(String ssid)2066 private SoftApConfiguration.Builder generateSoftApConfigBuilderWithSsid(String ssid) { 2067 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2068 return new SoftApConfiguration.Builder().setWifiSsid( 2069 WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8))); 2070 } 2071 return new SoftApConfiguration.Builder().setSsid(ssid); 2072 } 2073 assertSsidEquals(SoftApConfiguration config, String expectedSsid)2074 private void assertSsidEquals(SoftApConfiguration config, String expectedSsid) { 2075 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2076 assertEquals(WifiSsid.fromBytes(expectedSsid.getBytes(StandardCharsets.UTF_8)), 2077 config.getWifiSsid()); 2078 } else { 2079 assertEquals(expectedSsid, config.getSsid()); 2080 } 2081 } 2082 unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback)2083 private void unregisterLocalOnlyHotspotSoftApCallback(TestSoftApCallback lohsSoftApCallback) { 2084 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2085 sWifiManager.unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback); 2086 } else { 2087 sWifiManager.unregisterSoftApCallback(lohsSoftApCallback); 2088 } 2089 } 2090 2091 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 2092 @Test testStartLocalOnlyHotspotWithSupportedBand()2093 public void testStartLocalOnlyHotspotWithSupportedBand() throws Exception { 2094 // check that softap mode is supported by the device 2095 if (!sWifiManager.isPortableHotspotSupported()) { 2096 return; 2097 } 2098 2099 TestExecutor executor = new TestExecutor(); 2100 TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock); 2101 setWifiEnabled(false); 2102 Thread.sleep(TEST_WAIT_DURATION_MS); 2103 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 2104 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 2105 try { 2106 uiAutomation.adoptShellPermissionIdentity(); 2107 verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback); 2108 SoftApConfiguration.Builder customConfigBuilder = 2109 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 2110 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 2111 2112 SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting( 2113 lohsSoftApCallback.getCurrentSoftApCapability()); 2114 // The devices which doesn't have SIM and default country code in system property 2115 // (ro.boot.wificountrycodeCountry) will return a null country code. Since country code 2116 // is mandatory for 5GHz/6GHz band, skip the softap operation on 5GHz & 6GHz only band. 2117 boolean skip5g6gBand = false; 2118 String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions( 2119 sWifiManager::getCountryCode); 2120 if (wifiCountryCode == null) { 2121 skip5g6gBand = true; 2122 Log.e(TAG, "Country Code is not available - Skip 5GHz and 6GHz test"); 2123 } 2124 for (int i = 0; i < testBandsAndChannels.size(); i++) { 2125 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); 2126 int testBand = testBandsAndChannels.keyAt(i); 2127 if (skip5g6gBand && (testBand == SoftApConfiguration.BAND_6GHZ 2128 || testBand == SoftApConfiguration.BAND_5GHZ)) { 2129 continue; 2130 } 2131 // WPA2_PSK is not allowed in 6GHz band. So test with WPA3_SAE which is 2132 // mandatory to support in 6GHz band. 2133 if (testBand == SoftApConfiguration.BAND_6GHZ) { 2134 if (lohsSoftApCallback.getCurrentSoftApCapability() 2135 .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { 2136 customConfigBuilder.setPassphrase(TEST_PASSPHRASE, 2137 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); 2138 } else { 2139 Log.e(TAG, "SoftAp 6GHz capability is advertized without WPA3 support"); 2140 continue; 2141 } 2142 } 2143 customConfigBuilder.setBand(testBand); 2144 sWifiManager.startLocalOnlyHotspot(customConfigBuilder.build(), executor, callback); 2145 // now wait for callback 2146 Thread.sleep(DURATION_SOFTAP_START_MS); 2147 2148 // Verify callback is run on the supplied executor 2149 assertFalse(callback.onStartedCalled); 2150 executor.runAll(); 2151 assertTrue(callback.onStartedCalled); 2152 assertNotNull(callback.reservation); 2153 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); 2154 assertEquals( 2155 WifiSsid.fromBytes(TEST_SSID_UNQUOTED.getBytes(StandardCharsets.UTF_8)), 2156 softApConfig.getWifiSsid()); 2157 assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); 2158 // Automotive mode can force the LOHS to specific bands 2159 if (!hasAutomotiveFeature()) { 2160 assertEquals(testBand, softApConfig.getBand()); 2161 } 2162 if (lohsSoftApCallback.getOnSoftapInfoChangedCalledCount() > 1) { 2163 assertTrue(lohsSoftApCallback.getCurrentSoftApInfo().getFrequency() > 0); 2164 } 2165 stopLocalOnlyHotspot(callback, wifiEnabled); 2166 } 2167 } finally { 2168 // clean up 2169 sWifiManager.unregisterSoftApCallback(lohsSoftApCallback); 2170 uiAutomation.dropShellPermissionIdentity(); 2171 } 2172 } 2173 2174 @Test testStartLocalOnlyHotspotWithConfigBssid()2175 public void testStartLocalOnlyHotspotWithConfigBssid() throws Exception { 2176 // check that softap mode is supported by the device 2177 if (!sWifiManager.isPortableHotspotSupported()) { 2178 return; 2179 } 2180 2181 TestExecutor executor = new TestExecutor(); 2182 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); 2183 TestSoftApCallback lohsSoftApCallback = new TestSoftApCallback(mLock); 2184 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 2185 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 2186 try { 2187 uiAutomation.adoptShellPermissionIdentity(); 2188 verifyLohsRegisterSoftApCallback(executor, lohsSoftApCallback); 2189 SoftApConfiguration.Builder customConfigBuilder = 2190 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 2191 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 2192 2193 boolean isSupportCustomizedMac = lohsSoftApCallback.getCurrentSoftApCapability() 2194 .areFeaturesSupported( 2195 SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION) 2196 && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S); 2197 if (isSupportCustomizedMac) { 2198 customConfigBuilder.setBssid(TEST_MAC).setMacRandomizationSetting( 2199 SoftApConfiguration.RANDOMIZATION_NONE); 2200 } 2201 SoftApConfiguration customConfig = customConfigBuilder.build(); 2202 2203 sWifiManager.startLocalOnlyHotspot(customConfig, executor, callback); 2204 // now wait for callback 2205 Thread.sleep(TEST_WAIT_DURATION_MS); 2206 2207 // Verify callback is run on the supplied executor 2208 assertFalse(callback.onStartedCalled); 2209 executor.runAll(); 2210 assertTrue(callback.onStartedCalled); 2211 2212 assertNotNull(callback.reservation); 2213 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); 2214 assertNotNull(softApConfig); 2215 if (isSupportCustomizedMac) { 2216 assertEquals(TEST_MAC, softApConfig.getBssid()); 2217 } 2218 assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED); 2219 assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); 2220 } finally { 2221 // clean up 2222 stopLocalOnlyHotspot(callback, wifiEnabled); 2223 unregisterLocalOnlyHotspotSoftApCallback(lohsSoftApCallback); 2224 uiAutomation.dropShellPermissionIdentity(); 2225 } 2226 } 2227 2228 @Test testStartLocalOnlyHotspotWithNullBssidConfig()2229 public void testStartLocalOnlyHotspotWithNullBssidConfig() throws Exception { 2230 // check that softap mode is supported by the device 2231 if (!sWifiManager.isPortableHotspotSupported()) { 2232 return; 2233 } 2234 SoftApConfiguration customConfig = 2235 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 2236 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) 2237 .build(); 2238 2239 TestExecutor executor = new TestExecutor(); 2240 TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback(mLock); 2241 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 2242 boolean wifiEnabled = sWifiManager.isWifiEnabled(); 2243 try { 2244 uiAutomation.adoptShellPermissionIdentity(); 2245 2246 sWifiManager.startLocalOnlyHotspot(customConfig, executor, callback); 2247 // now wait for callback 2248 Thread.sleep(TEST_WAIT_DURATION_MS); 2249 2250 // Verify callback is run on the supplied executor 2251 assertFalse(callback.onStartedCalled); 2252 executor.runAll(); 2253 assertTrue(callback.onStartedCalled); 2254 2255 assertNotNull(callback.reservation); 2256 SoftApConfiguration softApConfig = callback.reservation.getSoftApConfiguration(); 2257 assertNotNull(softApConfig); 2258 assertSsidEquals(softApConfig, TEST_SSID_UNQUOTED); 2259 assertEquals(TEST_PASSPHRASE, softApConfig.getPassphrase()); 2260 } finally { 2261 // clean up 2262 stopLocalOnlyHotspot(callback, wifiEnabled); 2263 uiAutomation.dropShellPermissionIdentity(); 2264 } 2265 } 2266 2267 /** 2268 * Read the content of the given resource file into a String. 2269 * 2270 * @param filename String name of the file 2271 * @return String 2272 * @throws IOException 2273 */ loadResourceFile(String filename)2274 private String loadResourceFile(String filename) throws IOException { 2275 InputStream in = getClass().getClassLoader().getResourceAsStream(filename); 2276 BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 2277 StringBuilder builder = new StringBuilder(); 2278 String line; 2279 while ((line = reader.readLine()) != null) { 2280 builder.append(line).append("\n"); 2281 } 2282 return builder.toString(); 2283 } 2284 2285 /** 2286 * Verify that changing the mac randomization setting of a Passpoint configuration. 2287 */ 2288 @Test testMacRandomizationSettingPasspoint()2289 public void testMacRandomizationSettingPasspoint() throws Exception { 2290 String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_CA_CERT); 2291 PasspointConfiguration config = 2292 ConfigParser.parsePasspointConfig(TYPE_WIFI_CONFIG, configStr.getBytes()); 2293 String fqdn = config.getHomeSp().getFqdn(); 2294 String uniqueId = config.getUniqueId(); 2295 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 2296 try { 2297 uiAutomation.adoptShellPermissionIdentity(); 2298 2299 sWifiManager.addOrUpdatePasspointConfiguration(config); 2300 PasspointConfiguration passpointConfig = getTargetPasspointConfiguration( 2301 sWifiManager.getPasspointConfigurations(), uniqueId); 2302 assertNotNull("The installed passpoint profile is missing", passpointConfig); 2303 assertTrue("Mac randomization should be enabled for passpoint networks by default.", 2304 passpointConfig.isMacRandomizationEnabled()); 2305 2306 sWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, false); 2307 passpointConfig = getTargetPasspointConfiguration( 2308 sWifiManager.getPasspointConfigurations(), uniqueId); 2309 assertNotNull("The installed passpoint profile is missing", passpointConfig); 2310 assertFalse("Mac randomization should be disabled by the API call.", 2311 passpointConfig.isMacRandomizationEnabled()); 2312 } finally { 2313 // Clean up 2314 sWifiManager.removePasspointConfiguration(fqdn); 2315 uiAutomation.dropShellPermissionIdentity(); 2316 } 2317 } 2318 /** 2319 * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by 2320 * any package. 2321 * <p> 2322 * No apps should <em>ever</em> attempt to acquire this permission, since it would give those 2323 * apps extremely broad access to connectivity functionality. 2324 */ 2325 @Test testNetworkStackPermission()2326 public void testNetworkStackPermission() { 2327 final PackageManager pm = sContext.getPackageManager(); 2328 2329 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2330 android.Manifest.permission.NETWORK_STACK 2331 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2332 for (PackageInfo pi : holding) { 2333 fail("The NETWORK_STACK permission must not be held by " + pi.packageName 2334 + " and must be revoked for security reasons"); 2335 } 2336 } 2337 2338 /** 2339 * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is 2340 * never held by any package. 2341 * <p> 2342 * Only Settings, SysUi, NetworkStack and shell apps should <em>ever</em> attempt to acquire 2343 * this permission, since it would give those apps extremely broad access to connectivity 2344 * functionality. The permission is intended to be granted to only those apps with direct user 2345 * access and no others. 2346 */ 2347 @Test testNetworkSettingsPermission()2348 public void testNetworkSettingsPermission() { 2349 final PackageManager pm = sContext.getPackageManager(); 2350 2351 final ArraySet<String> allowedPackages = new ArraySet(); 2352 final ArraySet<Integer> allowedUIDs = new ArraySet(); 2353 // explicitly add allowed UIDs 2354 allowedUIDs.add(Process.SYSTEM_UID); 2355 allowedUIDs.add(Process.SHELL_UID); 2356 allowedUIDs.add(Process.PHONE_UID); 2357 allowedUIDs.add(Process.NETWORK_STACK_UID); 2358 if (!SdkLevel.isAtLeastV()) { 2359 allowedUIDs.add(Process.NFC_UID); 2360 } 2361 2362 // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using 2363 // this fact to determined allowed package name for sysui. This is a signature permission, 2364 // so allow any package with this permission. 2365 final List<PackageInfo> sysuiPackages = pm.getPackagesHoldingPermissions(new String[] { 2366 android.Manifest.permission.BIND_QUICK_SETTINGS_TILE 2367 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2368 for (PackageInfo info : sysuiPackages) { 2369 allowedPackages.add(info.packageName); 2370 } 2371 2372 // the captive portal flow also currently holds the NETWORK_SETTINGS permission 2373 final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); 2374 final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); 2375 if (ri != null) { 2376 allowedPackages.add(ri.activityInfo.packageName); 2377 } 2378 2379 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2380 android.Manifest.permission.NETWORK_SETTINGS 2381 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2382 StringBuilder stringBuilder = new StringBuilder(); 2383 for (PackageInfo pi : holding) { 2384 String packageName = pi.packageName; 2385 2386 // this is an explicitly allowed package 2387 if (allowedPackages.contains(packageName)) continue; 2388 2389 // now check if the packages are from allowed UIDs 2390 int uid = -1; 2391 try { 2392 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); 2393 } catch (PackageManager.NameNotFoundException e) { 2394 continue; 2395 } 2396 if (!allowedUIDs.contains(uid)) { 2397 stringBuilder.append("The NETWORK_SETTINGS permission must not be held by " 2398 + packageName + ":" + uid + " and must be revoked for security reasons\n"); 2399 } 2400 } 2401 if (stringBuilder.length() > 0) { 2402 fail(stringBuilder.toString()); 2403 } 2404 } 2405 2406 /** 2407 * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is 2408 * only held by the device setup wizard application. 2409 * <p> 2410 * Only the SetupWizard app should <em>ever</em> attempt to acquire this 2411 * permission, since it would give those apps extremely broad access to connectivity 2412 * functionality. The permission is intended to be granted to only the device setup wizard. 2413 */ 2414 @Test testNetworkSetupWizardPermission()2415 public void testNetworkSetupWizardPermission() { 2416 final ArraySet<String> allowedPackages = new ArraySet(); 2417 2418 final PackageManager pm = sContext.getPackageManager(); 2419 2420 final Intent intent = new Intent(Intent.ACTION_MAIN); 2421 intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); 2422 final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); 2423 String validPkg = ""; 2424 if (ri != null) { 2425 allowedPackages.add(ri.activityInfo.packageName); 2426 validPkg = ri.activityInfo.packageName; 2427 } 2428 2429 final Intent preIntent = new Intent("com.android.setupwizard.OEM_PRE_SETUP"); 2430 preIntent.addCategory(Intent.CATEGORY_DEFAULT); 2431 final ResolveInfo preRi = pm 2432 .resolveActivity(preIntent, PackageManager.MATCH_DISABLED_COMPONENTS); 2433 String prePackageName = ""; 2434 if (null != preRi) { 2435 prePackageName = preRi.activityInfo.packageName; 2436 } 2437 2438 final Intent postIntent = new Intent("com.android.setupwizard.OEM_POST_SETUP"); 2439 postIntent.addCategory(Intent.CATEGORY_DEFAULT); 2440 final ResolveInfo postRi = pm 2441 .resolveActivity(postIntent, PackageManager.MATCH_DISABLED_COMPONENTS); 2442 String postPackageName = ""; 2443 if (null != postRi) { 2444 postPackageName = postRi.activityInfo.packageName; 2445 } 2446 if (!TextUtils.isEmpty(prePackageName) && !TextUtils.isEmpty(postPackageName) 2447 && prePackageName.equals(postPackageName)) { 2448 allowedPackages.add(prePackageName); 2449 } 2450 2451 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[]{ 2452 android.Manifest.permission.NETWORK_SETUP_WIZARD 2453 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2454 for (PackageInfo pi : holding) { 2455 if (!allowedPackages.contains(pi.packageName)) { 2456 fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName 2457 + " and must be revoked for security reasons" 2458 + " | validPkg=" + validPkg); 2459 } 2460 } 2461 } 2462 2463 /** 2464 * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission 2465 * is only held by the device managed provisioning application. 2466 * <p> 2467 * Only the ManagedProvisioning app should <em>ever</em> attempt to acquire this 2468 * permission, since it would give those apps extremely broad access to connectivity 2469 * functionality. The permission is intended to be granted to only the device managed 2470 * provisioning. 2471 */ 2472 @Test testNetworkManagedProvisioningPermission()2473 public void testNetworkManagedProvisioningPermission() { 2474 final PackageManager pm = sContext.getPackageManager(); 2475 2476 // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the 2477 // managed provisioning app. 2478 // Ensure that the package exists. 2479 final Intent intent = new Intent(Intent.ACTION_MAIN); 2480 intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); 2481 final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); 2482 String validPkg = ""; 2483 if (ri != null) { 2484 validPkg = ri.activityInfo.packageName; 2485 } 2486 String dpmHolderName = null; 2487 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2488 DevicePolicyManager dpm = sContext.getSystemService(DevicePolicyManager.class); 2489 if (dpm != null) { 2490 dpmHolderName = dpm.getDevicePolicyManagementRoleHolderPackage(); 2491 } 2492 } 2493 2494 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2495 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING 2496 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2497 for (PackageInfo pi : holding) { 2498 if (!Objects.equals(pi.packageName, validPkg) 2499 && !Objects.equals(pi.packageName, dpmHolderName)) { 2500 fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " 2501 + pi.packageName + " and must be revoked for security reasons [" 2502 + validPkg + ", " + dpmHolderName + "]"); 2503 } 2504 } 2505 } 2506 2507 /** 2508 * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission 2509 * is held by at most one application. 2510 */ 2511 @Test testWifiSetDeviceMobilityStatePermission()2512 public void testWifiSetDeviceMobilityStatePermission() { 2513 final PackageManager pm = sContext.getPackageManager(); 2514 2515 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2516 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE 2517 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2518 2519 List<String> uniquePackageNames = holding 2520 .stream() 2521 .map(pi -> pi.packageName) 2522 .distinct() 2523 .collect(Collectors.toList()); 2524 2525 if (uniquePackageNames.size() > 1) { 2526 fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " 2527 + "application, but is held by " + uniquePackageNames.size() + " applications: " 2528 + String.join(", ", uniquePackageNames)); 2529 } 2530 } 2531 2532 /** 2533 * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission 2534 * is held by at most one application. 2535 */ 2536 @Test testNetworkCarrierProvisioningPermission()2537 public void testNetworkCarrierProvisioningPermission() { 2538 final PackageManager pm = sContext.getPackageManager(); 2539 2540 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2541 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING 2542 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2543 2544 List<String> uniquePackageNames = holding 2545 .stream() 2546 .map(pi -> pi.packageName) 2547 .distinct() 2548 .collect(Collectors.toList()); 2549 2550 if (uniquePackageNames.size() > 2) { 2551 fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than two " 2552 + "applications, but is held by " + uniquePackageNames.size() + " applications: " 2553 + String.join(", ", uniquePackageNames)); 2554 } 2555 } 2556 2557 /** 2558 * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} 2559 * permission is held by at most two applications. 2560 */ 2561 @Test testUpdateWifiUsabilityStatsScorePermission()2562 public void testUpdateWifiUsabilityStatsScorePermission() { 2563 final PackageManager pm = sContext.getPackageManager(); 2564 2565 final List<PackageInfo> holding = pm.getPackagesHoldingPermissions(new String[] { 2566 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE 2567 }, PackageManager.MATCH_UNINSTALLED_PACKAGES); 2568 2569 Set<String> uniqueNonSystemPackageNames = new HashSet<>(); 2570 for (PackageInfo pi : holding) { 2571 String packageName = pi.packageName; 2572 // Shell is allowed to hold this permission for testing. 2573 int uid = -1; 2574 try { 2575 uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); 2576 } catch (PackageManager.NameNotFoundException e) { 2577 continue; 2578 } 2579 if (uid == Process.SHELL_UID) continue; 2580 2581 uniqueNonSystemPackageNames.add(packageName); 2582 } 2583 2584 if (uniqueNonSystemPackageNames.size() > 2) { 2585 fail("The WIFI_UPDATE_USABILITY_STATS_SCORE permission must not be held by more than " 2586 + "two applications, but is held by " + uniqueNonSystemPackageNames.size() 2587 + " applications: " + String.join(", ", uniqueNonSystemPackageNames)); 2588 } 2589 } 2590 turnScreenOnNoDelay()2591 private static void turnScreenOnNoDelay() throws Exception { 2592 if (sWakeLock.isHeld()) sWakeLock.release(); 2593 sUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); 2594 sUiDevice.executeShellCommand("wm dismiss-keyguard"); 2595 } 2596 turnScreenOn()2597 private void turnScreenOn() throws Exception { 2598 turnScreenOnNoDelay(); 2599 // Since the screen on/off intent is ordered, they will not be sent right now. 2600 Thread.sleep(DURATION_SCREEN_TOGGLE); 2601 } 2602 turnScreenOffNoDelay()2603 private void turnScreenOffNoDelay() throws Exception { 2604 sUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); 2605 } 2606 turnScreenOff()2607 private void turnScreenOff() throws Exception { 2608 if (!sWakeLock.isHeld()) sWakeLock.acquire(); 2609 turnScreenOffNoDelay(); 2610 // Since the screen on/off intent is ordered, they will not be sent right now. 2611 Thread.sleep(DURATION_SCREEN_TOGGLE); 2612 } 2613 assertWifiScanningIsOn()2614 private void assertWifiScanningIsOn() { 2615 if (!sWifiManager.isScanAlwaysAvailable()) { 2616 fail("Wi-Fi scanning should be on."); 2617 } 2618 } 2619 runWithScanning(ThrowingRunnable r, boolean isEnabled)2620 private void runWithScanning(ThrowingRunnable r, boolean isEnabled) throws Exception { 2621 boolean scanModeChangedForTest = false; 2622 if (sWifiManager.isScanAlwaysAvailable() != isEnabled) { 2623 ShellIdentityUtils.invokeWithShellPermissions( 2624 () -> sWifiManager.setScanAlwaysAvailable(isEnabled)); 2625 scanModeChangedForTest = true; 2626 } 2627 try { 2628 r.run(); 2629 } finally { 2630 if (scanModeChangedForTest) { 2631 ShellIdentityUtils.invokeWithShellPermissions( 2632 () -> sWifiManager.setScanAlwaysAvailable(!isEnabled)); 2633 } 2634 } 2635 } 2636 2637 /** 2638 * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled 2639 * but location is on. 2640 * @throws Exception 2641 */ 2642 @Test testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled()2643 public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { 2644 if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) { 2645 // TV and auto do not support the setting options of WIFI scanning and Bluetooth 2646 // scanning 2647 return; 2648 } 2649 2650 if (!hasLocationFeature()) { 2651 // skip the test if location is not supported 2652 return; 2653 } 2654 if (!isLocationEnabled()) { 2655 fail("Please enable location for this test - since Marshmallow WiFi scan results are" 2656 + " empty when location is disabled!"); 2657 } 2658 runWithScanning(() -> { 2659 setWifiEnabled(false); 2660 turnScreenOn(); 2661 assertWifiScanningIsOn(); 2662 // Toggle screen and verify Wi-Fi scanning is still on. 2663 turnScreenOff(); 2664 assertWifiScanningIsOn(); 2665 turnScreenOn(); 2666 assertWifiScanningIsOn(); 2667 }, true /* run with enabled*/); 2668 } 2669 2670 /** 2671 * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. 2672 * @throws Exception 2673 */ 2674 @Test testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled()2675 public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { 2676 if (FeatureUtil.isTV() || FeatureUtil.isAutomotive()) { 2677 // TV and auto do not support the setting options of WIFI scanning and Bluetooth 2678 // scanning 2679 return; 2680 } 2681 2682 if (!hasLocationFeature()) { 2683 // skip the test if location is not supported 2684 return; 2685 } 2686 if (!isLocationEnabled()) { 2687 fail("Please enable location for this test - since Marshmallow WiFi scan results are" 2688 + " empty when location is disabled!"); 2689 } 2690 runWithScanning(() -> { 2691 setWifiEnabled(true); 2692 turnScreenOn(); 2693 assertWifiScanningIsOn(); 2694 // Toggle screen and verify Wi-Fi scanning is still on. 2695 turnScreenOff(); 2696 assertWifiScanningIsOn(); 2697 turnScreenOn(); 2698 assertWifiScanningIsOn(); 2699 }, true /* run with enabled*/); 2700 } 2701 2702 /** 2703 * Verify that the platform supports a reasonable number of suggestions per app. 2704 * @throws Exception 2705 */ 2706 @Test testMaxNumberOfNetworkSuggestionsPerApp()2707 public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { 2708 assertTrue(sWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() 2709 > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); 2710 } 2711 verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2712 private void verifyRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback) 2713 throws Exception { 2714 // Register callback to get SoftApCapability 2715 sWifiManager.registerSoftApCallback(executor, callback); 2716 PollingCheck.check( 2717 "SoftAp register failed!", 5_000, 2718 () -> { 2719 executor.runAll(); 2720 // Verify callback is run on the supplied executor and called 2721 return callback.getOnStateChangedCalled() 2722 && callback.getOnSoftapInfoChangedCalledCount() > 0 2723 && callback.getOnSoftApCapabilityChangedCalled() 2724 && callback.getOnConnectedClientCalled(); 2725 }); 2726 } 2727 verifyLohsRegisterSoftApCallback(TestExecutor executor, TestSoftApCallback callback)2728 private void verifyLohsRegisterSoftApCallback(TestExecutor executor, 2729 TestSoftApCallback callback) throws Exception { 2730 // Register callback to get SoftApCapability 2731 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2732 sWifiManager.registerLocalOnlyHotspotSoftApCallback(executor, callback); 2733 } else { 2734 sWifiManager.registerSoftApCallback(executor, callback); 2735 } 2736 PollingCheck.check( 2737 "SoftAp register failed!", 5_000, 2738 () -> { 2739 executor.runAll(); 2740 // Verify callback is run on the supplied executor and called 2741 return callback.getOnStateChangedCalled() && 2742 callback.getOnSoftapInfoChangedCalledCount() > 0 && 2743 callback.getOnSoftApCapabilityChangedCalled() && 2744 callback.getOnConnectedClientCalled(); 2745 }); 2746 } 2747 verifySetGetSoftApConfig(SoftApConfiguration targetConfig)2748 private void verifySetGetSoftApConfig(SoftApConfiguration targetConfig) { 2749 assertTrue(sWifiManager.validateSoftApConfiguration(targetConfig)); 2750 sWifiManager.setSoftApConfiguration(targetConfig); 2751 // Bssid set dodesn't support for tethered hotspot 2752 SoftApConfiguration currentConfig = sWifiManager.getSoftApConfiguration(); 2753 compareSoftApConfiguration(targetConfig, currentConfig); 2754 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 2755 assertTrue(currentConfig.isUserConfiguration()); 2756 } 2757 assertNotNull(currentConfig.getPersistentRandomizedMacAddress()); 2758 2759 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2760 // Verify set/get with the deprecated set/getSsid() 2761 SoftApConfiguration oldSsidConfig = new SoftApConfiguration.Builder(targetConfig) 2762 .setWifiSsid(null) 2763 .setSsid(targetConfig.getSsid()).build(); 2764 sWifiManager.setSoftApConfiguration(oldSsidConfig); 2765 currentConfig = sWifiManager.getSoftApConfiguration(); 2766 compareSoftApConfiguration(oldSsidConfig, currentConfig); 2767 } 2768 } 2769 compareSoftApConfiguration(SoftApConfiguration currentConfig, SoftApConfiguration testSoftApConfig)2770 private void compareSoftApConfiguration(SoftApConfiguration currentConfig, 2771 SoftApConfiguration testSoftApConfig) { 2772 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2773 assertEquals(currentConfig.getWifiSsid(), testSoftApConfig.getWifiSsid()); 2774 } 2775 assertEquals(currentConfig.getSsid(), testSoftApConfig.getSsid()); 2776 assertEquals(currentConfig.getBssid(), testSoftApConfig.getBssid()); 2777 assertEquals(currentConfig.getSecurityType(), testSoftApConfig.getSecurityType()); 2778 assertEquals(currentConfig.getPassphrase(), testSoftApConfig.getPassphrase()); 2779 assertEquals(currentConfig.isHiddenSsid(), testSoftApConfig.isHiddenSsid()); 2780 assertEquals(currentConfig.getBand(), testSoftApConfig.getBand()); 2781 assertEquals(currentConfig.getChannel(), testSoftApConfig.getChannel()); 2782 assertEquals(currentConfig.getMaxNumberOfClients(), 2783 testSoftApConfig.getMaxNumberOfClients()); 2784 assertEquals(currentConfig.isAutoShutdownEnabled(), 2785 testSoftApConfig.isAutoShutdownEnabled()); 2786 assertEquals(currentConfig.getShutdownTimeoutMillis(), 2787 testSoftApConfig.getShutdownTimeoutMillis()); 2788 assertEquals(currentConfig.isClientControlByUserEnabled(), 2789 testSoftApConfig.isClientControlByUserEnabled()); 2790 assertEquals(currentConfig.getAllowedClientList(), 2791 testSoftApConfig.getAllowedClientList()); 2792 assertEquals(currentConfig.getBlockedClientList(), 2793 testSoftApConfig.getBlockedClientList()); 2794 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 2795 assertEquals(currentConfig.getMacRandomizationSetting(), 2796 testSoftApConfig.getMacRandomizationSetting()); 2797 assertEquals(currentConfig.getChannels().toString(), 2798 testSoftApConfig.getChannels().toString()); 2799 assertEquals(currentConfig.isBridgedModeOpportunisticShutdownEnabled(), 2800 testSoftApConfig.isBridgedModeOpportunisticShutdownEnabled()); 2801 assertEquals(currentConfig.isIeee80211axEnabled(), 2802 testSoftApConfig.isIeee80211axEnabled()); 2803 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 2804 assertEquals(currentConfig.getBridgedModeOpportunisticShutdownTimeoutMillis(), 2805 testSoftApConfig.getBridgedModeOpportunisticShutdownTimeoutMillis()); 2806 assertEquals(currentConfig.isIeee80211beEnabled(), 2807 testSoftApConfig.isIeee80211beEnabled()); 2808 assertEquals(currentConfig.getVendorElements(), 2809 testSoftApConfig.getVendorElements()); 2810 assertArrayEquals( 2811 currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ), 2812 testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ)); 2813 assertArrayEquals( 2814 currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ), 2815 testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ)); 2816 assertArrayEquals( 2817 currentConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ), 2818 testSoftApConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ)); 2819 assertEquals(currentConfig.getMaxChannelBandwidth(), 2820 testSoftApConfig.getMaxChannelBandwidth()); 2821 } 2822 if (Flags.androidVWifiApi() 2823 && SdkLevel.isAtLeastV()) { 2824 assertTrue(Objects.equals( 2825 currentConfig.getVendorData(), testSoftApConfig.getVendorData())); 2826 } 2827 } 2828 } 2829 turnOffWifiAndTetheredHotspotIfEnabled()2830 private void turnOffWifiAndTetheredHotspotIfEnabled() throws Exception { 2831 if (sWifiManager.isWifiEnabled()) { 2832 Log.d(TAG, "Turn off WiFi"); 2833 sWifiManager.setWifiEnabled(false); 2834 PollingCheck.check("Wifi turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 2835 () -> !sWifiManager.isWifiEnabled()); 2836 } 2837 if (sWifiManager.isWifiApEnabled()) { 2838 sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); 2839 Log.d(TAG, "Turn off tethered Hotspot"); 2840 PollingCheck.check("SoftAp turn off failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 2841 () -> !sWifiManager.isWifiApEnabled()); 2842 } 2843 } 2844 verifyBridgedModeSoftApCallback(TestExecutor executor, TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)2845 private void verifyBridgedModeSoftApCallback(TestExecutor executor, 2846 TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled) 2847 throws Exception { 2848 // Verify state and info callback value as expected 2849 PollingCheck.check( 2850 "SoftAp state and info on bridged AP mode are mismatch!!!" 2851 + " shouldFallbackSingleApMode = " + shouldFallbackSingleApMode 2852 + ", isEnabled = " + isEnabled, 10_000, 2853 () -> { 2854 executor.runAll(); 2855 int expectedState = isEnabled ? WifiManager.WIFI_AP_STATE_ENABLED 2856 : WifiManager.WIFI_AP_STATE_DISABLED; 2857 int expectedInfoSize = isEnabled 2858 ? (shouldFallbackSingleApMode ? 1 : 2) : 0; 2859 return expectedState == callback.getCurrentState() 2860 && callback.getCurrentSoftApInfoList().size() == expectedInfoSize; 2861 }); 2862 } 2863 shouldFallbackToSingleAp(int[] bands, SoftApCapability capability)2864 private boolean shouldFallbackToSingleAp(int[] bands, SoftApCapability capability) { 2865 for (int band : bands) { 2866 if (capability.getSupportedChannelList(band).length == 0) { 2867 return true; 2868 } 2869 } 2870 return false; 2871 } 2872 getAvailableBandAndChannelForTesting(SoftApCapability capability)2873 private SparseIntArray getAvailableBandAndChannelForTesting(SoftApCapability capability) { 2874 final int[] bands = {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ, 2875 SoftApConfiguration.BAND_6GHZ, SoftApConfiguration.BAND_60GHZ}; 2876 SparseIntArray testBandsAndChannels = new SparseIntArray(); 2877 if (!ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 2878 testBandsAndChannels.put(SoftApConfiguration.BAND_2GHZ, 1); 2879 return testBandsAndChannels; 2880 } 2881 for (int band : bands) { 2882 int[] supportedList = capability.getSupportedChannelList(band); 2883 if (supportedList.length != 0) { 2884 testBandsAndChannels.put(band, supportedList[0]); 2885 } 2886 } 2887 return testBandsAndChannels; 2888 } 2889 2890 @Test testLastConfiguredPassphraseIsKeepInSoftApConfigurationWhenChangingToNone()2891 public void testLastConfiguredPassphraseIsKeepInSoftApConfigurationWhenChangingToNone() 2892 throws Exception { 2893 final SoftApConfiguration currentConfig = ShellIdentityUtils.invokeWithShellPermissions( 2894 sWifiManager::getSoftApConfiguration); 2895 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 2896 try { 2897 uiAutomation.adoptShellPermissionIdentity(); 2898 Mutable<String> lastPassphrase = new Mutable<>(); 2899 final String testPassphrase = "testPassphrase"; 2900 sWifiManager.setSoftApConfiguration( 2901 new SoftApConfiguration.Builder(currentConfig) 2902 .setPassphrase(testPassphrase, 2903 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build()); 2904 sWifiManager.queryLastConfiguredTetheredApPassphraseSinceBoot(mExecutor, 2905 new Consumer<String>() { 2906 @Override 2907 public void accept(String value) { 2908 synchronized (mLock) { 2909 lastPassphrase.value = value; 2910 mLock.notify(); 2911 } 2912 } 2913 }); 2914 synchronized (mLock) { 2915 mLock.wait(TEST_WAIT_DURATION_MS); 2916 } 2917 assertEquals(lastPassphrase.value, testPassphrase); 2918 2919 sWifiManager.setSoftApConfiguration( 2920 new SoftApConfiguration.Builder(currentConfig) 2921 .setPassphrase(null, 2922 SoftApConfiguration.SECURITY_TYPE_OPEN).build()); 2923 sWifiManager.queryLastConfiguredTetheredApPassphraseSinceBoot(mExecutor, 2924 new Consumer<String>() { 2925 @Override 2926 public void accept(String value) { 2927 synchronized (mLock) { 2928 lastPassphrase.value = value; 2929 mLock.notify(); 2930 } 2931 } 2932 }); 2933 synchronized (mLock) { 2934 mLock.wait(TEST_WAIT_DURATION_MS); 2935 } 2936 assertEquals(lastPassphrase.value, testPassphrase); 2937 } finally { 2938 // Restore SoftApConfiguration 2939 sWifiManager.setSoftApConfiguration(currentConfig); 2940 uiAutomation.dropShellPermissionIdentity(); 2941 } 2942 } 2943 2944 /** 2945 * Skip the test if telephony is not supported and default country code 2946 * is not stored in system property. 2947 */ shouldSkipCountryCodeDependentTest()2948 private boolean shouldSkipCountryCodeDependentTest() { 2949 String countryCode = SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE); 2950 return TextUtils.isEmpty(countryCode) && !WifiFeature.isTelephonySupported(sContext); 2951 } 2952 2953 /** 2954 * Test SoftApConfiguration#getPersistentRandomizedMacAddress(). There are two test cases in 2955 * this test. 2956 * 1. configure two different SoftApConfigurations (different SSID) and verify that randomized 2957 * MAC address is different. 2958 * 2. configure A then B then A (SSIDs) and verify that the 1st and 3rd MAC addresses are the 2959 * same. 2960 */ 2961 @Test testSoftApConfigurationGetPersistentRandomizedMacAddress()2962 public void testSoftApConfigurationGetPersistentRandomizedMacAddress() throws Exception { 2963 SoftApConfiguration currentConfig = ShellIdentityUtils.invokeWithShellPermissions( 2964 sWifiManager::getSoftApConfiguration); 2965 final String ssid = currentConfig.getSsid().length() <= 28 2966 ? currentConfig.getSsid() + "test" 2967 : "AndroidTest"; 2968 ShellIdentityUtils.invokeWithShellPermissions( 2969 () -> sWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder() 2970 .setSsid(ssid).build())); 2971 SoftApConfiguration changedSsidConfig = ShellIdentityUtils.invokeWithShellPermissions( 2972 sWifiManager::getSoftApConfiguration); 2973 assertNotEquals(currentConfig.getPersistentRandomizedMacAddress(), 2974 changedSsidConfig.getPersistentRandomizedMacAddress()); 2975 2976 // set currentConfig 2977 ShellIdentityUtils.invokeWithShellPermissions( 2978 () -> sWifiManager.setSoftApConfiguration(currentConfig)); 2979 2980 SoftApConfiguration changedSsidBackConfig = ShellIdentityUtils.invokeWithShellPermissions( 2981 sWifiManager::getSoftApConfiguration); 2982 2983 assertEquals(currentConfig.getPersistentRandomizedMacAddress(), 2984 changedSsidBackConfig.getPersistentRandomizedMacAddress()); 2985 } 2986 2987 /** 2988 * Test bridged AP enable succeeful when device supports it. 2989 * Also verify the callback info update correctly. 2990 * @throws Exception 2991 */ 2992 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 2993 @Test testTetheredBridgedAp()2994 public void testTetheredBridgedAp() throws Exception { 2995 // check that softap bridged mode is supported by the device 2996 if (!sWifiManager.isBridgedApConcurrencySupported()) { 2997 return; 2998 } 2999 runWithScanning(() -> { 3000 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation() 3001 .getUiAutomation(); 3002 TestExecutor executor = new TestExecutor(); 3003 TestSoftApCallback callback = new TestSoftApCallback(mLock); 3004 try { 3005 uiAutomation.adoptShellPermissionIdentity(); 3006 // Off/On Wifi to make sure that we get the supported channel 3007 turnOffWifiAndTetheredHotspotIfEnabled(); 3008 sWifiManager.setWifiEnabled(true); 3009 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 3010 () -> sWifiManager.isWifiEnabled()); 3011 turnOffWifiAndTetheredHotspotIfEnabled(); 3012 verifyRegisterSoftApCallback(executor, callback); 3013 if (!callback.getCurrentSoftApCapability() 3014 .areFeaturesSupported(SOFTAP_FEATURE_ACS_OFFLOAD)) { 3015 return; 3016 } 3017 int[] testBands = {SoftApConfiguration.BAND_2GHZ, 3018 SoftApConfiguration.BAND_5GHZ}; 3019 int[] expectedBands = {SoftApConfiguration.BAND_2GHZ, 3020 SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ}; 3021 // Test bridged SoftApConfiguration set and get (setBands) 3022 SoftApConfiguration testSoftApConfig = 3023 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 3024 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) 3025 .setBands(expectedBands) 3026 .build(); 3027 3028 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(testBands, 3029 callback.getCurrentSoftApCapability()); 3030 verifySetGetSoftApConfig(testSoftApConfig); 3031 3032 // start tethering which used to verify startTetheredHotspot 3033 sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, 3034 new TetheringManager.StartTetheringCallback() { 3035 @Override 3036 public void onTetheringFailed(final int result) { 3037 } 3038 }); 3039 verifyBridgedModeSoftApCallback(executor, callback, 3040 shouldFallbackToSingleAp, true /* enabled */); 3041 // stop tethering which used to verify stopSoftAp 3042 sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); 3043 verifyBridgedModeSoftApCallback(executor, callback, 3044 shouldFallbackToSingleAp, false /* disabled */); 3045 } finally { 3046 sWifiManager.unregisterSoftApCallback(callback); 3047 uiAutomation.dropShellPermissionIdentity(); 3048 } 3049 }, false /* run with disabled */); 3050 } 3051 3052 /** 3053 * Test bridged AP with forced channel config enable succeeful when device supports it. 3054 * Also verify the callback info update correctly. 3055 * @throws Exception 3056 */ 3057 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 3058 @Test testTetheredBridgedApWifiForcedChannel()3059 public void testTetheredBridgedApWifiForcedChannel() throws Exception { 3060 // check that softap bridged mode is supported by the device 3061 if (!sWifiManager.isBridgedApConcurrencySupported()) { 3062 return; 3063 } 3064 runWithScanning(() -> { 3065 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation() 3066 .getUiAutomation(); 3067 TestExecutor executor = new TestExecutor(); 3068 TestSoftApCallback callback = new TestSoftApCallback(mLock); 3069 try { 3070 uiAutomation.adoptShellPermissionIdentity(); 3071 // Off/On Wifi to make sure that we get the supported channel 3072 turnOffWifiAndTetheredHotspotIfEnabled(); 3073 sWifiManager.setWifiEnabled(true); 3074 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 3075 () -> sWifiManager.isWifiEnabled()); 3076 turnOffWifiAndTetheredHotspotIfEnabled(); 3077 verifyRegisterSoftApCallback(executor, callback); 3078 3079 boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp( 3080 new int[] {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ}, 3081 callback.getCurrentSoftApCapability()); 3082 3083 // Test when there are supported channels in both of the bands. 3084 if (!shouldFallbackToSingleAp) { 3085 // Test bridged SoftApConfiguration set and get (setChannels) 3086 SparseIntArray dual_channels = new SparseIntArray(2); 3087 dual_channels.put(SoftApConfiguration.BAND_2GHZ, 3088 callback.getCurrentSoftApCapability() 3089 .getSupportedChannelList(SoftApConfiguration.BAND_2GHZ)[0]); 3090 dual_channels.put(SoftApConfiguration.BAND_5GHZ, 3091 callback.getCurrentSoftApCapability() 3092 .getSupportedChannelList(SoftApConfiguration.BAND_5GHZ)[0]); 3093 SoftApConfiguration testSoftApConfig = 3094 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 3095 .setPassphrase(TEST_PASSPHRASE, 3096 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) 3097 .setChannels(dual_channels) 3098 .build(); 3099 3100 verifySetGetSoftApConfig(testSoftApConfig); 3101 3102 // start tethering which used to verify startTetheredHotspot 3103 sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, 3104 new TetheringManager.StartTetheringCallback() { 3105 @Override 3106 public void onTetheringFailed(final int result) { 3107 } 3108 }); 3109 verifyBridgedModeSoftApCallback(executor, callback, 3110 shouldFallbackToSingleAp, true /* enabled */); 3111 // stop tethering which used to verify stopSoftAp 3112 sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); 3113 verifyBridgedModeSoftApCallback(executor, callback, 3114 shouldFallbackToSingleAp, false /* disabled */); 3115 } 3116 } finally { 3117 sWifiManager.unregisterSoftApCallback(callback); 3118 uiAutomation.dropShellPermissionIdentity(); 3119 } 3120 }, false /* run with disabled */); 3121 } 3122 3123 /** 3124 * Test startTetheringRequest() starts a soft AP and relays the TetheringRequest object back via 3125 * SoftApCallback. 3126 * @throws Exception 3127 */ 3128 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) 3129 @Test testStartTetheredHotspotWithTetheringRequest()3130 public void testStartTetheredHotspotWithTetheringRequest() throws Exception { 3131 // check that softap is supported by the device 3132 if (!sWifiManager.isPortableHotspotSupported()) { 3133 return; 3134 } 3135 runWithScanning(() -> { 3136 TestExecutor executor = new TestExecutor(); 3137 TestSoftApCallback callback = new TestSoftApCallback(mLock); 3138 try { 3139 TetheringManager.TetheringRequest request = 3140 new TetheringManager.TetheringRequest.Builder( 3141 TetheringManager.TETHERING_WIFI).build(); 3142 sWifiManager.startTetheredHotspot(request, executor, callback); 3143 fail("startTetheredHotspot succeeded even without NETWORK_STACK permission!"); 3144 } catch (SecurityException e) { 3145 // Expected to fail without NETWORK_STACK 3146 } 3147 }, false /* run with disabled */); 3148 } 3149 3150 /** 3151 * Verify that the configuration from getSoftApConfiguration is same as the configuration which 3152 * set by setSoftApConfiguration. And depends softap capability callback to test different 3153 * configuration. 3154 * @throws Exception 3155 */ 3156 @RequiresDevice 3157 @Test testSetGetSoftApConfigurationAndSoftApCapabilityCallback()3158 public void testSetGetSoftApConfigurationAndSoftApCapabilityCallback() throws Exception { 3159 // check that softap mode is supported by the device 3160 if (!sWifiManager.isPortableHotspotSupported()) { 3161 return; 3162 } 3163 if (shouldSkipCountryCodeDependentTest()) { 3164 // skip the test when there is no Country Code available 3165 return; 3166 } 3167 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3168 TestExecutor executor = new TestExecutor(); 3169 TestSoftApCallback callback = new TestSoftApCallback(mLock); 3170 try { 3171 uiAutomation.adoptShellPermissionIdentity(); 3172 turnOffWifiAndTetheredHotspotIfEnabled(); 3173 verifyRegisterSoftApCallback(executor, callback); 3174 3175 SoftApConfiguration.Builder softApConfigBuilder = 3176 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 3177 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) 3178 .setAutoShutdownEnabled(true) 3179 .setShutdownTimeoutMillis(100000) 3180 .setBand(getAvailableBandAndChannelForTesting( 3181 callback.getCurrentSoftApCapability()).keyAt(0)) 3182 .setHiddenSsid(false); 3183 3184 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 3185 softApConfigBuilder.setBridgedModeOpportunisticShutdownTimeoutMillis(30_000); 3186 softApConfigBuilder.setVendorElements(TEST_VENDOR_ELEMENTS); 3187 softApConfigBuilder.setAllowedAcsChannels( 3188 SoftApConfiguration.BAND_2GHZ, new int[] {1, 6, 11}); 3189 softApConfigBuilder.setAllowedAcsChannels( 3190 SoftApConfiguration.BAND_5GHZ, new int[] {149}); 3191 softApConfigBuilder.setAllowedAcsChannels( 3192 SoftApConfiguration.BAND_6GHZ, new int[] {}); 3193 softApConfigBuilder.setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_80MHZ); 3194 } 3195 3196 if (Flags.androidVWifiApi() 3197 && SdkLevel.isAtLeastV()) { 3198 OuiKeyedData vendorDataElement = 3199 new OuiKeyedData.Builder(0x00112233, new PersistableBundle()).build(); 3200 softApConfigBuilder.setVendorData(Arrays.asList(vendorDataElement)); 3201 } 3202 3203 // Test SoftApConfiguration set and get 3204 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3205 3206 boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability() 3207 .areFeaturesSupported( 3208 SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION) 3209 && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S); 3210 3211 //Test MAC_ADDRESS_CUSTOMIZATION supported config 3212 if (isSupportCustomizedMac) { 3213 softApConfigBuilder.setBssid(TEST_MAC) 3214 .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE); 3215 3216 // Test SoftApConfiguration set and get 3217 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3218 } 3219 3220 assertThat(callback.getCurrentSoftApCapability().getMaxSupportedClients()) 3221 .isGreaterThan(0); 3222 // Test CLIENT_FORCE_DISCONNECT supported config. 3223 if (callback.getCurrentSoftApCapability() 3224 .areFeaturesSupported( 3225 SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT)) { 3226 softApConfigBuilder.setMaxNumberOfClients(10); 3227 softApConfigBuilder.setClientControlByUserEnabled(true); 3228 softApConfigBuilder.setBlockedClientList(new ArrayList<>()); 3229 softApConfigBuilder.setAllowedClientList(new ArrayList<>()); 3230 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3231 } 3232 3233 // Test SAE config 3234 if (callback.getCurrentSoftApCapability() 3235 .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE)) { 3236 softApConfigBuilder 3237 .setPassphrase(TEST_PASSPHRASE, 3238 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); 3239 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3240 softApConfigBuilder 3241 .setPassphrase(TEST_PASSPHRASE, 3242 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); 3243 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3244 } 3245 3246 // Test 11 BE control config 3247 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU)) { 3248 if (callback.getCurrentSoftApCapability() 3249 .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE)) { 3250 softApConfigBuilder.setIeee80211beEnabled(true); 3251 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3252 } 3253 } 3254 3255 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 3256 // Test 11 AX control config. 3257 if (callback.getCurrentSoftApCapability() 3258 .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) { 3259 softApConfigBuilder.setIeee80211axEnabled(true); 3260 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3261 } 3262 softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(false); 3263 verifySetGetSoftApConfig(softApConfigBuilder.build()); 3264 } 3265 3266 } finally { 3267 sWifiManager.unregisterSoftApCallback(callback); 3268 uiAutomation.dropShellPermissionIdentity(); 3269 } 3270 } 3271 3272 /** 3273 * Verify that startTetheredHotspot with specific channel config. 3274 * @throws Exception 3275 */ 3276 @RequiresDevice 3277 @Test testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback()3278 public void testStartTetheredHotspotWithChannelConfigAndSoftApStateAndInfoCallback() 3279 throws Exception { 3280 // check that softap mode is supported by the device 3281 if (!sWifiManager.isPortableHotspotSupported()) { 3282 return; 3283 } 3284 if (shouldSkipCountryCodeDependentTest()) { 3285 // skip the test when there is no Country Code available 3286 return; 3287 } 3288 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3289 TestExecutor executor = new TestExecutor(); 3290 TestSoftApCallback callback = new TestSoftApCallback(mLock); 3291 try { 3292 uiAutomation.adoptShellPermissionIdentity(); 3293 // check that tethering is supported by the device 3294 if (!sTetheringManager.isTetheringSupported()) { 3295 return; 3296 } 3297 turnOffWifiAndTetheredHotspotIfEnabled(); 3298 verifyRegisterSoftApCallback(executor, callback); 3299 3300 SparseIntArray testBandsAndChannels = getAvailableBandAndChannelForTesting( 3301 callback.getCurrentSoftApCapability()); 3302 3303 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 3304 assertNotEquals(0, testBandsAndChannels.size()); 3305 } 3306 boolean isSupportCustomizedMac = callback.getCurrentSoftApCapability() 3307 .areFeaturesSupported( 3308 SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION) 3309 && PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S); 3310 3311 SoftApConfiguration.Builder testSoftApConfigBuilder = 3312 generateSoftApConfigBuilderWithSsid(TEST_SSID_UNQUOTED) 3313 .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) 3314 .setChannel(testBandsAndChannels.valueAt(0), testBandsAndChannels.keyAt(0)); 3315 3316 if (isSupportCustomizedMac) { 3317 testSoftApConfigBuilder.setBssid(TEST_MAC) 3318 .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE); 3319 } 3320 3321 SoftApConfiguration testSoftApConfig = testSoftApConfigBuilder.build(); 3322 3323 sWifiManager.setSoftApConfiguration(testSoftApConfig); 3324 3325 // start tethering which used to verify startTetheredHotspot 3326 sTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor, 3327 new TetheringManager.StartTetheringCallback() { 3328 @Override 3329 public void onTetheringFailed(final int result) { 3330 } 3331 }); 3332 3333 // Verify state and info callback value as expected 3334 PollingCheck.check( 3335 "SoftAp channel and state mismatch!!!", 10_000, 3336 () -> { 3337 executor.runAll(); 3338 int sapChannel = ScanResult.convertFrequencyMhzToChannelIfSupported( 3339 callback.getCurrentSoftApInfo().getFrequency()); 3340 boolean isInfoCallbackSupported = 3341 callback.getOnSoftapInfoChangedCalledCount() > 1; 3342 if (isInfoCallbackSupported) { 3343 return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState() 3344 && testBandsAndChannels.valueAt(0) == sapChannel; 3345 } 3346 return WifiManager.WIFI_AP_STATE_ENABLED == callback.getCurrentState(); 3347 }); 3348 // After Soft Ap enabled, check SoftAp info if it supported 3349 if (isSupportCustomizedMac && callback.getOnSoftapInfoChangedCalledCount() > 1) { 3350 assertEquals(callback.getCurrentSoftApInfo().getBssid(), TEST_MAC); 3351 } 3352 if (PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.S) 3353 && callback.getOnSoftapInfoChangedCalledCount() > 1) { 3354 assertNotEquals(callback.getCurrentSoftApInfo().getWifiStandard(), 3355 ScanResult.WIFI_STANDARD_UNKNOWN); 3356 } 3357 if (Flags.androidVWifiApi() 3358 && SdkLevel.isAtLeastV() 3359 && callback.getOnSoftapInfoChangedCalledCount() > 1) { 3360 assertNotNull(callback.getCurrentSoftApInfo().getVendorData()); 3361 } 3362 3363 if (callback.getOnSoftapInfoChangedCalledCount() > 1) { 3364 assertTrue(callback.getCurrentSoftApInfo().getAutoShutdownTimeoutMillis() > 0); 3365 } 3366 } finally { 3367 // stop tethering which used to verify stopSoftAp 3368 sTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI); 3369 3370 // Verify clean up 3371 PollingCheck.check( 3372 "Stop Softap failed", 3_000, 3373 () -> { 3374 executor.runAll(); 3375 return WifiManager.WIFI_AP_STATE_DISABLED == callback.getCurrentState() && 3376 0 == callback.getCurrentSoftApInfo().getBandwidth() && 3377 0 == callback.getCurrentSoftApInfo().getFrequency(); 3378 }); 3379 if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S)) { 3380 assertEquals(callback.getCurrentSoftApInfo().getBssid(), null); 3381 assertEquals(ScanResult.WIFI_STANDARD_UNKNOWN, 3382 callback.getCurrentSoftApInfo().getWifiStandard()); 3383 } 3384 sWifiManager.unregisterSoftApCallback(callback); 3385 uiAutomation.dropShellPermissionIdentity(); 3386 } 3387 } 3388 3389 private static class TestActionListener implements WifiManager.ActionListener { 3390 private final Object mLock; 3391 public boolean onSuccessCalled = false; 3392 public boolean onFailedCalled = false; 3393 public int failureReason = -1; 3394 TestActionListener(Object lock)3395 TestActionListener(Object lock) { 3396 mLock = lock; 3397 } 3398 3399 @Override onSuccess()3400 public void onSuccess() { 3401 synchronized (mLock) { 3402 onSuccessCalled = true; 3403 mLock.notify(); 3404 } 3405 } 3406 3407 @Override onFailure(int reason)3408 public void onFailure(int reason) { 3409 synchronized (mLock) { 3410 onFailedCalled = true; 3411 failureReason = reason; 3412 mLock.notify(); 3413 } 3414 } 3415 } 3416 3417 /** 3418 * Triggers connection to one of the saved networks using {@link WifiManager#connect( 3419 * int, WifiManager.ActionListener)} or {@link WifiManager#connect(WifiConfiguration, 3420 * WifiManager.ActionListener)} 3421 * 3422 * @param withNetworkId Use networkId for triggering connection, false for using 3423 * WifiConfiguration. 3424 * @throws Exception 3425 */ testConnect(boolean withNetworkId)3426 private void testConnect(boolean withNetworkId) throws Exception { 3427 TestActionListener actionListener = new TestActionListener(mLock); 3428 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3429 List<WifiConfiguration> savedNetworks = null; 3430 try { 3431 uiAutomation.adoptShellPermissionIdentity(); 3432 // These below API's only work with privileged permissions (obtained via shell identity 3433 // for test) 3434 savedNetworks = sWifiManager.getConfiguredNetworks(); 3435 3436 // Disable all the saved networks to trigger disconnect & disable autojoin. 3437 for (WifiConfiguration network : savedNetworks) { 3438 assertTrue(sWifiManager.disableNetwork(network.networkId)); 3439 } 3440 waitForDisconnection(); 3441 3442 // Now trigger connection to the last saved network. 3443 WifiConfiguration savedNetworkToConnect = 3444 savedNetworks.get(savedNetworks.size() - 1); 3445 synchronized (mLock) { 3446 try { 3447 if (withNetworkId) { 3448 sWifiManager.connect(savedNetworkToConnect.networkId, actionListener); 3449 } else { 3450 sWifiManager.connect(savedNetworkToConnect, actionListener); 3451 } 3452 // now wait for callback 3453 mLock.wait(TEST_WAIT_DURATION_MS); 3454 } catch (InterruptedException e) { 3455 } 3456 } 3457 // check if we got the success callback 3458 assertTrue(actionListener.onSuccessCalled); 3459 // Wait for connection to complete & ensure we are connected to the saved network. 3460 waitForConnection(); 3461 assertEquals(savedNetworkToConnect.networkId, 3462 sWifiManager.getConnectionInfo().getNetworkId()); 3463 } finally { 3464 // Re-enable all saved networks before exiting. 3465 if (savedNetworks != null) { 3466 for (WifiConfiguration network : savedNetworks) { 3467 sWifiManager.enableNetwork(network.networkId, true); 3468 } 3469 } 3470 uiAutomation.dropShellPermissionIdentity(); 3471 } 3472 } 3473 3474 /** 3475 * Tests {@link WifiManager#connect(int, WifiManager.ActionListener)} to an existing saved 3476 * network. 3477 */ 3478 @Test testConnectWithNetworkId()3479 public void testConnectWithNetworkId() throws Exception { 3480 testConnect(true); 3481 } 3482 3483 /** 3484 * Tests {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)} to an 3485 * existing saved network. 3486 */ 3487 @Test testConnectWithWifiConfiguration()3488 public void testConnectWithWifiConfiguration() throws Exception { 3489 testConnect(false); 3490 3491 } 3492 3493 private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { 3494 private final Object mLock; 3495 public boolean onAvailableCalled = false; 3496 public Network network; 3497 public NetworkCapabilities networkCapabilities; 3498 TestNetworkCallback(Object lock)3499 TestNetworkCallback(Object lock) { 3500 mLock = lock; 3501 } 3502 3503 @Override onAvailable(Network network)3504 public void onAvailable(Network network) { 3505 synchronized (mLock) { 3506 onAvailableCalled = true; 3507 this.network = network; 3508 } 3509 } 3510 3511 @Override onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities)3512 public void onCapabilitiesChanged(Network network, 3513 NetworkCapabilities networkCapabilities) { 3514 synchronized (mLock) { 3515 this.networkCapabilities = networkCapabilities; 3516 mLock.notify(); 3517 } 3518 } 3519 } 3520 waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered)3521 private void waitForNetworkCallbackAndCheckForMeteredness(boolean expectMetered) { 3522 Object lock = new Object(); 3523 TestNetworkCallback networkCallbackListener = new TestNetworkCallback(lock); 3524 synchronized (lock) { 3525 try { 3526 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder() 3527 .addTransportType(TRANSPORT_WIFI); 3528 if (expectMetered) { 3529 networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_METERED); 3530 } else { 3531 networkRequestBuilder.addCapability(NET_CAPABILITY_NOT_METERED); 3532 } 3533 // File a request for wifi network. 3534 sConnectivityManager.registerNetworkCallback( 3535 networkRequestBuilder.build(), networkCallbackListener); 3536 // now wait for callback 3537 lock.wait(TEST_WAIT_DURATION_MS); 3538 } catch (InterruptedException e) { 3539 } 3540 } 3541 assertTrue(networkCallbackListener.onAvailableCalled); 3542 } 3543 3544 /** 3545 * Tests {@link WifiManager#save(WifiConfiguration, WifiManager.ActionListener)} by marking 3546 * an existing saved network metered. 3547 */ 3548 @Test testSave()3549 public void testSave() throws Exception { 3550 Object lock = new Object(); 3551 TestActionListener actionListener = new TestActionListener(lock); 3552 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3553 List<WifiConfiguration> savedNetworks = null; 3554 WifiConfiguration currentConfig = null; 3555 try { 3556 uiAutomation.adoptShellPermissionIdentity(); 3557 // These below API's only work with privileged permissions (obtained via shell identity 3558 // for test) 3559 3560 WifiInfo wifiInfo = sWifiManager.getConnectionInfo(); 3561 savedNetworks = sWifiManager.getConfiguredNetworks(); 3562 3563 // find the current network's WifiConfiguration 3564 currentConfig = savedNetworks 3565 .stream() 3566 .filter(config -> config.networkId == wifiInfo.getNetworkId()) 3567 .findAny() 3568 .get(); 3569 3570 // Ensure that the current network is not metered. 3571 assertNotEquals("Ensure that the saved network is configured as unmetered", 3572 currentConfig.meteredOverride, 3573 WifiConfiguration.METERED_OVERRIDE_METERED); 3574 3575 // Disable all except the currently connected networks to avoid reconnecting to the 3576 // wrong network after later setting the current network as metered. 3577 for (WifiConfiguration network : savedNetworks) { 3578 if (network.networkId != currentConfig.networkId) { 3579 assertTrue(sWifiManager.disableNetwork(network.networkId)); 3580 } 3581 } 3582 3583 // Check the network capabilities to ensure that the network is marked not metered. 3584 waitForNetworkCallbackAndCheckForMeteredness(false); 3585 3586 // Now mark the network metered and save. 3587 synchronized (lock) { 3588 try { 3589 WifiConfiguration modSavedNetwork = new WifiConfiguration(currentConfig); 3590 modSavedNetwork.meteredOverride = WifiConfiguration.METERED_OVERRIDE_METERED; 3591 sWifiManager.save(modSavedNetwork, actionListener); 3592 // now wait for callback 3593 lock.wait(TEST_WAIT_DURATION_MS); 3594 } catch (InterruptedException e) { 3595 } 3596 } 3597 // check if we got the success callback 3598 assertTrue(actionListener.onSuccessCalled); 3599 // Ensure we disconnected on marking the network metered & connect back. 3600 waitForDisconnection(); 3601 waitForConnection(); 3602 // Check the network capabilities to ensure that the network is marked metered now. 3603 waitForNetworkCallbackAndCheckForMeteredness(true); 3604 3605 } finally { 3606 // Restore original network config (restore the meteredness back); 3607 if (currentConfig != null) { 3608 sWifiManager.updateNetwork(currentConfig); 3609 } 3610 // re-enable all networks 3611 if (savedNetworks != null) { 3612 for (WifiConfiguration network : savedNetworks) { 3613 sWifiManager.enableNetwork(network.networkId, true); 3614 } 3615 } 3616 uiAutomation.dropShellPermissionIdentity(); 3617 } 3618 } 3619 3620 /** 3621 * Tests {@link WifiManager#forget(int, WifiManager.ActionListener)} by adding/removing a new 3622 * network. 3623 */ 3624 @AsbSecurityTest(cveBugId = 159373687) 3625 @Test testForget()3626 public void testForget() throws Exception { 3627 TestActionListener actionListener = new TestActionListener(mLock); 3628 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3629 int newNetworkId = INVALID_NETWORK_ID; 3630 try { 3631 uiAutomation.adoptShellPermissionIdentity(); 3632 // These below API's only work with privileged permissions (obtained via shell identity 3633 // for test) 3634 List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks(); 3635 3636 WifiConfiguration newOpenNetwork = new WifiConfiguration(); 3637 newOpenNetwork.SSID = "\"" + TEST_SSID_UNQUOTED + "\""; 3638 newNetworkId = sWifiManager.addNetwork(newOpenNetwork); 3639 assertNotEquals(INVALID_NETWORK_ID, newNetworkId); 3640 3641 // Multi-type configurations might be converted to more than 1 configuration. 3642 assertThat(savedNetworks.size() < sWifiManager.getConfiguredNetworks().size()).isTrue(); 3643 3644 // Need an effectively-final holder because we need to modify inner Intent in callback. 3645 class IntentHolder { 3646 Intent intent; 3647 } 3648 IntentHolder intentHolder = new IntentHolder(); 3649 sContext.registerReceiver(new BroadcastReceiver() { 3650 @Override 3651 public void onReceive(Context context, Intent intent) { 3652 Log.i(TAG, "Received CONFIGURED_NETWORKS_CHANGED_ACTION broadcast: " + intent); 3653 intentHolder.intent = intent; 3654 } 3655 }, new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); 3656 3657 // Now remove the network 3658 synchronized (mLock) { 3659 try { 3660 sWifiManager.forget(newNetworkId, actionListener); 3661 // now wait for callback 3662 mLock.wait(TEST_WAIT_DURATION_MS); 3663 } catch (InterruptedException e) { 3664 } 3665 } 3666 // check if we got the success callback 3667 assertTrue(actionListener.onSuccessCalled); 3668 3669 PollingCheck.check( 3670 "Didn't receive CONFIGURED_NETWORKS_CHANGED_ACTION broadcast!", 3671 TEST_WAIT_DURATION_MS, 3672 () -> intentHolder.intent != null); 3673 Intent intent = intentHolder.intent; 3674 assertEquals(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION, intent.getAction()); 3675 assertTrue(intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false)); 3676 assertEquals(WifiManager.CHANGE_REASON_REMOVED, 3677 intent.getIntExtra(WifiManager.EXTRA_CHANGE_REASON, -1)); 3678 assertNull(intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION)); 3679 3680 // Ensure that the new network has been successfully removed. 3681 assertEquals(savedNetworks.size(), sWifiManager.getConfiguredNetworks().size()); 3682 } finally { 3683 // For whatever reason, if the forget fails, try removing using the public remove API. 3684 if (newNetworkId != INVALID_NETWORK_ID) sWifiManager.removeNetwork(newNetworkId); 3685 uiAutomation.dropShellPermissionIdentity(); 3686 } 3687 } 3688 3689 /** 3690 * Tests {@link WifiManager#getFactoryMacAddresses()} returns at least one valid MAC address. 3691 */ 3692 @RequiresDevice 3693 @Test testGetFactoryMacAddresses()3694 public void testGetFactoryMacAddresses() throws Exception { 3695 TestActionListener actionListener = new TestActionListener(mLock); 3696 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3697 int newNetworkId = INVALID_NETWORK_ID; 3698 try { 3699 uiAutomation.adoptShellPermissionIdentity(); 3700 // Obtain the factory MAC address 3701 String[] macAddresses = sWifiManager.getFactoryMacAddresses(); 3702 assertTrue("At list one MAC address should be returned.", macAddresses.length > 0); 3703 try { 3704 MacAddress mac = MacAddress.fromString(macAddresses[0]); 3705 assertNotEquals(WifiInfo.DEFAULT_MAC_ADDRESS, mac); 3706 assertFalse(MacAddressUtils.isMulticastAddress(mac)); 3707 } catch (IllegalArgumentException e) { 3708 fail("Factory MAC address is invalid"); 3709 } 3710 } finally { 3711 uiAutomation.dropShellPermissionIdentity(); 3712 } 3713 } 3714 3715 /** 3716 * Tests {@link WifiManager#isApMacRandomizationSupported()} does not crash. 3717 */ 3718 @Test testIsApMacRandomizationSupported()3719 public void testIsApMacRandomizationSupported() throws Exception { 3720 sWifiManager.isApMacRandomizationSupported(); 3721 } 3722 3723 /** 3724 * Tests {@link WifiManager#isConnectedMacRandomizationSupported()} does not crash. 3725 */ 3726 @Test testIsConnectedMacRandomizationSupported()3727 public void testIsConnectedMacRandomizationSupported() throws Exception { 3728 sWifiManager.isConnectedMacRandomizationSupported(); 3729 } 3730 3731 /** 3732 * Tests {@link WifiManager#isPreferredNetworkOffloadSupported()} does not crash. 3733 */ 3734 @Test testIsPreferredNetworkOffloadSupported()3735 public void testIsPreferredNetworkOffloadSupported() throws Exception { 3736 sWifiManager.isPreferredNetworkOffloadSupported(); 3737 } 3738 3739 /** Test that PNO scans reconnects us when the device is disconnected and the screen is off. */ 3740 @Test testPnoScan()3741 public void testPnoScan() throws Exception { 3742 if (!sWifiManager.isPreferredNetworkOffloadSupported()) { 3743 // skip the test if PNO scanning is not supported 3744 return; 3745 } 3746 3747 WifiInfo currentNetwork = ShellIdentityUtils.invokeWithShellPermissions( 3748 sWifiManager::getConnectionInfo); 3749 3750 // disable all networks that aren't already disabled 3751 List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions( 3752 sWifiManager::getConfiguredNetworks); 3753 Set<Integer> disabledNetworkIds = new HashSet<>(); 3754 for (WifiConfiguration config : savedNetworks) { 3755 if (config.getNetworkSelectionStatus().getNetworkSelectionDisableReason() 3756 == WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE) { 3757 ShellIdentityUtils.invokeWithShellPermissions( 3758 () -> sWifiManager.disableNetwork(config.networkId)); 3759 disabledNetworkIds.add(config.networkId); 3760 } 3761 } 3762 3763 try { 3764 // wait for disconnection from current network 3765 waitForDisconnection(); 3766 3767 // turn screen off 3768 turnScreenOffNoDelay(); 3769 3770 // re-enable the current network - this will trigger PNO 3771 ShellIdentityUtils.invokeWithShellPermissions( 3772 () -> sWifiManager.enableNetwork(currentNetwork.getNetworkId(), false)); 3773 disabledNetworkIds.remove(currentNetwork.getNetworkId()); 3774 3775 // PNO should reconnect us back to the network we disconnected from 3776 waitForConnection(WIFI_PNO_CONNECT_TIMEOUT_MILLIS); 3777 } finally { 3778 // re-enable disabled networks 3779 for (int disabledNetworkId : disabledNetworkIds) { 3780 ShellIdentityUtils.invokeWithShellPermissions( 3781 () -> sWifiManager.enableNetwork(disabledNetworkId, true)); 3782 } 3783 } 3784 } 3785 3786 /** 3787 * Tests {@link WifiManager#isStaApConcurrencySupported()}. 3788 */ 3789 @Test testIsStaApConcurrencySupported()3790 public void testIsStaApConcurrencySupported() throws Exception { 3791 // check that softap mode is supported by the device 3792 assumeTrue(sWifiManager.isPortableHotspotSupported()); 3793 // Re-enabled Wi-Fi as shell for HalDeviceManager legacy LOHS behavior when there's no 3794 // STA+AP concurrency. 3795 ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.setWifiEnabled(false)); 3796 PollingCheck.check("Wifi turn off failed!", 2_000, () -> !sWifiManager.isWifiEnabled()); 3797 SystemUtil.runShellCommand("cmd wifi set-wifi-enabled enabled"); 3798 PollingCheck.check("Wifi turn on failed!", WIFI_OFF_ON_TIMEOUT_MILLIS, 3799 () -> sWifiManager.isWifiEnabled()); 3800 3801 runWithScanning(() -> { 3802 boolean isStaApConcurrencySupported = sWifiManager.isStaApConcurrencySupported(); 3803 // start local only hotspot. 3804 TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); 3805 try { 3806 if (isStaApConcurrencySupported) { 3807 assertTrue(sWifiManager.isWifiEnabled()); 3808 } else { 3809 // no concurrency, wifi should be disabled. 3810 assertFalse(sWifiManager.isWifiEnabled()); 3811 } 3812 } finally { 3813 // clean up local only hotspot no matter if assertion passed or failed 3814 stopLocalOnlyHotspot(callback, true); 3815 } 3816 3817 assertTrue(sWifiManager.isWifiEnabled()); 3818 }, false); 3819 } 3820 3821 /** 3822 * state is a bitset, where bit 0 indicates whether there was data in, and bit 1 indicates 3823 * whether there was data out. Only count down on the latch once there was both data in and out. 3824 */ 3825 private static class TestTrafficStateCallback implements WifiManager.TrafficStateCallback { 3826 public final CountDownLatch latch = new CountDownLatch(1); 3827 private int mAccumulator = 0; 3828 3829 @Override onStateChanged(int state)3830 public void onStateChanged(int state) { 3831 mAccumulator |= state; 3832 if (mAccumulator == DATA_ACTIVITY_INOUT) { 3833 latch.countDown(); 3834 } 3835 } 3836 } 3837 sendTraffic()3838 private void sendTraffic() { 3839 boolean didAnyConnectionSucceed = false; 3840 for (int i = 0; i < 10; i++) { 3841 // Do some network operations 3842 HttpURLConnection connection = null; 3843 try { 3844 URL url = new URL("http://www.google.com/"); 3845 connection = (HttpURLConnection) url.openConnection(); 3846 connection.setInstanceFollowRedirects(false); 3847 connection.setConnectTimeout(TEST_WAIT_DURATION_MS); 3848 connection.setReadTimeout(TEST_WAIT_DURATION_MS); 3849 connection.setUseCaches(false); 3850 InputStream stream = connection.getInputStream(); 3851 byte[] bytes = new byte[100]; 3852 int receivedBytes = stream.read(bytes); 3853 if (receivedBytes > 0) { 3854 didAnyConnectionSucceed = true; 3855 } 3856 } catch (Exception e) { 3857 // ignore 3858 } finally { 3859 if (connection != null) connection.disconnect(); 3860 } 3861 } 3862 assertTrue("All connections failed!", didAnyConnectionSucceed); 3863 } 3864 3865 /** 3866 * Tests {@link WifiManager#registerTrafficStateCallback(Executor, 3867 * WifiManager.TrafficStateCallback)} by sending some traffic. 3868 */ 3869 @Test testTrafficStateCallback()3870 public void testTrafficStateCallback() throws Exception { 3871 TestTrafficStateCallback callback = new TestTrafficStateCallback(); 3872 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3873 try { 3874 uiAutomation.adoptShellPermissionIdentity(); 3875 3876 // Turn screen on for wifi traffic polling. 3877 turnScreenOn(); 3878 sWifiManager.registerTrafficStateCallback( 3879 Executors.newSingleThreadExecutor(), callback); 3880 // Send some traffic to trigger the traffic state change callbacks. 3881 sendTraffic(); 3882 // now wait for callback 3883 boolean success = callback.latch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS); 3884 // check if we got the state changed callback with both data in and out 3885 assertTrue(success); 3886 } finally { 3887 turnScreenOff(); 3888 sWifiManager.unregisterTrafficStateCallback(callback); 3889 uiAutomation.dropShellPermissionIdentity(); 3890 } 3891 } 3892 3893 /** 3894 * Tests {@link WifiManager#setScanAlwaysAvailable(boolean)} & 3895 * {@link WifiManager#isScanAlwaysAvailable()}. 3896 */ 3897 @Test testScanAlwaysAvailable()3898 public void testScanAlwaysAvailable() throws Exception { 3899 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3900 Boolean currState = null; 3901 try { 3902 uiAutomation.adoptShellPermissionIdentity(); 3903 currState = sWifiManager.isScanAlwaysAvailable(); 3904 boolean newState = !currState; 3905 sWifiManager.setScanAlwaysAvailable(newState); 3906 PollingCheck.check( 3907 "Wifi scanning toggle failed!", 3908 DURATION_SETTINGS_TOGGLE, 3909 () -> sWifiManager.isScanAlwaysAvailable() == newState); 3910 assertEquals(newState, sWifiManager.isScanAlwaysAvailable()); 3911 } finally { 3912 if (currState != null) sWifiManager.setScanAlwaysAvailable(currState); 3913 uiAutomation.dropShellPermissionIdentity(); 3914 } 3915 } 3916 3917 /** 3918 * Tests {@link WifiManager#setScanThrottleEnabled(boolean)} & 3919 * {@link WifiManager#isScanThrottleEnabled()}. 3920 */ 3921 @Test testScanThrottleEnabled()3922 public void testScanThrottleEnabled() throws Exception { 3923 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3924 Boolean currState = null; 3925 try { 3926 uiAutomation.adoptShellPermissionIdentity(); 3927 currState = sWifiManager.isScanThrottleEnabled(); 3928 boolean newState = !currState; 3929 sWifiManager.setScanThrottleEnabled(newState); 3930 PollingCheck.check( 3931 "Wifi settings toggle failed!", 3932 DURATION_SETTINGS_TOGGLE, 3933 () -> sWifiManager.isScanThrottleEnabled() == newState); 3934 assertEquals(newState, sWifiManager.isScanThrottleEnabled()); 3935 } finally { 3936 if (currState != null) sWifiManager.setScanThrottleEnabled(currState); 3937 uiAutomation.dropShellPermissionIdentity(); 3938 } 3939 } 3940 3941 /** 3942 * Tests {@link WifiManager#setAutoWakeupEnabled(boolean)} & 3943 * {@link WifiManager#isAutoWakeupEnabled()}. 3944 */ 3945 @Test testAutoWakeUpEnabled()3946 public void testAutoWakeUpEnabled() throws Exception { 3947 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3948 Boolean currState = null; 3949 try { 3950 uiAutomation.adoptShellPermissionIdentity(); 3951 currState = sWifiManager.isAutoWakeupEnabled(); 3952 boolean newState = !currState; 3953 sWifiManager.setAutoWakeupEnabled(newState); 3954 PollingCheck.check( 3955 "Wifi settings toggle failed!", 3956 DURATION_SETTINGS_TOGGLE, 3957 () -> sWifiManager.isAutoWakeupEnabled() == newState); 3958 assertEquals(newState, sWifiManager.isAutoWakeupEnabled()); 3959 } finally { 3960 if (currState != null) sWifiManager.setAutoWakeupEnabled(currState); 3961 uiAutomation.dropShellPermissionIdentity(); 3962 } 3963 } 3964 3965 /** 3966 * Tests {@link WifiManager#setVerboseLoggingEnabled(boolean)} & 3967 * {@link WifiManager#isVerboseLoggingEnabled()}. 3968 */ 3969 @Test testVerboseLoggingEnabled()3970 public void testVerboseLoggingEnabled() throws Exception { 3971 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 3972 Boolean currState = null; 3973 TestWifiVerboseLoggingStatusChangedListener listener = 3974 WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext) 3975 ? new TestWifiVerboseLoggingStatusChangedListener() : null; 3976 try { 3977 uiAutomation.adoptShellPermissionIdentity(); 3978 if (listener != null) { 3979 sWifiManager.addWifiVerboseLoggingStatusChangedListener(mExecutor, listener); 3980 } 3981 currState = sWifiManager.isVerboseLoggingEnabled(); 3982 boolean newState = !currState; 3983 if (listener != null) { 3984 assertEquals(0, listener.numCalls); 3985 } 3986 sWifiManager.setVerboseLoggingEnabled(newState); 3987 PollingCheck.check( 3988 "Wifi verbose logging toggle failed!", 3989 DURATION_SETTINGS_TOGGLE, 3990 () -> sWifiManager.isVerboseLoggingEnabled() == newState); 3991 if (listener != null) { 3992 PollingCheck.check( 3993 "Verbose logging listener timeout", 3994 DURATION_SETTINGS_TOGGLE, 3995 () -> listener.status == newState && listener.numCalls == 1); 3996 } 3997 } finally { 3998 if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState); 3999 if (listener != null) { 4000 sWifiManager.removeWifiVerboseLoggingStatusChangedListener(listener); 4001 } 4002 uiAutomation.dropShellPermissionIdentity(); 4003 } 4004 } 4005 4006 /** 4007 * Tests {@link WifiManager#setVerboseLoggingLevel(int)}. 4008 */ 4009 @Test testSetVerboseLogging()4010 public void testSetVerboseLogging() throws Exception { 4011 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4012 Boolean currState = null; 4013 try { 4014 uiAutomation.adoptShellPermissionIdentity(); 4015 currState = sWifiManager.isVerboseLoggingEnabled(); 4016 4017 sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED); 4018 assertTrue(sWifiManager.isVerboseLoggingEnabled()); 4019 assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED, 4020 sWifiManager.getVerboseLoggingLevel()); 4021 4022 sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED); 4023 assertFalse(sWifiManager.isVerboseLoggingEnabled()); 4024 assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED, 4025 sWifiManager.getVerboseLoggingLevel()); 4026 } finally { 4027 if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState); 4028 uiAutomation.dropShellPermissionIdentity(); 4029 } 4030 } 4031 4032 /** 4033 * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode. 4034 */ 4035 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 4036 @Test testSetVerboseLoggingShowKeyModeNonUserBuild()4037 public void testSetVerboseLoggingShowKeyModeNonUserBuild() throws Exception { 4038 if (Build.TYPE.equals("user")) return; 4039 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4040 Boolean currState = null; 4041 try { 4042 uiAutomation.adoptShellPermissionIdentity(); 4043 currState = sWifiManager.isVerboseLoggingEnabled(); 4044 4045 sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY); 4046 assertTrue(sWifiManager.isVerboseLoggingEnabled()); 4047 assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY, 4048 sWifiManager.getVerboseLoggingLevel()); 4049 } finally { 4050 if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState); 4051 uiAutomation.dropShellPermissionIdentity(); 4052 } 4053 } 4054 4055 /** 4056 * Test {@link WifiManager#setVerboseLoggingLevel(int)} for show key mode. 4057 */ 4058 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 4059 @Test testSetVerboseLoggingShowKeyModeUserBuild()4060 public void testSetVerboseLoggingShowKeyModeUserBuild() throws Exception { 4061 if (!Build.TYPE.equals("user")) return; 4062 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4063 Boolean currState = null; 4064 try { 4065 uiAutomation.adoptShellPermissionIdentity(); 4066 currState = sWifiManager.isVerboseLoggingEnabled(); 4067 4068 sWifiManager.setVerboseLoggingLevel(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY); 4069 assertTrue(sWifiManager.isVerboseLoggingEnabled()); 4070 assertEquals(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY, 4071 sWifiManager.getVerboseLoggingLevel()); 4072 fail("Verbosing logging show key mode should not be allowed for user build."); 4073 } catch (SecurityException e) { 4074 // expected 4075 } finally { 4076 if (currState != null) sWifiManager.setVerboseLoggingEnabled(currState); 4077 uiAutomation.dropShellPermissionIdentity(); 4078 } 4079 } 4080 4081 /** 4082 * Tests {@link WifiManager#factoryReset()} cannot be invoked from a non-privileged app. 4083 * 4084 * Note: This intentionally does not test the full reset functionality because it causes 4085 * the existing saved networks on the device to be lost after the test. If you add the 4086 * networks back after reset, the ownership of saved networks will change. 4087 */ 4088 @Test testFactoryReset()4089 public void testFactoryReset() throws Exception { 4090 List<WifiConfiguration> beforeSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions( 4091 sWifiManager::getConfiguredNetworks); 4092 try { 4093 sWifiManager.factoryReset(); 4094 fail("Factory reset should not be allowed for non-privileged apps"); 4095 } catch (SecurityException e) { 4096 // expected 4097 } 4098 List<WifiConfiguration> afterSavedNetworks = ShellIdentityUtils.invokeWithShellPermissions( 4099 sWifiManager::getConfiguredNetworks); 4100 assertEquals(beforeSavedNetworks.size(), afterSavedNetworks.size()); 4101 } 4102 4103 /** 4104 * Test {@link WifiNetworkConnectionStatistics} does not crash. 4105 * TODO(b/150891569): deprecate it in Android S, this API is not used anywhere. 4106 */ 4107 @Test testWifiNetworkConnectionStatistics()4108 public void testWifiNetworkConnectionStatistics() { 4109 new WifiNetworkConnectionStatistics(); 4110 WifiNetworkConnectionStatistics stats = new WifiNetworkConnectionStatistics(0, 0); 4111 new WifiNetworkConnectionStatistics(stats); 4112 } 4113 4114 /** 4115 * Verify that startRestrictingAutoJoinToSubscriptionId disconnects wifi and disables 4116 * auto-connect to non-carrier-merged networks. Then verify that 4117 * stopRestrictingAutoJoinToSubscriptionId makes the disabled networks clear to connect 4118 * again. 4119 */ 4120 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 4121 @Test testStartAndStopRestrictingAutoJoinToSubscriptionId()4122 public void testStartAndStopRestrictingAutoJoinToSubscriptionId() throws Exception { 4123 int fakeSubscriptionId = 5; 4124 ShellIdentityUtils.invokeWithShellPermissions(() -> 4125 sWifiManager.startRestrictingAutoJoinToSubscriptionId(fakeSubscriptionId)); 4126 waitForDisconnection(); 4127 startScan(); 4128 ensureNotConnected(); 4129 ShellIdentityUtils.invokeWithShellPermissions(() -> 4130 sWifiManager.stopRestrictingAutoJoinToSubscriptionId()); 4131 startScan(); 4132 waitForConnection(); 4133 } 4134 4135 private class TestActiveCountryCodeChangedCallback implements 4136 WifiManager.ActiveCountryCodeChangedCallback { 4137 private String mCurrentCountryCode; 4138 private boolean mIsOnActiveCountryCodeChangedCalled = false; 4139 private boolean mIsOnCountryCodeInactiveCalled = false; 4140 isOnActiveCountryCodeChangedCalled()4141 public boolean isOnActiveCountryCodeChangedCalled() { 4142 return mIsOnActiveCountryCodeChangedCalled; 4143 } 4144 isOnCountryCodeInactiveCalled()4145 public boolean isOnCountryCodeInactiveCalled() { 4146 return mIsOnCountryCodeInactiveCalled; 4147 } resetCallbackCallededHistory()4148 public void resetCallbackCallededHistory() { 4149 mIsOnActiveCountryCodeChangedCalled = false; 4150 mIsOnCountryCodeInactiveCalled = false; 4151 } 4152 getCurrentDriverCountryCode()4153 public String getCurrentDriverCountryCode() { 4154 return mCurrentCountryCode; 4155 } 4156 4157 @Override onActiveCountryCodeChanged(String country)4158 public void onActiveCountryCodeChanged(String country) { 4159 Log.d(TAG, "Receive DriverCountryCodeChanged to " + country); 4160 mCurrentCountryCode = country; 4161 mIsOnActiveCountryCodeChangedCalled = true; 4162 } 4163 4164 @Override onCountryCodeInactive()4165 public void onCountryCodeInactive() { 4166 Log.d(TAG, "Receive onCountryCodeInactive"); 4167 mCurrentCountryCode = null; 4168 mIsOnCountryCodeInactiveCalled = true; 4169 } 4170 } 4171 4172 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 4173 @Test testActiveCountryCodeChangedCallback()4174 public void testActiveCountryCodeChangedCallback() throws Exception { 4175 if (!hasLocationFeature()) { 4176 // skip the test if location is not supported 4177 return; 4178 } 4179 if (!isLocationEnabled()) { 4180 fail("Please enable location for this test - since country code is not available" 4181 + " when location is disabled!"); 4182 } 4183 if (shouldSkipCountryCodeDependentTest()) { 4184 // skip the test when there is no Country Code available 4185 return; 4186 } 4187 if (!PropertyUtil.isVndkApiLevelAtLeast(Build.VERSION_CODES.TIRAMISU)) { 4188 // skip the test if vendor version is lower than T 4189 return; 4190 } 4191 TestActiveCountryCodeChangedCallback testCountryCodeChangedCallback = 4192 new TestActiveCountryCodeChangedCallback(); 4193 TestExecutor executor = new TestExecutor(); 4194 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4195 try { 4196 // Run with scanning disable to make sure there is no active mode. 4197 runWithScanning(() -> { 4198 uiAutomation.adoptShellPermissionIdentity(); 4199 turnOffWifiAndTetheredHotspotIfEnabled(); 4200 sWifiManager.registerActiveCountryCodeChangedCallback( 4201 executor, testCountryCodeChangedCallback); 4202 4203 4204 PollingCheck.check( 4205 "DriverCountryCode is non-null when wifi off", 4206 5000, 4207 () -> { 4208 executor.runAll(); 4209 return testCountryCodeChangedCallback 4210 .isOnCountryCodeInactiveCalled() 4211 && testCountryCodeChangedCallback.getCurrentDriverCountryCode() 4212 == null; 4213 }); 4214 // Enable wifi to make sure country code has been updated. 4215 sWifiManager.setWifiEnabled(true); 4216 PollingCheck.check( 4217 "DriverCountryCode is null when wifi on", 4218 5000, 4219 () -> { 4220 executor.runAll(); 4221 return testCountryCodeChangedCallback 4222 .isOnActiveCountryCodeChangedCalled() 4223 && testCountryCodeChangedCallback.getCurrentDriverCountryCode() 4224 != null; 4225 }); 4226 // Disable wifi to trigger country code change 4227 sWifiManager.setWifiEnabled(false); 4228 PollingCheck.check( 4229 "DriverCountryCode should be null when wifi off", 4230 5000, 4231 () -> { 4232 executor.runAll(); 4233 return testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled() 4234 && testCountryCodeChangedCallback 4235 .getCurrentDriverCountryCode() == null; 4236 }); 4237 sWifiManager.unregisterActiveCountryCodeChangedCallback( 4238 testCountryCodeChangedCallback); 4239 testCountryCodeChangedCallback.resetCallbackCallededHistory(); 4240 sWifiManager.setWifiEnabled(true); 4241 // Check there is no callback has been called. 4242 PollingCheck.check( 4243 "Callback is called after unregister", 4244 5000, 4245 () -> { 4246 executor.runAll(); 4247 return !testCountryCodeChangedCallback.isOnCountryCodeInactiveCalled() 4248 && !testCountryCodeChangedCallback 4249 .isOnActiveCountryCodeChangedCalled(); 4250 }); 4251 }, false /* Run with disabled */); 4252 } finally { 4253 uiAutomation.dropShellPermissionIdentity(); 4254 } 4255 } 4256 4257 /** 4258 * Test that the wifi country code is either null, or a length-2 string. 4259 */ 4260 @Test testGetCountryCode()4261 public void testGetCountryCode() throws Exception { 4262 String wifiCountryCode = ShellIdentityUtils.invokeWithShellPermissions( 4263 sWifiManager::getCountryCode); 4264 4265 if (wifiCountryCode == null) { 4266 return; 4267 } 4268 assertEquals(2, wifiCountryCode.length()); 4269 4270 // assert that the country code is all uppercase 4271 assertEquals(wifiCountryCode.toUpperCase(Locale.US), wifiCountryCode); 4272 4273 // skip if Telephony is unsupported 4274 if (!WifiFeature.isTelephonySupported(sContext)) { 4275 return; 4276 } 4277 4278 String telephonyCountryCode = sContext.getSystemService(TelephonyManager.class) 4279 .getNetworkCountryIso(); 4280 4281 // skip if Telephony country code is unavailable 4282 if (telephonyCountryCode == null || telephonyCountryCode.isEmpty()) { 4283 return; 4284 } 4285 4286 assertEquals(telephonyCountryCode, wifiCountryCode.toLowerCase(Locale.US)); 4287 } 4288 4289 /** 4290 * Helper function to test getCurrentNetwork 4291 * @param shouldDisableWifi true to disable wifi, false to disconnect 4292 * @throws Exception 4293 */ testGetCurrentNetwork(boolean shouldDisableWifi)4294 private void testGetCurrentNetwork(boolean shouldDisableWifi) throws Exception { 4295 // ensure Wifi is connected 4296 ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.reconnect()); 4297 PollingCheck.check( 4298 "Connection info network id is invalid - Please ensure there is a " + 4299 " saved network in range of this device", 4300 WIFI_CONNECT_TIMEOUT_MILLIS, 4301 () -> sWifiManager.getConnectionInfo().getNetworkId() != -1); 4302 PollingCheck.check( 4303 "Wifi current network is null - Please ensure there is a saved network " + 4304 " in range of this device", 4305 WIFI_CONNECT_TIMEOUT_MILLIS, 4306 () -> ShellIdentityUtils.invokeWithShellPermissions(sWifiManager::getCurrentNetwork) 4307 != null); 4308 4309 String networkKey = sWifiManager.getConnectionInfo().getNetworkKey(); 4310 assertNotNull(networkKey); 4311 4312 Network wifiCurrentNetwork = ShellIdentityUtils.invokeWithShellPermissions( 4313 sWifiManager::getCurrentNetwork); 4314 assertNotNull(wifiCurrentNetwork); 4315 4316 List<WifiConfiguration> configuredNetwork = ShellIdentityUtils.invokeWithShellPermissions( 4317 sWifiManager::getConfiguredNetworks); 4318 4319 boolean isNetworkKeyExist = false; 4320 for (WifiConfiguration config : configuredNetwork) { 4321 if (config.getAllNetworkKeys().contains(networkKey)) { 4322 isNetworkKeyExist = true; 4323 break; 4324 } 4325 } 4326 4327 assertTrue(isNetworkKeyExist); 4328 4329 TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock); 4330 synchronized (mLock) { 4331 try { 4332 // File a request for wifi network. 4333 sConnectivityManager.registerNetworkCallback( 4334 new NetworkRequest.Builder() 4335 .addTransportType(TRANSPORT_WIFI) 4336 .build(), 4337 networkCallbackListener); 4338 // now wait for callback 4339 mLock.wait(TEST_WAIT_DURATION_MS); 4340 } catch (InterruptedException e) { 4341 } 4342 } 4343 assertTrue(networkCallbackListener.onAvailableCalled); 4344 Network connectivityCurrentNetwork = networkCallbackListener.network; 4345 assertEquals(connectivityCurrentNetwork, wifiCurrentNetwork); 4346 4347 if (shouldDisableWifi) { 4348 setWifiEnabled(false); 4349 PollingCheck.check( 4350 "Wifi not disabled!", 4351 20000, 4352 () -> !sWifiManager.isWifiEnabled()); 4353 } else { 4354 ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.disconnect()); 4355 } 4356 PollingCheck.check( 4357 "Wifi not disconnected! Connection info network id still valid", 4358 20000, 4359 () -> sWifiManager.getConnectionInfo().getNetworkId() == -1); 4360 4361 PollingCheck.check( 4362 "Wifi not disconnected! Current network is not null", 4363 WIFI_CONNECT_TIMEOUT_MILLIS, 4364 () -> ShellIdentityUtils.invokeWithShellPermissions(sWifiManager::getCurrentNetwork) 4365 == null); 4366 } 4367 4368 /** 4369 * Test that {@link WifiManager#getCurrentNetwork()} returns a Network object consistent 4370 * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network, 4371 * and returns null when disconnected. 4372 */ 4373 @Test testGetCurrentNetworkWifiDisconnected()4374 public void testGetCurrentNetworkWifiDisconnected() throws Exception { 4375 testGetCurrentNetwork(false); 4376 } 4377 4378 /** 4379 * Test that {@link WifiManager#getCurrentNetwork()} returns a Network object consistent 4380 * with {@link ConnectivityManager#registerNetworkCallback} when connected to a Wifi network, 4381 * and returns null when wifi disabled. 4382 */ 4383 @Test testGetCurrentNetworkWifiDisabled()4384 public void testGetCurrentNetworkWifiDisabled() throws Exception { 4385 testGetCurrentNetwork(true); 4386 } 4387 4388 /** 4389 * Tests {@link WifiManager#isWpa3SaeSupported()} does not crash. 4390 */ 4391 @Test testIsWpa3SaeSupported()4392 public void testIsWpa3SaeSupported() throws Exception { 4393 sWifiManager.isWpa3SaeSupported(); 4394 } 4395 4396 /** 4397 * Tests {@link WifiManager#isWpa3SuiteBSupported()} does not crash. 4398 */ 4399 @Test testIsWpa3SuiteBSupported()4400 public void testIsWpa3SuiteBSupported() throws Exception { 4401 sWifiManager.isWpa3SuiteBSupported(); 4402 } 4403 4404 /** 4405 * Tests {@link WifiManager#isEnhancedOpenSupported()} does not crash. 4406 */ 4407 @Test testIsEnhancedOpenSupported()4408 public void testIsEnhancedOpenSupported() throws Exception { 4409 sWifiManager.isEnhancedOpenSupported(); 4410 } 4411 4412 /** 4413 * Test that {@link WifiManager#is5GHzBandSupported()} returns successfully in 4414 * both WiFi enabled/disabled states. 4415 * Note that the response depends on device support and hence both true/false 4416 * are valid responses. 4417 */ 4418 @Test testIs5GhzBandSupported()4419 public void testIs5GhzBandSupported() throws Exception { 4420 // Check for 5GHz support with wifi enabled 4421 setWifiEnabled(true); 4422 PollingCheck.check( 4423 "Wifi not enabled!", 4424 20000, 4425 () -> sWifiManager.isWifiEnabled()); 4426 boolean isSupportedEnabled = sWifiManager.is5GHzBandSupported(); 4427 4428 // Check for 5GHz support with wifi disabled 4429 setWifiEnabled(false); 4430 PollingCheck.check( 4431 "Wifi not disabled!", 4432 20000, 4433 () -> !sWifiManager.isWifiEnabled()); 4434 boolean isSupportedDisabled = sWifiManager.is5GHzBandSupported(); 4435 4436 // If Support is true when WiFi is disable, then it has to be true when it is enabled. 4437 // Note, the reverse is a valid case. 4438 if (isSupportedDisabled) { 4439 assertTrue(isSupportedEnabled); 4440 } 4441 } 4442 4443 /** 4444 * Test that {@link WifiManager#is6GHzBandSupported()} returns successfully in 4445 * both Wifi enabled/disabled states. 4446 * Note that the response depends on device support and hence both true/false 4447 * are valid responses. 4448 */ 4449 @Test testIs6GhzBandSupported()4450 public void testIs6GhzBandSupported() throws Exception { 4451 // Check for 6GHz support with wifi enabled 4452 setWifiEnabled(true); 4453 PollingCheck.check( 4454 "Wifi not enabled!", 4455 20000, 4456 () -> sWifiManager.isWifiEnabled()); 4457 boolean isSupportedEnabled = sWifiManager.is6GHzBandSupported(); 4458 4459 // Check for 6GHz support with wifi disabled 4460 setWifiEnabled(false); 4461 PollingCheck.check( 4462 "Wifi not disabled!", 4463 20000, 4464 () -> !sWifiManager.isWifiEnabled()); 4465 boolean isSupportedDisabled = sWifiManager.is6GHzBandSupported(); 4466 4467 // If Support is true when WiFi is disable, then it has to be true when it is enabled. 4468 // Note, the reverse is a valid case. 4469 if (isSupportedDisabled) { 4470 assertTrue(isSupportedEnabled); 4471 } 4472 } 4473 4474 /** 4475 * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in 4476 * both Wifi enabled/disabled states. 4477 * Note that the response depends on device support and hence both true/false 4478 * are valid responses. 4479 */ 4480 @Test testIs60GhzBandSupported()4481 public void testIs60GhzBandSupported() throws Exception { 4482 if (!(WifiFeature.isWifiSupported(sContext) 4483 && ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S))) { 4484 // skip the test if WiFi is not supported 4485 return; 4486 } 4487 4488 // Check for 60GHz support with wifi enabled 4489 setWifiEnabled(true); 4490 PollingCheck.check( 4491 "Wifi not enabled!", 4492 20000, 4493 () -> sWifiManager.isWifiEnabled()); 4494 boolean isSupportedEnabled = sWifiManager.is60GHzBandSupported(); 4495 4496 // Check for 60GHz support with wifi disabled 4497 setWifiEnabled(false); 4498 PollingCheck.check( 4499 "Wifi not disabled!", 4500 20000, 4501 () -> !sWifiManager.isWifiEnabled()); 4502 boolean isSupportedDisabled = sWifiManager.is60GHzBandSupported(); 4503 4504 // If Support is true when WiFi is disable, then it has to be true when it is enabled. 4505 // Note, the reverse is a valid case. 4506 if (isSupportedDisabled) { 4507 assertTrue(isSupportedEnabled); 4508 } 4509 } 4510 4511 /** 4512 * Test that {@link WifiManager#isWifiStandardSupported()} returns successfully in 4513 * both Wifi enabled/disabled states. The test is to be performed on 4514 * {@link WifiAnnotations}'s {@code WIFI_STANDARD_} 4515 * Note that the response depends on device support and hence both true/false 4516 * are valid responses. 4517 */ 4518 @Test testIsWifiStandardsSupported()4519 public void testIsWifiStandardsSupported() throws Exception { 4520 // Check for WiFi standards support with wifi enabled 4521 setWifiEnabled(true); 4522 PollingCheck.check( 4523 "Wifi not enabled!", 4524 20000, 4525 () -> sWifiManager.isWifiEnabled()); 4526 boolean isLegacySupportedEnabled = 4527 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); 4528 boolean is11nSupporedEnabled = 4529 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); 4530 boolean is11acSupportedEnabled = 4531 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); 4532 boolean is11axSupportedEnabled = 4533 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); 4534 boolean is11beSupportedEnabled = 4535 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE); 4536 4537 // Check for WiFi standards support with wifi disabled 4538 setWifiEnabled(false); 4539 PollingCheck.check( 4540 "Wifi not disabled!", 4541 20000, 4542 () -> !sWifiManager.isWifiEnabled()); 4543 4544 boolean isLegacySupportedDisabled = 4545 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_LEGACY); 4546 boolean is11nSupportedDisabled = 4547 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11N); 4548 boolean is11acSupportedDisabled = 4549 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AC); 4550 boolean is11axSupportedDisabled = 4551 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX); 4552 boolean is11beSupportedDisabled = 4553 sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE); 4554 4555 if (isLegacySupportedDisabled) { 4556 assertTrue(isLegacySupportedEnabled); 4557 } 4558 4559 if (is11nSupportedDisabled) { 4560 assertTrue(is11nSupporedEnabled); 4561 } 4562 4563 if (is11acSupportedDisabled) { 4564 assertTrue(is11acSupportedEnabled); 4565 } 4566 4567 if (is11axSupportedDisabled) { 4568 assertTrue(is11axSupportedEnabled); 4569 } 4570 4571 if (is11beSupportedDisabled) { 4572 assertTrue(is11beSupportedEnabled); 4573 } 4574 } 4575 createPasspointConfiguration()4576 private static PasspointConfiguration createPasspointConfiguration() { 4577 PasspointConfiguration config = new PasspointConfiguration(); 4578 HomeSp homeSp = new HomeSp(); 4579 homeSp.setFqdn("test.com"); 4580 homeSp.setFriendlyName("friendly name"); 4581 homeSp.setRoamingConsortiumOis(new long[]{0x55, 0x66}); 4582 config.setHomeSp(homeSp); 4583 Credential.SimCredential simCred = new Credential.SimCredential(); 4584 simCred.setImsi("123456*"); 4585 simCred.setEapType(23 /* EAP_AKA */); 4586 Credential cred = new Credential(); 4587 cred.setRealm("realm"); 4588 cred.setSimCredential(simCred); 4589 config.setCredential(cred); 4590 4591 return config; 4592 } 4593 4594 /** 4595 * Tests {@link WifiManager#addOrUpdatePasspointConfiguration(PasspointConfiguration)} 4596 * adds a Passpoint configuration correctly by getting it once it is added, and comparing it 4597 * to the local copy of the configuration. 4598 */ 4599 @Test testAddOrUpdatePasspointConfiguration()4600 public void testAddOrUpdatePasspointConfiguration() throws Exception { 4601 // Create and install a Passpoint configuration 4602 PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); 4603 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4604 try { 4605 uiAutomation.adoptShellPermissionIdentity(); 4606 sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); 4607 4608 // Compare configurations 4609 List<PasspointConfiguration> configurations = sWifiManager.getPasspointConfigurations(); 4610 assertNotNull("The installed passpoint profile is missing", configurations); 4611 assertEquals(passpointConfiguration, getTargetPasspointConfiguration(configurations, 4612 passpointConfiguration.getUniqueId())); 4613 } finally { 4614 // Clean up 4615 sWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); 4616 uiAutomation.dropShellPermissionIdentity(); 4617 } 4618 } 4619 4620 /** 4621 * Tests {@link WifiManager#setPasspointMeteredOverride(String, int)} 4622 * adds a Passpoint configuration correctly, check the default metered setting. Use API change 4623 * metered override, verify Passpoint configuration changes with it. 4624 */ 4625 @Test testSetPasspointMeteredOverride()4626 public void testSetPasspointMeteredOverride() throws Exception { 4627 // Create and install a Passpoint configuration 4628 PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); 4629 String fqdn = passpointConfiguration.getHomeSp().getFqdn(); 4630 String uniqueId = passpointConfiguration.getUniqueId(); 4631 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4632 4633 try { 4634 uiAutomation.adoptShellPermissionIdentity(); 4635 sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); 4636 PasspointConfiguration saved = getTargetPasspointConfiguration( 4637 sWifiManager.getPasspointConfigurations(), uniqueId); 4638 assertNotNull("The installed passpoint profile is missing", saved); 4639 // Verify meter override setting. 4640 assertEquals("Metered overrider default should be none", 4641 WifiConfiguration.METERED_OVERRIDE_NONE, saved.getMeteredOverride()); 4642 // Change the meter override setting. 4643 sWifiManager.setPasspointMeteredOverride(fqdn, 4644 WifiConfiguration.METERED_OVERRIDE_METERED); 4645 // Verify passpoint config change with the new setting. 4646 saved = getTargetPasspointConfiguration( 4647 sWifiManager.getPasspointConfigurations(), uniqueId); 4648 assertNotNull("The installed passpoint profile is missing", saved); 4649 assertEquals("Metered override should be metered", 4650 WifiConfiguration.METERED_OVERRIDE_METERED, saved.getMeteredOverride()); 4651 } finally { 4652 // Clean up 4653 sWifiManager.removePasspointConfiguration(fqdn); 4654 uiAutomation.dropShellPermissionIdentity(); 4655 } 4656 } 4657 4658 /** 4659 * Tests that 4660 * {@link WifiManager#startSubscriptionProvisioning(OsuProvider, Executor, ProvisioningCallback)} 4661 * starts a subscription provisioning, and confirm a status callback invoked once. 4662 */ 4663 @Test testStartSubscriptionProvisioning()4664 public void testStartSubscriptionProvisioning() throws Exception { 4665 // Using Java reflection to construct an OsuProvider instance because its constructor is 4666 // hidden and not available to apps. 4667 Class<?> osuProviderClass = Class.forName("android.net.wifi.hotspot2.OsuProvider"); 4668 Constructor<?> osuProviderClassConstructor = osuProviderClass.getConstructor(String.class, 4669 Map.class, String.class, Uri.class, String.class, List.class); 4670 4671 OsuProvider osuProvider = (OsuProvider) osuProviderClassConstructor.newInstance(TEST_SSID, 4672 TEST_FRIENDLY_NAMES, TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, 4673 TEST_METHOD_LIST); 4674 TestProvisioningCallback callback = new TestProvisioningCallback(mLock); 4675 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4676 try { 4677 uiAutomation.adoptShellPermissionIdentity(); 4678 synchronized (mLock) { 4679 // Start a subscription provisioning for a non-existent Passpoint R2 AP 4680 sWifiManager.startSubscriptionProvisioning(osuProvider, mExecutor, callback); 4681 mLock.wait(TEST_WAIT_DURATION_MS); 4682 } 4683 } finally { 4684 uiAutomation.dropShellPermissionIdentity(); 4685 } 4686 waitForDisconnection(); 4687 // Expect only a single callback event, connecting. Since AP doesn't exist, it ends here 4688 assertEquals(ProvisioningCallback.OSU_STATUS_AP_CONNECTING, callback.mProvisioningStatus); 4689 // No failure callbacks expected 4690 assertEquals(0, callback.mProvisioningFailureStatus); 4691 // No completion callback expected 4692 assertFalse(callback.mProvisioningComplete); 4693 ShellIdentityUtils.invokeWithShellPermissions(() -> sWifiManager.setWifiEnabled(false)); 4694 PollingCheck.check("Wifi not disabled!", 20000, 4695 () -> !sWifiManager.isWifiEnabled()); 4696 } 4697 4698 /** 4699 * Tests {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} does not crash. 4700 */ 4701 @Test testSetTdlsEnabled()4702 public void testSetTdlsEnabled() throws Exception { 4703 InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS); 4704 4705 sWifiManager.setTdlsEnabled(inetAddress, true); 4706 Thread.sleep(50); 4707 sWifiManager.setTdlsEnabled(inetAddress, false); 4708 } 4709 4710 /** 4711 * Tests {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} does not crash. 4712 */ 4713 @Test testSetTdlsEnabledWithMacAddress()4714 public void testSetTdlsEnabledWithMacAddress() throws Exception { 4715 sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true); 4716 Thread.sleep(50); 4717 sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false); 4718 } 4719 4720 /** 4721 * Verify the usage of {@code WifiManager#isTdlsOperationCurrentlyAvailable}. 4722 */ 4723 @Test testIsTdlsOperationCurrentlyAvailable()4724 public void testIsTdlsOperationCurrentlyAvailable() throws Exception { 4725 boolean expectedResult = sWifiManager.isTdlsSupported(); 4726 AtomicBoolean enabled = new AtomicBoolean(false); 4727 sWifiManager.isTdlsOperationCurrentlyAvailable(mExecutor, 4728 (enabledLocal) -> { 4729 synchronized (mLock) { 4730 enabled.set(enabledLocal); 4731 mLock.notify(); 4732 } 4733 }); 4734 synchronized (mLock) { 4735 mLock.wait(TEST_WAIT_DURATION_MS); 4736 } 4737 assertEquals(expectedResult, enabled.get()); 4738 } 4739 4740 /** 4741 * Verify the usage of {@code WifiManager#getMaxSupportedConcurrentTdlsSessions}. 4742 */ 4743 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 4744 @Test testGetMaxSupportedConcurrentTdlsSessions()4745 public void testGetMaxSupportedConcurrentTdlsSessions() throws Exception { 4746 if (!sWifiManager.isTdlsSupported()) { 4747 // skip the test if TDLS is not supported 4748 return; 4749 } 4750 4751 AtomicInteger maxNumOfTdlsSessions = new AtomicInteger(0); 4752 sWifiManager.getMaxSupportedConcurrentTdlsSessions(mExecutor, 4753 (maxNumOfTdlsSessionsLocal) -> { 4754 synchronized (mLock) { 4755 maxNumOfTdlsSessions.set(maxNumOfTdlsSessionsLocal); 4756 mLock.notify(); 4757 } 4758 }); 4759 synchronized (mLock) { 4760 mLock.wait(TEST_WAIT_DURATION_MS); 4761 } 4762 // {@code WifiManager#getMaxSupportedConcurrentTdlsSessions} returns -1 4763 // if HAL doesn't provide this TDLS capability. 4764 assertTrue(maxNumOfTdlsSessions.get() == -1 || maxNumOfTdlsSessions.get() > 0); 4765 } 4766 4767 /** 4768 * Verify the usage of 4769 * {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}. 4770 */ 4771 @Test testSetTdlsEnabledWithIpAddressConsumerModel()4772 public void testSetTdlsEnabledWithIpAddressConsumerModel() throws Exception { 4773 if (!sWifiManager.isTdlsSupported()) { 4774 // skip the test if TDLS is not supported 4775 return; 4776 } 4777 4778 InetAddress inetAddress = InetAddress.getByName(TEST_IP_ADDRESS); 4779 sWifiManager.setTdlsEnabled(inetAddress, true, mExecutor, (e) -> {}); 4780 sWifiManager.setTdlsEnabled(inetAddress, false, mExecutor, (e) -> {}); 4781 } 4782 4783 /** 4784 * Verify the usage of 4785 * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)} 4786 * and {@link WifiManager#getNumberOfEnabledTdlsSessions(Executor, Consumer)}. 4787 */ 4788 @Test testSetTdlsEnabledWithMacAddressConsumerModel()4789 public void testSetTdlsEnabledWithMacAddressConsumerModel() throws Exception { 4790 if (!sWifiManager.isTdlsSupported()) { 4791 // skip the test if TDLS is not supported 4792 return; 4793 } 4794 4795 AtomicBoolean enabled = new AtomicBoolean(false); 4796 AtomicInteger numOfTdlsSessions = new AtomicInteger(0); 4797 Consumer<Integer> listener2 = new Consumer<Integer>() { 4798 @Override 4799 public void accept(Integer value) { 4800 synchronized (mLock) { 4801 numOfTdlsSessions.set(value); 4802 mLock.notify(); 4803 } 4804 } 4805 }; 4806 4807 sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, true, mExecutor, 4808 (enabledLocal) -> { 4809 synchronized (mLock) { 4810 enabled.set(enabledLocal); 4811 mLock.notify(); 4812 } 4813 }); 4814 synchronized (mLock) { 4815 mLock.wait(TEST_WAIT_DURATION_MS); 4816 } 4817 assertTrue(enabled.get()); 4818 sWifiManager.getNumberOfEnabledTdlsSessions(mExecutor, listener2); 4819 synchronized (mLock) { 4820 mLock.wait(TEST_WAIT_DURATION_MS); 4821 } 4822 assertEquals(1, numOfTdlsSessions.get()); 4823 4824 sWifiManager.setTdlsEnabledWithMacAddress(TEST_MAC_ADDRESS, false, mExecutor, (e) -> {}); 4825 sWifiManager.getNumberOfEnabledTdlsSessions(mExecutor, listener2); 4826 synchronized (mLock) { 4827 mLock.wait(TEST_WAIT_DURATION_MS); 4828 } 4829 assertEquals(0, numOfTdlsSessions.get()); 4830 } 4831 4832 /** 4833 * Verify WifiNetworkSuggestion.Builder.setMacRandomizationSetting(WifiNetworkSuggestion 4834 * .RANDOMIZATION_NON_PERSISTENT) creates a 4835 * WifiConfiguration with macRandomizationSetting == RANDOMIZATION_NON_PERSISTENT. 4836 * Then verify by default, a WifiConfiguration created by suggestions should have 4837 * macRandomizationSetting == RANDOMIZATION_PERSISTENT. 4838 */ 4839 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 4840 @Test testSuggestionBuilderNonPersistentRandomization()4841 public void testSuggestionBuilderNonPersistentRandomization() throws Exception { 4842 WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() 4843 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE) 4844 .setMacRandomizationSetting(WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT) 4845 .build(); 4846 assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, 4847 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion))); 4848 verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID, 4849 WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT); 4850 4851 suggestion = new WifiNetworkSuggestion.Builder() 4852 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE) 4853 .build(); 4854 assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, 4855 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion))); 4856 verifySuggestionFoundWithMacRandomizationSetting(TEST_SSID, 4857 WifiNetworkSuggestion.RANDOMIZATION_PERSISTENT); 4858 } 4859 verifySuggestionFoundWithMacRandomizationSetting(String ssid, int macRandomizationSetting)4860 private void verifySuggestionFoundWithMacRandomizationSetting(String ssid, 4861 int macRandomizationSetting) { 4862 List<WifiNetworkSuggestion> retrievedSuggestions = sWifiManager.getNetworkSuggestions(); 4863 for (WifiNetworkSuggestion entry : retrievedSuggestions) { 4864 if (entry.getSsid().equals(ssid)) { 4865 assertEquals(macRandomizationSetting, entry.getMacRandomizationSetting()); 4866 return; // pass test after the MAC randomization setting is verified. 4867 } 4868 } 4869 fail("WifiNetworkSuggestion not found for SSID=" + ssid + ", macRandomizationSetting=" 4870 + macRandomizationSetting); 4871 } 4872 4873 /** 4874 * Tests {@link WifiManager#getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(List)} 4875 */ 4876 @Test testGetAllWifiConfigForMatchedNetworkSuggestion()4877 public void testGetAllWifiConfigForMatchedNetworkSuggestion() { 4878 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4879 ScanResult scanResult = new ScanResult(); 4880 scanResult.SSID = TEST_SSID; 4881 scanResult.capabilities = TEST_PSK_CAP; 4882 scanResult.BSSID = TEST_BSSID; 4883 List<ScanResult> testList = Arrays.asList(scanResult); 4884 WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() 4885 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build(); 4886 4887 assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS, 4888 sWifiManager.addNetworkSuggestions(Arrays.asList(suggestion))); 4889 List<WifiConfiguration> matchedResult; 4890 try { 4891 uiAutomation.adoptShellPermissionIdentity(); 4892 matchedResult = sWifiManager 4893 .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(testList); 4894 } finally { 4895 uiAutomation.dropShellPermissionIdentity(); 4896 } 4897 // As suggestion is not approved, will return empty list. 4898 assertTrue(matchedResult.isEmpty()); 4899 } 4900 4901 /** 4902 * Tests {@link WifiManager#getMatchingScanResults(List, List)} 4903 */ 4904 @Test testGetMatchingScanResults()4905 public void testGetMatchingScanResults() { 4906 // Create pair of ScanResult and WifiNetworkSuggestion 4907 ScanResult scanResult = new ScanResult(); 4908 scanResult.SSID = TEST_SSID; 4909 scanResult.capabilities = TEST_PSK_CAP; 4910 scanResult.BSSID = TEST_BSSID; 4911 4912 WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder() 4913 .setSsid(TEST_SSID).setWpa2Passphrase(TEST_PASSPHRASE).build(); 4914 4915 Map<WifiNetworkSuggestion, List<ScanResult>> matchedResults = sWifiManager 4916 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult)); 4917 // Verify result is matched pair of ScanResult and WifiNetworkSuggestion 4918 assertEquals(scanResult.SSID, matchedResults.get(suggestion).get(0).SSID); 4919 4920 // Change ScanResult to unmatched should return empty result. 4921 scanResult.SSID = TEST_SSID_UNQUOTED; 4922 matchedResults = sWifiManager 4923 .getMatchingScanResults(Arrays.asList(suggestion), Arrays.asList(scanResult)); 4924 assertTrue(matchedResults.get(suggestion).isEmpty()); 4925 } 4926 4927 /** 4928 * Tests {@link WifiManager#disableEphemeralNetwork(String)}. 4929 */ 4930 @Test testDisableEphemeralNetwork()4931 public void testDisableEphemeralNetwork() throws Exception { 4932 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4933 List<WifiConfiguration> savedNetworks = null; 4934 try { 4935 uiAutomation.adoptShellPermissionIdentity(); 4936 // Temporarily disable on all networks. 4937 savedNetworks = sWifiManager.getConfiguredNetworks(); 4938 for (WifiConfiguration network : savedNetworks) { 4939 sWifiManager.disableEphemeralNetwork(network.SSID); 4940 } 4941 // trigger a disconnect and wait for disconnect. 4942 sWifiManager.disconnect(); 4943 waitForDisconnection(); 4944 4945 // Now trigger scan and ensure that the device does not connect to any networks. 4946 sWifiManager.startScan(); 4947 ensureNotConnected(); 4948 } finally { 4949 uiAutomation.dropShellPermissionIdentity(); 4950 setWifiEnabled(false); 4951 } 4952 } 4953 4954 /** 4955 * Tests {@link WifiManager#allowAutojoin(int, boolean)}. 4956 */ 4957 @Test testAllowAutojoin()4958 public void testAllowAutojoin() throws Exception { 4959 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 4960 List<WifiConfiguration> savedNetworks = null; 4961 try { 4962 uiAutomation.adoptShellPermissionIdentity(); 4963 // disable autojoin on all networks. 4964 savedNetworks = sWifiManager.getConfiguredNetworks(); 4965 for (WifiConfiguration network : savedNetworks) { 4966 sWifiManager.allowAutojoin(network.networkId, false); 4967 } 4968 // trigger a disconnect and wait for disconnect. 4969 sWifiManager.disconnect(); 4970 waitForDisconnection(); 4971 4972 // Now trigger scan and ensure that the device does not connect to any networks. 4973 sWifiManager.startScan(); 4974 ensureNotConnected(); 4975 4976 // Now enable autojoin on all networks. 4977 for (WifiConfiguration network : savedNetworks) { 4978 sWifiManager.allowAutojoin(network.networkId, true); 4979 } 4980 4981 // Trigger a scan & wait for connection to one of the saved networks. 4982 sWifiManager.startScan(); 4983 waitForConnection(); 4984 } finally { 4985 // Restore auto join state. 4986 if (savedNetworks != null) { 4987 for (WifiConfiguration network : savedNetworks) { 4988 sWifiManager.allowAutojoin(network.networkId, network.allowAutojoin); 4989 } 4990 } 4991 uiAutomation.dropShellPermissionIdentity(); 4992 } 4993 } 4994 4995 /** 4996 * Tests {@link WifiManager#allowAutojoinPasspoint(String, boolean)}. 4997 */ 4998 @Test testAllowAutojoinPasspoint()4999 public void testAllowAutojoinPasspoint() throws Exception { 5000 PasspointConfiguration passpointConfiguration = createPasspointConfiguration(); 5001 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5002 try { 5003 uiAutomation.adoptShellPermissionIdentity(); 5004 sWifiManager.addOrUpdatePasspointConfiguration(passpointConfiguration); 5005 // Turn off auto-join 5006 sWifiManager.allowAutojoinPasspoint( 5007 passpointConfiguration.getHomeSp().getFqdn(), false); 5008 // Turn on auto-join 5009 sWifiManager.allowAutojoinPasspoint( 5010 passpointConfiguration.getHomeSp().getFqdn(), true); 5011 } finally { 5012 sWifiManager.removePasspointConfiguration(passpointConfiguration.getHomeSp().getFqdn()); 5013 uiAutomation.dropShellPermissionIdentity(); 5014 } 5015 } 5016 5017 /** 5018 * Tests {@link WifiManager#allowAutojoinGlobal(boolean)}. 5019 */ 5020 @Test testAllowAutojoinGlobal()5021 public void testAllowAutojoinGlobal() throws Exception { 5022 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5023 try { 5024 uiAutomation.adoptShellPermissionIdentity(); 5025 // disable autojoin on all networks. 5026 sWifiManager.allowAutojoinGlobal(false); 5027 5028 // trigger a disconnect and wait for disconnect. 5029 sWifiManager.disconnect(); 5030 waitForDisconnection(); 5031 5032 // Now trigger scan and ensure that the device does not connect to any networks. 5033 sWifiManager.startScan(); 5034 ensureNotConnected(); 5035 5036 // verify null is returned when attempting to get current configured network. 5037 WifiConfiguration config = sWifiManager.getPrivilegedConnectedNetwork(); 5038 assertNull("config should be null because wifi is not connected", config); 5039 5040 // Now enable autojoin on all networks. 5041 sWifiManager.allowAutojoinGlobal(true); 5042 5043 // Trigger a scan & wait for connection to one of the saved networks. 5044 sWifiManager.startScan(); 5045 waitForConnection(); 5046 } finally { 5047 // Re-enable auto join if the test fails for some reason. 5048 sWifiManager.allowAutojoinGlobal(true); 5049 uiAutomation.dropShellPermissionIdentity(); 5050 } 5051 } 5052 5053 /** 5054 * Verify the invalid and valid usages of {@code WifiManager#queryAutojoinGlobal}. 5055 */ 5056 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5057 @Test testQueryAutojoinGlobal()5058 public void testQueryAutojoinGlobal() throws Exception { 5059 AtomicBoolean enabled = new AtomicBoolean(false); 5060 Consumer<Boolean> listener = new Consumer<Boolean>() { 5061 @Override 5062 public void accept(Boolean value) { 5063 synchronized (mLock) { 5064 enabled.set(value); 5065 mLock.notify(); 5066 } 5067 } 5068 }; 5069 // Test invalid inputs trigger IllegalArgumentException 5070 assertThrows("null executor should trigger exception", NullPointerException.class, 5071 () -> sWifiManager.queryAutojoinGlobal(null, listener)); 5072 assertThrows("null listener should trigger exception", NullPointerException.class, 5073 () -> sWifiManager.queryAutojoinGlobal(mExecutor, null)); 5074 5075 // Test caller with no permission triggers SecurityException. 5076 assertThrows("No permission should trigger SecurityException", SecurityException.class, 5077 () -> sWifiManager.queryAutojoinGlobal(mExecutor, listener)); 5078 5079 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5080 try { 5081 uiAutomation.adoptShellPermissionIdentity(); 5082 // Test get/set autojoin global enabled 5083 sWifiManager.allowAutojoinGlobal(true); 5084 sWifiManager.queryAutojoinGlobal(mExecutor, listener); 5085 synchronized (mLock) { 5086 mLock.wait(TEST_WAIT_DURATION_MS); 5087 } 5088 assertTrue(enabled.get()); 5089 5090 // Test get/set autojoin global disabled 5091 sWifiManager.allowAutojoinGlobal(false); 5092 sWifiManager.queryAutojoinGlobal(mExecutor, listener); 5093 synchronized (mLock) { 5094 mLock.wait(TEST_WAIT_DURATION_MS); 5095 } 5096 assertFalse(enabled.get()); 5097 } finally { 5098 // Re-enable auto join if the test fails for some reason. 5099 sWifiManager.allowAutojoinGlobal(true); 5100 uiAutomation.dropShellPermissionIdentity(); 5101 } 5102 } 5103 5104 /** 5105 * Tests {@link WifiManager#setPerSsidRoamingMode(WifiSsid, int)}, 5106 * {@link WifiManager#getPerSsidRoamingModes(Executor, Consumer)}, 5107 * and {@link WifiManager#removePerSsidRoamingMode(WifiSsid)}. 5108 */ 5109 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 5110 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, 5111 codeName = "VanillaIceCream") 5112 @Test testPerSsidRoamingMode()5113 public void testPerSsidRoamingMode() throws Exception { 5114 if (!sWifiManager.isAggressiveRoamingModeSupported()) { 5115 // skip the test if aggressive roaming mode is not supported 5116 return; 5117 } 5118 WifiSsid testSsid = WifiSsid.fromBytes("TEST_SSID_1".getBytes(StandardCharsets.UTF_8)); 5119 Map<String, Integer> roamingModes = new HashMap<>(); 5120 Consumer<Map<String, Integer>> listener = new Consumer<Map<String, Integer>>() { 5121 @Override 5122 public void accept(Map<String, Integer> value) { 5123 synchronized (mLock) { 5124 roamingModes.clear(); 5125 roamingModes.putAll(value); 5126 mLock.notify(); 5127 } 5128 } 5129 }; 5130 5131 // Test caller with no permission triggers SecurityException. 5132 assertThrows("No permission should trigger SecurityException", SecurityException.class, 5133 () -> sWifiManager.setPerSsidRoamingMode(testSsid, 5134 WifiManager.ROAMING_MODE_AGGRESSIVE)); 5135 assertThrows("No permission should trigger SecurityException", SecurityException.class, 5136 () -> sWifiManager.removePerSsidRoamingMode(testSsid)); 5137 assertThrows("No permission should trigger SecurityException", SecurityException.class, 5138 () -> sWifiManager.getPerSsidRoamingModes(mExecutor, listener)); 5139 5140 // Test that invalid inputs trigger an Exception. 5141 assertThrows("null WifiSsid should trigger exception", NullPointerException.class, 5142 () -> sWifiManager.setPerSsidRoamingMode(null, 5143 WifiManager.ROAMING_MODE_AGGRESSIVE)); 5144 assertThrows("null WifiSsid should trigger exception", NullPointerException.class, 5145 () -> sWifiManager.removePerSsidRoamingMode(null)); 5146 assertThrows("null executor should trigger exception", NullPointerException.class, 5147 () -> sWifiManager.getPerSsidRoamingModes(null, listener)); 5148 assertThrows("null listener should trigger exception", NullPointerException.class, 5149 () -> sWifiManager.getPerSsidRoamingModes(mExecutor, null)); 5150 5151 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5152 try { 5153 uiAutomation.adoptShellPermissionIdentity(); 5154 sWifiManager.setPerSsidRoamingMode(testSsid, WifiManager.ROAMING_MODE_AGGRESSIVE); 5155 sWifiManager.getPerSsidRoamingModes(mExecutor, listener); 5156 Thread.sleep(TEST_WAIT_DURATION_MS); 5157 assertTrue( 5158 roamingModes.get(testSsid.toString()) == WifiManager.ROAMING_MODE_AGGRESSIVE); 5159 sWifiManager.removePerSsidRoamingMode(testSsid); 5160 sWifiManager.getPerSsidRoamingModes(mExecutor, listener); 5161 Thread.sleep(TEST_WAIT_DURATION_MS); 5162 assertNull(roamingModes.get(testSsid.toString())); 5163 } finally { 5164 uiAutomation.dropShellPermissionIdentity(); 5165 } 5166 } 5167 5168 /** 5169 * Verify the invalid and valid usages of {@code WifiManager#setPnoScanState}. 5170 */ 5171 @Test 5172 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) testSetPnoScanState()5173 public void testSetPnoScanState() throws Exception { 5174 // Test caller with no permission triggers SecurityException. 5175 assertThrows("No permission should trigger SecurityException", SecurityException.class, 5176 () -> sWifiManager.setPnoScanState(WifiManager.PNO_SCAN_STATE_ENABLED)); 5177 5178 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5179 try { 5180 uiAutomation.adoptShellPermissionIdentity(); 5181 sWifiManager.setPnoScanState(WifiManager.PNO_SCAN_STATE_ENABLED); 5182 } finally { 5183 uiAutomation.dropShellPermissionIdentity(); 5184 } 5185 } 5186 5187 /** 5188 * Tests {@link WifiManager#isWapiSupported()} does not crash. 5189 */ 5190 @Test testIsWapiSupported()5191 public void testIsWapiSupported() throws Exception { 5192 sWifiManager.isWapiSupported(); 5193 } 5194 5195 /** 5196 * Tests {@link WifiManager#isWpa3SaePublicKeySupported()} does not crash. 5197 */ 5198 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5199 @Test testIsWpa3SaePublicKeySupported()5200 public void testIsWpa3SaePublicKeySupported() throws Exception { 5201 sWifiManager.isWpa3SaePublicKeySupported(); 5202 } 5203 5204 /** 5205 * Tests {@link WifiManager#isWpa3SaeH2eSupported()} does not crash. 5206 */ 5207 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5208 @Test testIsWpa3SaeH2eSupported()5209 public void testIsWpa3SaeH2eSupported() throws Exception { 5210 sWifiManager.isWpa3SaeH2eSupported(); 5211 } 5212 5213 /** 5214 * Tests {@link WifiManager#isWifiDisplayR2Supported()} does not crash. 5215 */ 5216 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5217 @Test testIsWifiDisplayR2Supported()5218 public void testIsWifiDisplayR2Supported() throws Exception { 5219 sWifiManager.isWifiDisplayR2Supported(); 5220 } 5221 5222 /** 5223 * Tests {@link WifiManager#isP2pSupported()} returns true 5224 * if this device supports it, otherwise, ensure no crash. 5225 */ 5226 @Test testIsP2pSupported()5227 public void testIsP2pSupported() throws Exception { 5228 if (WifiFeature.isP2pSupported(sContext)) { 5229 // if this device supports P2P, ensure hw capability is correct. 5230 assertTrue(sWifiManager.isP2pSupported()); 5231 } else { 5232 // ensure no crash. 5233 sWifiManager.isP2pSupported(); 5234 } 5235 5236 } 5237 5238 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5239 @Test testIsMultiStaConcurrencySupported()5240 public void testIsMultiStaConcurrencySupported() throws Exception { 5241 // ensure no crash. 5242 sWifiManager.isStaApConcurrencySupported(); 5243 } 5244 getTargetPasspointConfiguration( List<PasspointConfiguration> configurationList, String uniqueId)5245 private PasspointConfiguration getTargetPasspointConfiguration( 5246 List<PasspointConfiguration> configurationList, String uniqueId) { 5247 if (configurationList == null || configurationList.isEmpty()) { 5248 return null; 5249 } 5250 for (PasspointConfiguration config : configurationList) { 5251 if (TextUtils.equals(config.getUniqueId(), uniqueId)) { 5252 return config; 5253 } 5254 } 5255 return null; 5256 } 5257 5258 /** 5259 * Test that {@link WifiManager#is60GHzBandSupported()} throws UnsupportedOperationException 5260 * if the release is older than S. 5261 */ 5262 @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R) 5263 @Test testIs60GhzBandSupportedOnROrOlder()5264 public void testIs60GhzBandSupportedOnROrOlder() throws Exception { 5265 // check for 60ghz support with wifi enabled 5266 try { 5267 sWifiManager.is60GHzBandSupported(); 5268 fail("Expected UnsupportedOperationException"); 5269 } catch (UnsupportedOperationException ex) { 5270 } 5271 } 5272 5273 /** 5274 * Test that {@link WifiManager#is60GHzBandSupported()} returns successfully in 5275 * both Wifi enabled/disabled states for release newer than R. 5276 * Note that the response depends on device support and hence both true/false 5277 * are valid responses. 5278 */ 5279 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5280 @Test testIs60GhzBandSupportedOnSOrNewer()5281 public void testIs60GhzBandSupportedOnSOrNewer() throws Exception { 5282 // check for 60ghz support with wifi enabled 5283 boolean isSupportedWhenWifiEnabled = sWifiManager.is60GHzBandSupported(); 5284 5285 // Check for 60GHz support with wifi disabled 5286 setWifiEnabled(false); 5287 PollingCheck.check( 5288 "Wifi not disabled!", 5289 20000, 5290 () -> !sWifiManager.isWifiEnabled()); 5291 boolean isSupportedWhenWifiDisabled = sWifiManager.is60GHzBandSupported(); 5292 5293 // If Support is true when WiFi is disable, then it has to be true when it is enabled. 5294 // Note, the reverse is a valid case. 5295 if (isSupportedWhenWifiDisabled) { 5296 assertTrue(isSupportedWhenWifiEnabled); 5297 } 5298 } 5299 5300 /** 5301 * Tests {@link WifiManager#isTrustOnFirstUseSupported()} does not crash. 5302 */ 5303 // TODO(b/196180536): Wait for T SDK finalization before changing 5304 // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU)` 5305 @SdkSuppress(minSdkVersion = 31) 5306 @Test testIsTrustOnFirstUseSupported()5307 public void testIsTrustOnFirstUseSupported() throws Exception { 5308 sWifiManager.isTrustOnFirstUseSupported(); 5309 } 5310 5311 public class TestCoexCallback extends WifiManager.CoexCallback { 5312 private Object mCoexLock; 5313 private int mOnCoexUnsafeChannelChangedCount; 5314 private List<CoexUnsafeChannel> mCoexUnsafeChannels; 5315 private int mCoexRestrictions; 5316 TestCoexCallback(Object lock)5317 TestCoexCallback(Object lock) { 5318 mCoexLock = lock; 5319 } 5320 5321 @Override onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, int restrictions)5322 public void onCoexUnsafeChannelsChanged( 5323 @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) { 5324 synchronized (mCoexLock) { 5325 mCoexUnsafeChannels = unsafeChannels; 5326 mCoexRestrictions = restrictions; 5327 mOnCoexUnsafeChannelChangedCount++; 5328 mCoexLock.notify(); 5329 } 5330 } 5331 getOnCoexUnsafeChannelChangedCount()5332 public int getOnCoexUnsafeChannelChangedCount() { 5333 synchronized (mCoexLock) { 5334 return mOnCoexUnsafeChannelChangedCount; 5335 } 5336 } 5337 getCoexUnsafeChannels()5338 public List<CoexUnsafeChannel> getCoexUnsafeChannels() { 5339 return mCoexUnsafeChannels; 5340 } 5341 getCoexRestrictions()5342 public int getCoexRestrictions() { 5343 return mCoexRestrictions; 5344 } 5345 } 5346 5347 /** 5348 * Test that coex-related methods fail without the needed privileged permissions 5349 */ 5350 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5351 @Test testCoexMethodsShouldFailNoPermission()5352 public void testCoexMethodsShouldFailNoPermission() { 5353 try { 5354 sWifiManager.setCoexUnsafeChannels(Collections.emptyList(), 0); 5355 fail("setCoexUnsafeChannels should not succeed - privileged call"); 5356 } catch (SecurityException e) { 5357 // expected 5358 } 5359 final TestCoexCallback callback = new TestCoexCallback(mLock); 5360 try { 5361 sWifiManager.registerCoexCallback(mExecutor, callback); 5362 fail("registerCoexCallback should not succeed - privileged call"); 5363 } catch (SecurityException e) { 5364 // expected 5365 } 5366 try { 5367 sWifiManager.unregisterCoexCallback(callback); 5368 fail("unregisterCoexCallback should not succeed - privileged call"); 5369 } catch (SecurityException e) { 5370 // expected 5371 } 5372 } 5373 5374 /** 5375 * Test that coex-related methods succeed in setting the current unsafe channels and notifying 5376 * the listener. Since the default coex algorithm may be enabled, no-op is also valid behavior. 5377 */ 5378 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5379 @Test testListenOnCoexUnsafeChannels()5380 public void testListenOnCoexUnsafeChannels() { 5381 // These below API's only work with privileged permissions (obtained via shell identity 5382 // for test) 5383 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5384 List<CoexUnsafeChannel> prevUnsafeChannels = new ArrayList<>(); 5385 int prevRestrictions = -1; 5386 try { 5387 uiAutomation.adoptShellPermissionIdentity(); 5388 synchronized (mLock) { 5389 try { 5390 boolean defaultAlgoEnabled = false; 5391 final TestCoexCallback callback = new TestCoexCallback(mLock); 5392 sWifiManager.registerCoexCallback(mExecutor, callback); 5393 5394 // Callback should be called after registering 5395 mLock.wait(TEST_WAIT_DURATION_MS); 5396 assertEquals(1, callback.getOnCoexUnsafeChannelChangedCount()); 5397 5398 // Store the previous coex channels and try setting new coex channels 5 times. 5399 // 5400 // If the default algorithm is disabled, we'll get exactly 5 callbacks, and we 5401 // can verify that the update channels match what we inputted. 5402 // 5403 // If the default algorithm is enabled, then the callbacks will trigger 5404 // according to the algorithm, which may or may not trigger during the test. 5405 // Thus we try 5 times and see if the callbacks match the number of tries, since 5406 // it's highly unlikely that the default algorithm will update the channels 5407 // exactly 5 times during the test. 5408 prevUnsafeChannels = callback.getCoexUnsafeChannels(); 5409 prevRestrictions = callback.getCoexRestrictions(); 5410 List<CoexUnsafeChannel> testChannels = null; 5411 final int testRestrictions = COEX_RESTRICTION_WIFI_DIRECT 5412 | COEX_RESTRICTION_SOFTAP | COEX_RESTRICTION_WIFI_AWARE; 5413 for (int i = 0; i < 5; i++) { 5414 testChannels = List.of(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 1 + i)); 5415 sWifiManager.setCoexUnsafeChannels(testChannels, testRestrictions); 5416 mLock.wait(TEST_WAIT_DURATION_MS); 5417 if (callback.getOnCoexUnsafeChannelChangedCount() != i + 2) { 5418 defaultAlgoEnabled = true; 5419 break; 5420 } 5421 } 5422 5423 if (!defaultAlgoEnabled) { 5424 int currentCallbackCount = callback.getOnCoexUnsafeChannelChangedCount(); 5425 assertEquals(testChannels, callback.getCoexUnsafeChannels()); 5426 assertEquals(testRestrictions, callback.getCoexRestrictions()); 5427 // Unregister callback and try setting again 5428 sWifiManager.unregisterCoexCallback(callback); 5429 sWifiManager.setCoexUnsafeChannels( 5430 List.of(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 11)), 5431 testRestrictions); 5432 mLock.wait(TEST_WAIT_DURATION_MS); 5433 // Callback should not be called here since it was unregistered. 5434 assertThat(callback.getOnCoexUnsafeChannelChangedCount()) 5435 .isEqualTo(currentCallbackCount); 5436 } 5437 } catch (InterruptedException e) { 5438 fail("Thread interrupted unexpectedly while waiting on mLock"); 5439 } 5440 } 5441 } finally { 5442 // Reset the previous unsafe channels if we overrode them. 5443 if (prevRestrictions != -1) { 5444 sWifiManager.setCoexUnsafeChannels(prevUnsafeChannels, prevRestrictions); 5445 } 5446 uiAutomation.dropShellPermissionIdentity(); 5447 } 5448 } 5449 5450 /** 5451 * Verify that secure WPA-Enterprise network configurations can be added and updated. 5452 */ 5453 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5454 @Test testSecureEnterpriseConfigurationsAccepted()5455 public void testSecureEnterpriseConfigurationsAccepted() throws Exception { 5456 WifiConfiguration wifiConfiguration = new WifiConfiguration(); 5457 wifiConfiguration.SSID = SSID1; 5458 wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE); 5459 wifiConfiguration.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS); 5460 int networkId = INVALID_NETWORK_ID; 5461 5462 // These below API's only work with privileged permissions (obtained via shell identity 5463 // for test) 5464 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5465 try { 5466 uiAutomation.adoptShellPermissionIdentity(); 5467 5468 // Now configure it correctly with a Root CA cert and domain name 5469 wifiConfiguration.enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0); 5470 wifiConfiguration.enterpriseConfig.setAltSubjectMatch(TEST_DOM_SUBJECT_MATCH); 5471 5472 // Verify that the network is added 5473 networkId = sWifiManager.addNetwork(wifiConfiguration); 5474 assertNotEquals(INVALID_NETWORK_ID, networkId); 5475 5476 // Verify that the update API accepts configurations configured securely 5477 wifiConfiguration.networkId = networkId; 5478 assertEquals(networkId, sWifiManager.updateNetwork(wifiConfiguration)); 5479 } finally { 5480 if (networkId != INVALID_NETWORK_ID) { 5481 // Clean up the previously added network 5482 sWifiManager.removeNetwork(networkId); 5483 } 5484 uiAutomation.dropShellPermissionIdentity(); 5485 } 5486 } 5487 5488 /** 5489 * Tests {@link WifiManager#isPasspointTermsAndConditionsSupported)} does not crash. 5490 */ 5491 @Test testIsPasspointTermsAndConditionsSupported()5492 public void testIsPasspointTermsAndConditionsSupported() throws Exception { 5493 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 5494 // Skip the test if wifi module version is older than S. 5495 return; 5496 } 5497 sWifiManager.isPasspointTermsAndConditionsSupported(); 5498 } 5499 5500 /** 5501 * Test that call to {@link WifiManager#setOverrideCountryCode()}, 5502 * {@link WifiManager#clearOverrideCountryCode()} and 5503 * {@link WifiManager#setDefaultCountryCode()} need privileged permission 5504 * and the permission is not even given to shell user. 5505 */ 5506 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5507 @Test testManageCountryCodeMethodsFailWithoutPermissions()5508 public void testManageCountryCodeMethodsFailWithoutPermissions() throws Exception { 5509 ShellIdentityUtils.invokeWithShellPermissions(() -> { 5510 try { 5511 sWifiManager.setOverrideCountryCode(TEST_COUNTRY_CODE); 5512 fail("setOverrideCountryCode() expected to fail - privileged call"); 5513 } catch (SecurityException e) { 5514 // expected 5515 } 5516 5517 try { 5518 sWifiManager.clearOverrideCountryCode(); 5519 fail("clearOverrideCountryCode() expected to fail - privileged call"); 5520 } catch (SecurityException e) { 5521 // expected 5522 } 5523 5524 try { 5525 sWifiManager.setDefaultCountryCode(TEST_COUNTRY_CODE); 5526 fail("setDefaultCountryCode() expected to fail - privileged call"); 5527 } catch (SecurityException e) { 5528 // expected 5529 } 5530 }); 5531 } 5532 5533 /** 5534 * Tests {@link WifiManager#flushPasspointAnqpCache)} does not crash. 5535 */ 5536 @Test testFlushPasspointAnqpCache()5537 public void testFlushPasspointAnqpCache() throws Exception { 5538 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 5539 // Skip the test if wifi module version is older than S. 5540 return; 5541 } 5542 // The below API only works with privileged permissions (obtained via shell identity 5543 // for test) 5544 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5545 try { 5546 uiAutomation.adoptShellPermissionIdentity(); 5547 sWifiManager.flushPasspointAnqpCache(); 5548 } finally { 5549 uiAutomation.dropShellPermissionIdentity(); 5550 } 5551 } 5552 5553 /** 5554 * Tests {@link WifiManager#setWifiPasspointEnabled)} raise security exception without 5555 * permission. 5556 */ 5557 // TODO(b/139192273): Wait for T SDK finalization before changing 5558 // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)` 5559 @SdkSuppress(minSdkVersion = 31) 5560 @Test testEnablePasspointWithoutPermission()5561 public void testEnablePasspointWithoutPermission() throws Exception { 5562 try { 5563 sWifiManager.setWifiPasspointEnabled(true); 5564 fail("setWifiPasspointEnabled() expected to fail - privileged call"); 5565 } catch (SecurityException e) { 5566 // expected 5567 } 5568 } 5569 5570 /** 5571 * Tests {@link WifiManager#setWifiPasspointEnabled)} does not crash and returns success. 5572 */ 5573 // TODO(b/139192273): Wait for T SDK finalization before changing 5574 // to `@SdkSuppress(minSdkVersion = Build.VERSION_CODES.T)` 5575 @SdkSuppress(minSdkVersion = 31) 5576 @Test testEnablePasspoint()5577 public void testEnablePasspoint() throws Exception { 5578 // The below API only works with privileged permissions (obtained via shell identity 5579 // for test) 5580 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5581 try { 5582 uiAutomation.adoptShellPermissionIdentity(); 5583 // Check if passpoint is enabled by default. 5584 assertTrue(sWifiManager.isWifiPasspointEnabled()); 5585 // Try to disable passpoint 5586 sWifiManager.setWifiPasspointEnabled(false); 5587 PollingCheck.check("Wifi passpoint turn off failed!", 2_000, 5588 () -> !sWifiManager.isWifiPasspointEnabled()); 5589 // Try to enable passpoint 5590 sWifiManager.setWifiPasspointEnabled(true); 5591 PollingCheck.check("Wifi passpoint turn on failed!", 2_000, 5592 () -> sWifiManager.isWifiPasspointEnabled()); 5593 } finally { 5594 uiAutomation.dropShellPermissionIdentity(); 5595 } 5596 } 5597 5598 /** 5599 * Tests {@link WifiManager#isDecoratedIdentitySupported)} does not crash. 5600 */ 5601 @Test testIsDecoratedIdentitySupported()5602 public void testIsDecoratedIdentitySupported() throws Exception { 5603 if (!WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 5604 // Skip the test if wifi module version is older than S. 5605 return; 5606 } 5607 sWifiManager.isDecoratedIdentitySupported(); 5608 } 5609 5610 /** 5611 * Tests {@link WifiManager#setCarrierNetworkOffloadEnabled)} and 5612 * {@link WifiManager#isCarrierNetworkOffloadEnabled} work as expected. 5613 */ 5614 @Test testSetCarrierNetworkOffloadEnabled()5615 public void testSetCarrierNetworkOffloadEnabled() { 5616 if (!WifiFeature.isWifiSupported(sContext) 5617 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 5618 // skip the test if WiFi is not supported 5619 return; 5620 } 5621 assertTrue(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false)); 5622 // The below API only works with privileged permissions (obtained via shell identity 5623 // for test) 5624 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5625 try { 5626 uiAutomation.adoptShellPermissionIdentity(); 5627 sWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, false); 5628 assertFalse(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false)); 5629 } finally { 5630 sWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, false, true); 5631 uiAutomation.dropShellPermissionIdentity(); 5632 } 5633 assertTrue(sWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false)); 5634 } 5635 5636 /** 5637 * Test that {@link WifiManager#getUsableChannels(int, int)}, 5638 * {@link WifiManager#getAllowedChannels(int, int)} 5639 * throws UnsupportedOperationException if the release is older than S. 5640 */ 5641 @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.R) 5642 @Test testGetAllowedUsableChannelsOnROrOlder()5643 public void testGetAllowedUsableChannelsOnROrOlder() throws Exception { 5644 try { 5645 sWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA); 5646 fail("getAllowedChannels Expected to fail - UnsupportedOperationException"); 5647 } catch (UnsupportedOperationException ex) {} 5648 5649 try { 5650 sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA); 5651 fail("getUsableChannels Expected to fail - UnsupportedOperationException"); 5652 } catch (UnsupportedOperationException ex) {} 5653 } 5654 5655 /** 5656 * Tests {@link WifiManager#getAllowedChannels(int, int))} does not crash 5657 */ 5658 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5659 @Test testGetAllowedChannels()5660 public void testGetAllowedChannels() throws Exception { 5661 // The below API only works with privileged permissions (obtained via shell identity 5662 // for test) 5663 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5664 try { 5665 WifiAvailableChannel channel = new WifiAvailableChannel(2412, OP_MODE_SAP); 5666 assertEquals(channel.getFrequencyMhz(), 2412); 5667 assertEquals(channel.getOperationalModes(), OP_MODE_SAP); 5668 final List<Integer> valid24GhzFreqs = Arrays.asList( 5669 2412, 2417, 2422, 2427, 2432, 2437, 2442, 5670 2447, 2452, 2457, 2462, 2467, 2472, 2484); 5671 Set<Integer> supported24GhzFreqs = new HashSet<Integer>(); 5672 uiAutomation.adoptShellPermissionIdentity(); 5673 List<WifiAvailableChannel> allowedChannels = 5674 sWifiManager.getAllowedChannels(WIFI_BAND_24_GHZ, OP_MODE_STA); 5675 assertNotNull(allowedChannels); 5676 for (WifiAvailableChannel ch : allowedChannels) { 5677 //Must contain a valid 2.4GHz frequency 5678 assertTrue(valid24GhzFreqs.contains(ch.getFrequencyMhz())); 5679 if(ch.getFrequencyMhz() <= 2462) { 5680 //Channels 1-11 are supported for STA in all countries 5681 assertEquals(ch.getOperationalModes() & OP_MODE_STA, OP_MODE_STA); 5682 supported24GhzFreqs.add(ch.getFrequencyMhz()); 5683 } 5684 } 5685 //Channels 1-11 are supported for STA in all countries 5686 assertEquals(supported24GhzFreqs.size(), 11); 5687 } catch (UnsupportedOperationException ex) { 5688 //expected if the device does not support this API 5689 } catch (Exception ex) { 5690 fail("getAllowedChannels unexpected Exception " + ex); 5691 } finally { 5692 uiAutomation.dropShellPermissionIdentity(); 5693 } 5694 } 5695 5696 /** 5697 * Tests {@link WifiAvailableChannel#getChannelWidth()}. 5698 */ 5699 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5700 @RequiresFlagsEnabled(Flags.FLAG_GET_CHANNEL_WIDTH_API) 5701 @ApiTest(apis = {"android.net.wifi.WifiAvailableChannel#getChannelWidth"}) 5702 @Test testGetAllowedChannelsWidth()5703 public void testGetAllowedChannelsWidth() throws Exception { 5704 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5705 try { 5706 final List<Integer> valid24GhzFreqs = Arrays.asList(2412, 2417, 2422, 2427, 2432, 2437, 5707 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484); 5708 uiAutomation.adoptShellPermissionIdentity(); 5709 List<WifiAvailableChannel> allowedChannels = sWifiManager.getAllowedChannels( 5710 WIFI_BAND_24_GHZ, OP_MODE_STA); 5711 assertNotNull(allowedChannels); 5712 for (WifiAvailableChannel ch : allowedChannels) { 5713 //Must contain a valid 2.4GHz frequency 5714 assertTrue(valid24GhzFreqs.contains(ch.getFrequencyMhz())); 5715 if (ch.getFrequencyMhz() <= 2462) { 5716 //Channels 1-11 are supported for STA in all countries 5717 assertEquals(ch.getOperationalModes() & OP_MODE_STA, OP_MODE_STA); 5718 assertEquals(ch.getChannelWidth(), ScanResult.CHANNEL_WIDTH_20MHZ); 5719 } 5720 } 5721 } catch (UnsupportedOperationException ex) { 5722 //expected if the device does not support this API 5723 } catch (Exception ex) { 5724 fail("getAllowedChannels unexpected Exception " + ex); 5725 } finally { 5726 uiAutomation.dropShellPermissionIdentity(); 5727 } 5728 } 5729 5730 /** 5731 * Tests {@link WifiManager#getUsableChannels(int, int))} does not crash 5732 * and returns at least one 2G channel in STA and WFD GO modes (if WFD is supported) 5733 */ 5734 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) 5735 @Test testGetUsableChannelsStaWfdMode()5736 public void testGetUsableChannelsStaWfdMode() throws Exception { 5737 // The below API only works with privileged permissions (obtained via shell identity 5738 // for test) 5739 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5740 try { 5741 uiAutomation.adoptShellPermissionIdentity(); 5742 List<WifiAvailableChannel> usableStaChannels = 5743 sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_STA); 5744 //There must be at least one usable STA channel in 2.4GHz band 5745 assertFalse(usableStaChannels.isEmpty()); 5746 if (sWifiManager.isP2pSupported()) { 5747 List<WifiAvailableChannel> usableGoChannels = 5748 sWifiManager.getUsableChannels(WIFI_BAND_24_GHZ, OP_MODE_WIFI_DIRECT_GO); 5749 //There must be at least one usable P2P channel in 2.4GHz band 5750 assertFalse(usableGoChannels.isEmpty()); 5751 } 5752 5753 } catch (UnsupportedOperationException ex) { 5754 //expected if the device does not support this API 5755 } catch (Exception ex) { 5756 fail("getUsableChannels unexpected Exception " + ex); 5757 } finally { 5758 uiAutomation.dropShellPermissionIdentity(); 5759 } 5760 } 5761 5762 /** 5763 * Tests {@link WifiManager#getChannelData(Executor, Consumer<List<Bundle>>)} 5764 * does not crash. 5765 */ 5766 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5767 @Test testGetChannelData()5768 public void testGetChannelData() throws Exception { 5769 List<Bundle> dataList = new ArrayList<>(); 5770 Consumer<List<Bundle>> listener = new Consumer<List<Bundle>>() { 5771 @Override 5772 public void accept(List<Bundle> value) { 5773 synchronized (mLock) { 5774 dataList.addAll(value); 5775 mLock.notify(); 5776 } 5777 } 5778 }; 5779 // Test invalid inputs trigger IllegalArgumentException 5780 assertThrows("null executor should trigger exception", NullPointerException.class, 5781 () -> sWifiManager.getChannelData(null, listener)); 5782 assertThrows("null listener should trigger exception", NullPointerException.class, 5783 () -> sWifiManager.getChannelData(mExecutor, null)); 5784 5785 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5786 try { 5787 uiAutomation.adoptShellPermissionIdentity(); 5788 // Start scan and wait for scan results 5789 startScan(); 5790 sWifiManager.getChannelData(mExecutor, listener); 5791 synchronized (mLock) { 5792 mLock.wait(TEST_WAIT_DURATION_MS); 5793 } 5794 if (sWifiManager.isScanAlwaysAvailable() && isScanCurrentlyAvailable()) { 5795 assertFalse(dataList.isEmpty()); 5796 } 5797 } catch (UnsupportedOperationException ex) { 5798 //expected if the device does not support this API 5799 } catch (Exception ex) { 5800 fail("getChannelData unexpected Exception " + ex); 5801 } finally { 5802 uiAutomation.dropShellPermissionIdentity(); 5803 } 5804 } 5805 5806 /** 5807 * Validate that the Passpoint feature is enabled on the device. 5808 */ 5809 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5810 @Test testPasspointCapability()5811 public void testPasspointCapability() { 5812 if (PropertyUtil.getVsrApiLevel() < Build.VERSION_CODES.S) { 5813 return; 5814 } 5815 PackageManager packageManager = sContext.getPackageManager(); 5816 assertTrue("Passpoint must be supported", 5817 packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)); 5818 } 5819 5820 /** 5821 * Validate add and remove SuggestionUserApprovalStatusListener. And verify the listener's 5822 * stickiness. 5823 */ 5824 @Test testAddRemoveSuggestionUserApprovalStatusListener()5825 public void testAddRemoveSuggestionUserApprovalStatusListener() throws Exception { 5826 if (!WifiFeature.isWifiSupported(sContext) 5827 || !WifiBuildCompat.isPlatformOrWifiModuleAtLeastS(sContext)) { 5828 return; 5829 } 5830 CountDownLatch countDownLatch = new CountDownLatch(1); 5831 TestUserApprovalStatusListener listener = new TestUserApprovalStatusListener( 5832 countDownLatch); 5833 try { 5834 sWifiManager.addSuggestionUserApprovalStatusListener(mExecutor, listener); 5835 assertTrue(countDownLatch.await(TEST_WAIT_DURATION_MS, TimeUnit.MILLISECONDS)); 5836 } finally { 5837 sWifiManager.removeSuggestionUserApprovalStatusListener(listener); 5838 } 5839 } 5840 5841 private static class TestUserApprovalStatusListener implements 5842 WifiManager.SuggestionUserApprovalStatusListener { 5843 private final CountDownLatch mBlocker; 5844 TestUserApprovalStatusListener(CountDownLatch countDownLatch)5845 public TestUserApprovalStatusListener(CountDownLatch countDownLatch) { 5846 mBlocker = countDownLatch; 5847 } 5848 @Override onUserApprovalStatusChange(int status)5849 public void onUserApprovalStatusChange(int status) { 5850 mBlocker.countDown(); 5851 } 5852 } 5853 5854 /** 5855 * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception 5856 * without permission. 5857 */ 5858 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5859 @Test testIsStaConcurrencyForMultiInternetSupported()5860 public void testIsStaConcurrencyForMultiInternetSupported() throws Exception { 5861 // ensure no crash. 5862 sWifiManager.isStaConcurrencyForMultiInternetSupported(); 5863 } 5864 5865 /** 5866 * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} raise security exception 5867 * without permission. 5868 */ 5869 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5870 @Test testSetStaConcurrencyForMultiInternetModeWithoutPermission()5871 public void testSetStaConcurrencyForMultiInternetModeWithoutPermission() throws Exception { 5872 if (!WifiFeature.isWifiSupported(sContext) 5873 || !sWifiManager.isStaConcurrencyForMultiInternetSupported()) { 5874 // skip the test if WiFi is not supported or multi internet feature not supported. 5875 return; 5876 } 5877 try { 5878 sWifiManager.setStaConcurrencyForMultiInternetMode( 5879 WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED); 5880 fail("setWifiPasspointEnabled() expected to fail - privileged call"); 5881 } catch (SecurityException e) { 5882 // expected 5883 } 5884 } 5885 5886 /** 5887 * Tests {@link WifiManager#setStaConcurrencyForMultiInternetMode)} does not crash. 5888 */ 5889 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 5890 @Test testSetStaConcurrencyForMultiInternetMode()5891 public void testSetStaConcurrencyForMultiInternetMode() throws Exception { 5892 if (!WifiFeature.isWifiSupported(sContext) 5893 || !sWifiManager.isStaConcurrencyForMultiInternetSupported()) { 5894 // skip the test if WiFi is not supported or multi internet feature not supported. 5895 return; 5896 } 5897 5898 // The below API only works with privileged permissions (obtained via shell identity 5899 // for test) 5900 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 5901 try { 5902 uiAutomation.adoptShellPermissionIdentity(); 5903 // Try to disable multi internet 5904 sWifiManager.setStaConcurrencyForMultiInternetMode( 5905 WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED); 5906 PollingCheck.check( 5907 "Wifi multi internet disable failed!", 2_000, 5908 () -> sWifiManager.getStaConcurrencyForMultiInternetMode() 5909 == WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED); 5910 // Try to enable multi internet 5911 sWifiManager.setStaConcurrencyForMultiInternetMode( 5912 WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP); 5913 PollingCheck.check( 5914 "Wifi multi internet turn on failed!", 2_000, 5915 () -> sWifiManager.getStaConcurrencyForMultiInternetMode() 5916 == WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP); 5917 } finally { 5918 uiAutomation.dropShellPermissionIdentity(); 5919 } 5920 } 5921 5922 static class TestWifiNetworkStateChangeListener implements 5923 WifiManager.WifiNetworkStateChangedListener { 5924 final int mCmmRole; 5925 private List<Integer> mStateList = new ArrayList<>(); 5926 TestWifiNetworkStateChangeListener(int cmmRole)5927 TestWifiNetworkStateChangeListener(int cmmRole) { 5928 mCmmRole = cmmRole; 5929 } 5930 5931 @Override onWifiNetworkStateChanged(int cmmRole, int state)5932 public void onWifiNetworkStateChanged(int cmmRole, int state) { 5933 if (cmmRole != mCmmRole) { 5934 return; 5935 } 5936 if (mStateList.contains(state)) { 5937 // ignore duplicate state transitions 5938 return; 5939 } 5940 mStateList.add(state); 5941 } 5942 getStateList()5943 public List<Integer> getStateList() { 5944 return mStateList; 5945 } 5946 clear()5947 public void clear() { 5948 mStateList.clear(); 5949 } 5950 } 5951 5952 @Test testWifiNetworkStateChangeListener()5953 public void testWifiNetworkStateChangeListener() throws Exception { 5954 TestWifiNetworkStateChangeListener testListener = new TestWifiNetworkStateChangeListener( 5955 WifiManager.WifiNetworkStateChangedListener.WIFI_ROLE_CLIENT_PRIMARY); 5956 // Verify permission check 5957 assertThrows(SecurityException.class, 5958 () -> sWifiManager.addWifiNetworkStateChangedListener(mExecutor, testListener)); 5959 5960 // Disable wifi 5961 setWifiEnabled(false); 5962 waitForDisconnection(); 5963 5964 try { 5965 // Register listener then enable wifi 5966 ShellIdentityUtils.invokeWithShellPermissions( 5967 () -> sWifiManager.addWifiNetworkStateChangedListener(mExecutor, testListener)); 5968 setWifiEnabled(true); 5969 5970 // Trigger a scan & wait for connection to one of the saved networks. 5971 sWifiManager.startScan(); 5972 waitForConnection(); 5973 5974 PollingCheck.check( 5975 "Wifi network state change listener did not receive connected!", 1_000, 5976 () -> testListener.getStateList().contains( 5977 WifiManager.WifiNetworkStateChangedListener 5978 .WIFI_NETWORK_STATUS_CONNECTED)); 5979 int firstState = testListener.getStateList().get(0); 5980 int lastState = testListener.getStateList().get(testListener.getStateList().size() - 1); 5981 assertEquals(WifiManager.WifiNetworkStateChangedListener 5982 .WIFI_NETWORK_STATUS_CONNECTING, firstState); 5983 assertEquals(WifiManager.WifiNetworkStateChangedListener 5984 .WIFI_NETWORK_STATUS_CONNECTED, lastState); 5985 5986 // Disable wifi and verify disconnect is reported. 5987 testListener.clear(); 5988 setWifiEnabled(false); 5989 waitForDisconnection(); 5990 PollingCheck.check( 5991 "Wifi network state change listener did not receive disconnected!", 1_000, 5992 () -> testListener.getStateList().contains( 5993 WifiManager.WifiNetworkStateChangedListener 5994 .WIFI_NETWORK_STATUS_DISCONNECTED)); 5995 } finally { 5996 sWifiManager.removeWifiNetworkStateChangedListener(testListener); 5997 } 5998 } 5999 6000 /** 6001 * Tests {@link WifiConfiguration#setBssidAllowlist(List)}. 6002 */ 6003 @Test testBssidAllowlist()6004 public void testBssidAllowlist() throws Exception { 6005 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6006 List<WifiConfiguration> savedNetworks = null; 6007 try { 6008 uiAutomation.adoptShellPermissionIdentity(); 6009 6010 WifiInfo wifiInfo = sWifiManager.getConnectionInfo(); 6011 String connectedBssid = wifiInfo.getBSSID(); 6012 int networkId = wifiInfo.getNetworkId(); 6013 6014 // Set empty BSSID allow list to block all APs 6015 savedNetworks = sWifiManager.getConfiguredNetworks(); 6016 for (WifiConfiguration network : savedNetworks) { 6017 network.setBssidAllowlist(Collections.emptyList()); 6018 sWifiManager.updateNetwork(network); 6019 } 6020 6021 // Disable and re-enable Wifi to avoid reconnect to the secondary candidate 6022 sWifiManager.setWifiEnabled(false); 6023 waitForDisconnection(); 6024 sWifiManager.setWifiEnabled(true); 6025 // Now trigger scan and ensure that the device does not connect to any networks. 6026 sWifiManager.startScan(); 6027 ensureNotConnected(); 6028 6029 // Set the previous connected BSSID on that network. Other network set with a fake 6030 // (not visible) BSSID only 6031 for (WifiConfiguration network : savedNetworks) { 6032 if (network.networkId == networkId) { 6033 network.setBssidAllowlist(List.of(MacAddress.fromString(connectedBssid))); 6034 sWifiManager.updateNetwork(network); 6035 } else { 6036 network.setBssidAllowlist(List.of(MacAddress.fromString(TEST_BSSID))); 6037 sWifiManager.updateNetwork(network); 6038 } 6039 } 6040 6041 // Trigger a scan & wait for connection to one of the saved networks. 6042 sWifiManager.startScan(); 6043 waitForConnection(); 6044 wifiInfo = sWifiManager.getConnectionInfo(); 6045 assertEquals(networkId, wifiInfo.getNetworkId()); 6046 } finally { 6047 // Reset BSSID allow list to accept all APs 6048 for (WifiConfiguration network : savedNetworks) { 6049 assertNotNull(network.getBssidAllowlist()); 6050 network.setBssidAllowlist(null); 6051 sWifiManager.updateNetwork(network); 6052 } 6053 uiAutomation.dropShellPermissionIdentity(); 6054 } 6055 } 6056 6057 /** 6058 * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)} 6059 * raise security exception without permission. 6060 */ 6061 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6062 @Test testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission()6063 public void testNotifyMinimumRequiredWifiSecurityLevelChangedWithoutPermission() 6064 throws Exception { 6065 if (!WifiFeature.isWifiSupported(sContext)) { 6066 // skip the test if WiFi is not supported. 6067 return; 6068 } 6069 assertThrows(SecurityException.class, 6070 () -> sWifiManager.notifyMinimumRequiredWifiSecurityLevelChanged( 6071 DevicePolicyManager.WIFI_SECURITY_PERSONAL)); 6072 } 6073 6074 /** 6075 * Tests {@link WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)} 6076 * raise security exception without permission. 6077 */ 6078 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6079 @Test testNotifyWifiSsidPolicyChangedWithoutPermission()6080 public void testNotifyWifiSsidPolicyChangedWithoutPermission() throws Exception { 6081 if (!WifiFeature.isWifiSupported(sContext)) { 6082 // skip the test if WiFi is not supported. 6083 return; 6084 } 6085 WifiSsidPolicy policy = new WifiSsidPolicy( 6086 WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, new ArraySet<>(Arrays.asList( 6087 WifiSsid.fromBytes("ssid".getBytes(StandardCharsets.UTF_8))))); 6088 try { 6089 sWifiManager.notifyWifiSsidPolicyChanged(policy); 6090 fail("Expected security exception due to lack of permission"); 6091 } catch (SecurityException e) { 6092 // expected 6093 } 6094 } 6095 6096 /** 6097 * Verifies that 6098 * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} raises 6099 * a security exception without permission. 6100 */ 6101 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6102 @Test testIsItPossibleToCreateInterfaceNotAllowed()6103 public void testIsItPossibleToCreateInterfaceNotAllowed() throws Exception { 6104 assertThrows(SecurityException.class, () -> sWifiManager.reportCreateInterfaceImpact( 6105 WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor, 6106 (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> { 6107 // should not get here (security exception!) 6108 })); 6109 } 6110 6111 /** 6112 * Verifies 6113 * {@link WifiManager#reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)} . 6114 */ 6115 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6116 @Test testIsItPossibleToCreateInterface()6117 public void testIsItPossibleToCreateInterface() throws Exception { 6118 AtomicBoolean called = new AtomicBoolean(false); 6119 AtomicBoolean canBeCreated = new AtomicBoolean(false); 6120 AtomicReference<Set<WifiManager.InterfaceCreationImpact>> 6121 interfacesWhichWillBeDeleted = new AtomicReference<>(null); 6122 ShellIdentityUtils.invokeWithShellPermissions( 6123 () -> sWifiManager.reportCreateInterfaceImpact( 6124 WifiManager.WIFI_INTERFACE_TYPE_AP, false, mExecutor, 6125 (canBeCreatedLocal, interfacesWhichWillBeDeletedLocal) -> { 6126 synchronized (mLock) { 6127 canBeCreated.set(canBeCreatedLocal); 6128 called.set(true); 6129 interfacesWhichWillBeDeleted.set(interfacesWhichWillBeDeletedLocal); 6130 mLock.notify(); 6131 } 6132 })); 6133 synchronized (mLock) { 6134 mLock.wait(TEST_WAIT_DURATION_MS); 6135 } 6136 assertTrue(called.get()); 6137 if (canBeCreated.get()) { 6138 for (WifiManager.InterfaceCreationImpact entry : interfacesWhichWillBeDeleted.get()) { 6139 int interfaceType = entry.getInterfaceType(); 6140 assertTrue(interfaceType == WifiManager.WIFI_INTERFACE_TYPE_STA 6141 || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AP 6142 || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_DIRECT 6143 || interfaceType == WifiManager.WIFI_INTERFACE_TYPE_AWARE); 6144 Set<String> packages = entry.getPackages(); 6145 for (String p : packages) { 6146 assertNotNull(p); 6147 } 6148 } 6149 } 6150 6151 // verify the WifiManager.InterfaceCreationImpact APIs 6152 int interfaceType = WifiManager.WIFI_INTERFACE_TYPE_STA; 6153 Set<String> packages = Set.of("package1", "packages2"); 6154 WifiManager.InterfaceCreationImpact element = new WifiManager.InterfaceCreationImpact( 6155 interfaceType, packages); 6156 assertEquals(interfaceType, element.getInterfaceType()); 6157 assertEquals(packages, element.getPackages()); 6158 } 6159 6160 /** 6161 * Tests {@link WifiManager#isEasyConnectDppAkmSupported)} does not crash. 6162 */ 6163 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6164 @Test testIsEasyConnectDppAkmSupported()6165 public void testIsEasyConnectDppAkmSupported() throws Exception { 6166 sWifiManager.isEasyConnectDppAkmSupported(); 6167 } 6168 6169 /** 6170 * Tests {@link WifiManager#getMaxNumberOfChannelsPerNetworkSpecifierRequest)} works 6171 */ 6172 @Test testGetMaxNumberOfChannelsPerNetworkSpecifierRequest()6173 public void testGetMaxNumberOfChannelsPerNetworkSpecifierRequest() { 6174 assertTrue(sWifiManager.getMaxNumberOfChannelsPerNetworkSpecifierRequest() > 0); 6175 } 6176 6177 /** 6178 * Tests {@link WifiManager#isTlsV13Supported)} does not crash. 6179 */ 6180 @Test testIsTlsV13Supported()6181 public void testIsTlsV13Supported() throws Exception { 6182 sWifiManager.isTlsV13Supported(); 6183 } 6184 6185 /** 6186 * Tests {@link WifiManager#isTlsMinimumVersionSupported)} does not crash. 6187 */ 6188 @Test testIsTlsMinimumVersionSupported()6189 public void testIsTlsMinimumVersionSupported() throws Exception { 6190 sWifiManager.isTlsMinimumVersionSupported(); 6191 } 6192 fillQosPolicyParamsList(List<QosPolicyParams> policyParamsList, int size, boolean uniqueIds)6193 private void fillQosPolicyParamsList(List<QosPolicyParams> policyParamsList, 6194 int size, boolean uniqueIds) { 6195 policyParamsList.clear(); 6196 for (int i = 0; i < size; i++) { 6197 int policyId = uniqueIds ? i + 2 : 5; 6198 policyParamsList.add(new QosPolicyParams.Builder( 6199 policyId, QosPolicyParams.DIRECTION_DOWNLINK) 6200 .setUserPriority(QosPolicyParams.USER_PRIORITY_VIDEO_LOW) 6201 .setIpVersion(QosPolicyParams.IP_VERSION_4) 6202 .build()); 6203 } 6204 } 6205 6206 /** 6207 * Check whether the application QoS feature is enabled. 6208 * 6209 * The feature is enabled if the overlay is true, the experiment feature flag 6210 * is true, and the supplicant service implements V2 of the AIDL interface. 6211 */ applicationQosFeatureEnabled()6212 private boolean applicationQosFeatureEnabled() { 6213 boolean overlayEnabled; 6214 try { 6215 WifiResourceUtil resourceUtil = new WifiResourceUtil(sContext); 6216 overlayEnabled = resourceUtil 6217 .getWifiBoolean("config_wifiApplicationCentricQosPolicyFeatureEnabled"); 6218 } catch (Exception e) { 6219 Log.i(TAG, "Unable to retrieve the QoS overlay value"); 6220 return false; 6221 } 6222 6223 // Supplicant V2 is supported if the vendor partition indicates API > T. 6224 boolean halSupport = PropertyUtil.isVndkApiLevelNewerThan(Build.VERSION_CODES.TIRAMISU); 6225 boolean featureFlagEnabled = DeviceConfig.getBoolean(DEVICE_CONFIG_NAMESPACE, 6226 "application_qos_policy_api_enabled", true); 6227 6228 return overlayEnabled && featureFlagEnabled && halSupport; 6229 } 6230 6231 /** 6232 * Tests that {@link WifiManager#addQosPolicies(List, Executor, Consumer)}, 6233 * {@link WifiManager#removeQosPolicies(int[])}, and 6234 * {@link WifiManager#removeAllQosPolicies()} do not crash. 6235 */ 6236 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6237 @Test testAddAndRemoveQosPolicies()6238 public void testAddAndRemoveQosPolicies() throws Exception { 6239 final Mutable<Boolean> callbackReceived = new Mutable<Boolean>(false); 6240 final Mutable<Boolean> policiesRejected = new Mutable<Boolean>(true); 6241 Consumer<List<Integer>> listener = new Consumer<List<Integer>>() { 6242 @Override 6243 public void accept(List value) { 6244 synchronized (mLock) { 6245 callbackReceived.value = true; 6246 List<Integer> statusList = value; 6247 for (Integer status : statusList) { 6248 if (status != WifiManager.QOS_REQUEST_STATUS_FAILURE_UNKNOWN) { 6249 policiesRejected.value = false; 6250 break; 6251 } 6252 } 6253 Log.i(TAG, "Callback received for QoS add request, size=" + statusList.size() 6254 + ", rejected=" + policiesRejected.value); 6255 mLock.notify(); 6256 } 6257 } 6258 }; 6259 6260 // Test that invalid inputs trigger an Exception. 6261 final List<QosPolicyParams> policyParamsList = new ArrayList<>(); 6262 assertThrows("null executor should trigger exception", NullPointerException.class, 6263 () -> sWifiManager.addQosPolicies(policyParamsList, null, listener)); 6264 assertThrows("null listener should trigger exception", NullPointerException.class, 6265 () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, null)); 6266 assertThrows("null policy list should trigger exception", NullPointerException.class, 6267 () -> sWifiManager.addQosPolicies(null, mExecutor, listener)); 6268 6269 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6270 try { 6271 uiAutomation.adoptShellPermissionIdentity(); 6272 boolean enabled = applicationQosFeatureEnabled(); 6273 6274 // If the feature is disabled, verify that all policies are rejected. 6275 if (!enabled) { 6276 Log.i(TAG, "QoS policy APIs are not enabled"); 6277 fillQosPolicyParamsList(policyParamsList, 4, true); 6278 sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener); 6279 synchronized (mLock) { 6280 mLock.wait(TEST_WAIT_DURATION_MS); 6281 } 6282 assertTrue(callbackReceived.value); 6283 assertTrue(policiesRejected.value); 6284 return; 6285 } 6286 6287 // Empty params list 6288 assertThrows("empty list should trigger exception", IllegalArgumentException.class, 6289 () -> sWifiManager.addQosPolicies(new ArrayList<>(), mExecutor, listener)); 6290 6291 // More than {@link WifiManager#getMaxNumberOfPoliciesPerQosRequest()} 6292 // policies in the list 6293 fillQosPolicyParamsList(policyParamsList, 6294 sWifiManager.getMaxNumberOfPoliciesPerQosRequest() + 1, true); 6295 assertThrows("large list should trigger exception", IllegalArgumentException.class, 6296 () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener)); 6297 6298 // Params list contains duplicate policy ids 6299 fillQosPolicyParamsList(policyParamsList, 4, false); 6300 assertThrows("duplicate ids should trigger exception", IllegalArgumentException.class, 6301 () -> sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener)); 6302 6303 // Valid list 6304 fillQosPolicyParamsList(policyParamsList, 4, true); 6305 sWifiManager.addQosPolicies(policyParamsList, mExecutor, listener); 6306 6307 // sleep to wait for a response from supplicant 6308 synchronized (mLock) { 6309 mLock.wait(TEST_WAIT_DURATION_MS); 6310 } 6311 6312 int[] policyIds = new int[policyParamsList.size()]; 6313 for (int i = 0; i < policyParamsList.size(); i++) { 6314 policyIds[i] = policyParamsList.get(i).getPolicyId(); 6315 } 6316 sWifiManager.removeQosPolicies(policyIds); 6317 6318 // sleep to wait for a response from supplicant 6319 synchronized (mLock) { 6320 mLock.wait(TEST_WAIT_DURATION_MS); 6321 } 6322 sWifiManager.removeAllQosPolicies(); 6323 } catch (Exception e) { 6324 fail("addAndRemoveQosPolicy unexpected Exception " + e); 6325 } finally { 6326 uiAutomation.dropShellPermissionIdentity(); 6327 } 6328 } 6329 qosR3Supported()6330 private boolean qosR3Supported() { 6331 return SdkLevel.isAtLeastV() && Flags.androidVWifiApi(); 6332 } 6333 6334 /** 6335 * Tests the builder and get methods for {@link QosPolicyParams}. 6336 */ 6337 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6338 @Test testQosPolicyParamsBuilder()6339 public void testQosPolicyParamsBuilder() throws Exception { 6340 final int policyId = 5; 6341 final int direction = QosPolicyParams.DIRECTION_DOWNLINK; 6342 final int ipVersion = QosPolicyParams.IP_VERSION_6; 6343 final int dscp = 12; 6344 final int userPriority = QosPolicyParams.USER_PRIORITY_VIDEO_LOW; 6345 final String ipv6Address = "2001:db8:3333:4444:5555:6666:7777:8888"; 6346 final InetAddress srcAddr = InetAddress.getByName(ipv6Address); 6347 final InetAddress dstAddr = InetAddress.getByName(ipv6Address); 6348 final int srcPort = 123; 6349 final int protocol = QosPolicyParams.PROTOCOL_TCP; 6350 final int dstPort = 17; 6351 final int[] dstPortRange = new int[]{15, 22}; 6352 final byte[] flowLabel = new byte[]{17, 18, 19}; 6353 6354 int minServiceIntervalMicros = 2000; 6355 int maxServiceIntervalMicros = 5000; 6356 int minDataRateKbps = 500; 6357 int delayBoundMicros = 200; 6358 QosCharacteristics qosCharacteristics = new QosCharacteristics.Builder( 6359 minServiceIntervalMicros, maxServiceIntervalMicros, 6360 minDataRateKbps, delayBoundMicros).build(); 6361 6362 // Invalid parameter 6363 assertThrows("Invalid dscp should trigger an exception", IllegalArgumentException.class, 6364 () -> new QosPolicyParams.Builder(policyId, direction) 6365 .setDscp(70) 6366 .build()); 6367 6368 // Valid downlink parameters 6369 QosPolicyParams.Builder builder = 6370 new QosPolicyParams.Builder(policyId, QosPolicyParams.DIRECTION_DOWNLINK) 6371 .setSourceAddress(srcAddr) 6372 .setDestinationAddress(dstAddr) 6373 .setUserPriority(userPriority) 6374 .setIpVersion(ipVersion) 6375 .setSourcePort(srcPort) 6376 .setProtocol(protocol) 6377 .setDestinationPort(dstPort) 6378 .setFlowLabel(flowLabel); 6379 if (qosR3Supported()) { 6380 // Optional field for downlink policies 6381 builder.setQosCharacteristics(qosCharacteristics); 6382 } 6383 QosPolicyParams downlinkParams = builder.build(); 6384 6385 assertEquals(policyId, downlinkParams.getPolicyId()); 6386 assertEquals(QosPolicyParams.DIRECTION_DOWNLINK, downlinkParams.getDirection()); 6387 assertEquals(srcAddr, downlinkParams.getSourceAddress()); 6388 assertEquals(dstAddr, downlinkParams.getDestinationAddress()); 6389 assertEquals(userPriority, downlinkParams.getUserPriority()); 6390 assertEquals(ipVersion, downlinkParams.getIpVersion()); 6391 assertEquals(srcPort, downlinkParams.getSourcePort()); 6392 assertEquals(protocol, downlinkParams.getProtocol()); 6393 assertEquals(dstPort, downlinkParams.getDestinationPort()); 6394 assertArrayEquals(flowLabel, downlinkParams.getFlowLabel()); 6395 if (qosR3Supported()) { 6396 assertEquals(qosCharacteristics, downlinkParams.getQosCharacteristics()); 6397 } 6398 6399 if (ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 6400 Log.i(TAG, "Uplink policies were not tested, since they are not supported before V"); 6401 return; 6402 } 6403 6404 // Valid uplink parameters 6405 if (qosR3Supported()) { 6406 QosPolicyParams uplinkParams = 6407 new QosPolicyParams.Builder(policyId, QosPolicyParams.DIRECTION_UPLINK) 6408 .setSourceAddress(srcAddr) 6409 .setDestinationAddress(dstAddr) 6410 .setDscp(dscp) 6411 .setSourcePort(srcPort) 6412 .setProtocol(protocol) 6413 .setDestinationPortRange(dstPortRange[0], dstPortRange[1]) 6414 .setQosCharacteristics(qosCharacteristics) 6415 .build(); 6416 assertEquals(policyId, uplinkParams.getPolicyId()); 6417 assertEquals(QosPolicyParams.DIRECTION_UPLINK, uplinkParams.getDirection()); 6418 assertEquals(srcAddr, uplinkParams.getSourceAddress()); 6419 assertEquals(dstAddr, uplinkParams.getDestinationAddress()); 6420 assertEquals(dscp, uplinkParams.getDscp()); 6421 assertEquals(srcPort, uplinkParams.getSourcePort()); 6422 assertEquals(protocol, uplinkParams.getProtocol()); 6423 assertArrayEquals(dstPortRange, uplinkParams.getDestinationPortRange()); 6424 assertEquals(qosCharacteristics, uplinkParams.getQosCharacteristics()); 6425 } 6426 } 6427 6428 /** 6429 * Verifies when the link layer stats polling interval is overridden by 6430 * {@link WifiManager#setLinkLayerStatsPollingInterval(int)}, 6431 * the new interval is set correctly by checking 6432 * {@link WifiManager#getLinkLayerStatsPollingInterval(Executor, Consumer)} 6433 */ 6434 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6435 @Test testSetAndGetLinkLayerStatsPollingInterval()6436 public void testSetAndGetLinkLayerStatsPollingInterval() throws Exception { 6437 AtomicInteger currentInterval = new AtomicInteger(-1); 6438 Consumer<Integer> listener = new Consumer<Integer>() { 6439 @Override 6440 public void accept(Integer value) { 6441 synchronized (mLock) { 6442 currentInterval.set(value); 6443 mLock.notify(); 6444 } 6445 } 6446 }; 6447 6448 // SecurityException 6449 assertThrows(SecurityException.class, 6450 () -> sWifiManager.setLinkLayerStatsPollingInterval( 6451 TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS)); 6452 assertThrows(SecurityException.class, 6453 () -> sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, listener)); 6454 // null executor 6455 assertThrows("null executor should trigger exception", NullPointerException.class, 6456 () -> sWifiManager.getLinkLayerStatsPollingInterval(null, listener)); 6457 // null listener 6458 assertThrows("null listener should trigger exception", NullPointerException.class, 6459 () -> sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, null)); 6460 6461 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6462 6463 try { 6464 uiAutomation.adoptShellPermissionIdentity(); 6465 assertThrows(IllegalArgumentException.class, 6466 () -> sWifiManager.setLinkLayerStatsPollingInterval( 6467 -TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS)); 6468 sWifiManager.setLinkLayerStatsPollingInterval( 6469 TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS); 6470 sWifiManager.getLinkLayerStatsPollingInterval(mExecutor, listener); 6471 synchronized (mLock) { 6472 mLock.wait(TEST_WAIT_DURATION_MS); 6473 } 6474 assertEquals(TEST_LINK_LAYER_STATS_POLLING_INTERVAL_MS, currentInterval.get()); 6475 // set the interval to automatic handling after the test 6476 sWifiManager.setLinkLayerStatsPollingInterval(0); 6477 } catch (UnsupportedOperationException ex) { 6478 // Expected if the device does not support this API 6479 } catch (Exception e) { 6480 fail("setLinkLayerStatsPollingInterval / getLinkLayerStatsPollingInterval " 6481 + "unexpected Exception " + e); 6482 } finally { 6483 uiAutomation.dropShellPermissionIdentity(); 6484 } 6485 } 6486 6487 /** 6488 * Tests {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)} and 6489 * {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}. 6490 */ 6491 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6492 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6493 @Test testMloCapabilities()6494 public void testMloCapabilities() throws Exception { 6495 AtomicInteger linkCount = new AtomicInteger(); 6496 Consumer<Integer> getListener = new Consumer<Integer>() { 6497 @Override 6498 public void accept(Integer value) { 6499 synchronized (mLock) { 6500 linkCount.set(value); 6501 mLock.notify(); 6502 } 6503 } 6504 }; 6505 6506 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6507 try { 6508 uiAutomation.adoptShellPermissionIdentity(); 6509 // Test that invalid inputs trigger an exception. 6510 assertThrows("null executor should trigger exception", NullPointerException.class, 6511 () -> sWifiManager.getMaxMloAssociationLinkCount(null, getListener)); 6512 assertThrows("null listener should trigger exception", NullPointerException.class, 6513 () -> sWifiManager.getMaxMloAssociationLinkCount(mExecutor, null)); 6514 assertThrows("null executor should trigger exception", NullPointerException.class, 6515 () -> sWifiManager.getMaxMloStrLinkCount(null, getListener)); 6516 assertThrows("null listener should trigger exception", NullPointerException.class, 6517 () -> sWifiManager.getMaxMloStrLinkCount(mExecutor, null)); 6518 6519 linkCount.set(Integer.MIN_VALUE); 6520 sWifiManager.getMaxMloStrLinkCount(mExecutor, getListener); 6521 PollingCheck.check("getMaxMloStrLinkCount failed", TEST_WAIT_DURATION_MS, 6522 () -> (linkCount.get() >= -1)); 6523 6524 linkCount.set(Integer.MIN_VALUE); 6525 sWifiManager.getMaxMloAssociationLinkCount(mExecutor, getListener); 6526 PollingCheck.check("getMaxMloAssociationLinkCount failed", TEST_WAIT_DURATION_MS, 6527 () -> (linkCount.get() >= -1)); 6528 } catch (Exception e) { 6529 fail("Unexpected exception " + e); 6530 } finally { 6531 uiAutomation.dropShellPermissionIdentity(); 6532 } 6533 } 6534 /** 6535 * Tests {@link WifiManager#setLinkMode} and {@link WifiManager#getLinkMode} works 6536 */ 6537 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6538 @Test testMloMode()6539 public void testMloMode() { 6540 // Get listener. 6541 AtomicInteger getMode = new AtomicInteger(); 6542 Consumer<Integer> getListener = new Consumer<Integer>() { 6543 @Override 6544 public void accept(Integer value) { 6545 synchronized (mLock) { 6546 getMode.set(value); 6547 mLock.notify(); 6548 } 6549 } 6550 }; 6551 // Set listener. 6552 AtomicBoolean setStatus = new AtomicBoolean(); 6553 Consumer<Boolean> setListener = new Consumer<Boolean>() { 6554 @Override 6555 public void accept(Boolean value) { 6556 synchronized (mLock) { 6557 setStatus.set(value); 6558 mLock.notify(); 6559 } 6560 } 6561 }; 6562 // Test that invalid inputs trigger an exception. 6563 assertThrows("null executor should trigger exception", NullPointerException.class, 6564 () -> sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, null, setListener)); 6565 assertThrows("null listener should trigger exception", NullPointerException.class, 6566 () -> sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, mExecutor, null)); 6567 assertThrows("null executor should trigger exception", NullPointerException.class, 6568 () -> sWifiManager.getMloMode(null, getListener)); 6569 assertThrows("null listener should trigger exception", NullPointerException.class, 6570 () -> sWifiManager.getMloMode(mExecutor, null)); 6571 6572 // Test that invalid inputs trigger an IllegalArgumentException. 6573 assertThrows("Invalid mode", IllegalArgumentException.class, 6574 () -> sWifiManager.setMloMode(-1, mExecutor, setListener)); 6575 assertThrows("Invalid mode", IllegalArgumentException.class, 6576 () -> sWifiManager.setMloMode(1000, mExecutor, setListener)); 6577 6578 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6579 // Test set if supported. 6580 try { 6581 uiAutomation.adoptShellPermissionIdentity(); 6582 // Check getMloMode() returns values in range. 6583 sWifiManager.getMloMode(mExecutor, getListener); 6584 assertThat(getMode.get()).isIn(Range.closed(WifiManager.MLO_MODE_DEFAULT, 6585 WifiManager.MLO_MODE_LOW_POWER)); 6586 // Try to set default MLO mode and get. 6587 sWifiManager.setMloMode(WifiManager.MLO_MODE_DEFAULT, mExecutor, setListener); 6588 if (setStatus.get()) { 6589 sWifiManager.getMloMode(mExecutor, getListener); 6590 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT); 6591 } 6592 // Try to set low latency MLO mode and get. 6593 sWifiManager.setMloMode(WifiManager.MLO_MODE_LOW_LATENCY, mExecutor, setListener); 6594 if (setStatus.get()) { 6595 sWifiManager.getMloMode(mExecutor, getListener); 6596 assertTrue(getMode.get() == WifiManager.MLO_MODE_LOW_LATENCY); 6597 } 6598 // Try to set high throughput MLO mode and get. 6599 sWifiManager.setMloMode(WifiManager.MLO_MODE_HIGH_THROUGHPUT, mExecutor, setListener); 6600 if (setStatus.get()) { 6601 sWifiManager.getMloMode(mExecutor, getListener); 6602 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT); 6603 } 6604 // Try to set low power MLO mode and get. 6605 sWifiManager.setMloMode(WifiManager.MLO_MODE_LOW_POWER, mExecutor, setListener); 6606 if (setStatus.get()) { 6607 sWifiManager.getMloMode(mExecutor, getListener); 6608 assertTrue(getMode.get() == WifiManager.MLO_MODE_DEFAULT); 6609 } 6610 } catch (Exception e) { 6611 fail("Unexpected exception " + e); 6612 } finally { 6613 uiAutomation.dropShellPermissionIdentity(); 6614 } 6615 } 6616 6617 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6618 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6619 @Test testGetSupportedSimultaneousBandCombinations()6620 public void testGetSupportedSimultaneousBandCombinations() { 6621 AtomicInteger nEntries = new AtomicInteger(); 6622 Consumer<List<int[]>> getListener = new Consumer<List<int[]>>() { 6623 @Override 6624 public void accept(List<int[]> bands) { 6625 synchronized (mLock) { 6626 nEntries.set(bands.size()); 6627 mLock.notify(); 6628 } 6629 } 6630 }; 6631 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6632 try { 6633 uiAutomation.adoptShellPermissionIdentity(); 6634 6635 assertThrows("null executor should trigger exception", NullPointerException.class, 6636 () -> sWifiManager.getSupportedSimultaneousBandCombinations(null, getListener)); 6637 assertThrows("null listener should trigger exception", NullPointerException.class, 6638 () -> sWifiManager.getSupportedSimultaneousBandCombinations(mExecutor, null)); 6639 6640 nEntries.set(-1); 6641 sWifiManager.getSupportedSimultaneousBandCombinations(mExecutor, getListener); 6642 PollingCheck.check("getSupportedSimultaneousBandCombinations failed", 6643 TEST_WAIT_DURATION_MS, 6644 () -> (nEntries.get() > -1)); 6645 } catch (Exception e) { 6646 fail("Unexpected exception " + e); 6647 } finally { 6648 uiAutomation.dropShellPermissionIdentity(); 6649 } 6650 } 6651 6652 /** 6653 * Tests {@link WifiManager#isThirdPartyAppEnablingWifiConfirmationDialogEnabled()} 6654 * and {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} 6655 */ 6656 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6657 @Test testGetAndSetThirdPartyAppEnablingWifiConfirmationDialogEnabled()6658 public void testGetAndSetThirdPartyAppEnablingWifiConfirmationDialogEnabled() { 6659 // Expect a SecurityException without the required permissions. 6660 assertThrows(SecurityException.class, 6661 () -> sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled()); 6662 assertThrows(SecurityException.class, 6663 () -> sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(true)); 6664 6665 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6666 try { 6667 uiAutomation.adoptShellPermissionIdentity(); 6668 6669 // Store a new value. 6670 boolean defaultVal = 6671 sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled(); 6672 boolean newVal = !defaultVal; 6673 sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(newVal); 6674 assertEquals(newVal, 6675 sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled()); 6676 6677 // Restore the original value. 6678 sWifiManager.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(defaultVal); 6679 assertEquals(defaultVal, 6680 sWifiManager.isThirdPartyAppEnablingWifiConfirmationDialogEnabled()); 6681 } catch (Exception e) { 6682 fail("Unexpected exception " + e); 6683 } finally { 6684 uiAutomation.dropShellPermissionIdentity(); 6685 } 6686 } 6687 6688 static class TestWifiLowLatencyLockListener implements WifiManager.WifiLowLatencyLockListener { 6689 private boolean mIsActivated = false; 6690 private int[] mOwnerUids = null; 6691 private int[] mActiveUids = null; 6692 clear()6693 public void clear() { 6694 mIsActivated = false; 6695 mOwnerUids = null; 6696 mActiveUids = null; 6697 } 6698 6699 @Override onActivatedStateChanged(boolean activated)6700 public void onActivatedStateChanged(boolean activated) { 6701 mIsActivated = activated; 6702 } 6703 6704 @Override onOwnershipChanged(@onNull int[] ownerUids)6705 public void onOwnershipChanged(@NonNull int[] ownerUids) { 6706 mOwnerUids = ownerUids; 6707 } 6708 6709 @Override onActiveUsersChanged(@onNull int[] activeUids)6710 public void onActiveUsersChanged(@NonNull int[] activeUids) { 6711 mActiveUids = activeUids; 6712 } 6713 isActivated()6714 public boolean isActivated() { 6715 return mIsActivated; 6716 } 6717 isLockOwned(int myUid)6718 public boolean isLockOwned(int myUid) { 6719 if (mOwnerUids == null) return false; 6720 for (int uid : mOwnerUids) { 6721 if (uid == myUid) return true; 6722 } 6723 return false; 6724 } 6725 isActiveLockUser(int myUid)6726 public boolean isActiveLockUser(int myUid) { 6727 if (mActiveUids == null) return false; 6728 for (int uid : mActiveUids) { 6729 if (uid == myUid) return true; 6730 } 6731 return false; 6732 } 6733 } 6734 6735 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 6736 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6737 @Test testWifiLowLatencyLockListener()6738 public void testWifiLowLatencyLockListener() throws Exception { 6739 TestWifiLowLatencyLockListener testListener = new TestWifiLowLatencyLockListener(); 6740 // Verify permission check 6741 assertThrows(SecurityException.class, 6742 () -> sWifiManager.addWifiLowLatencyLockListener(mExecutor, testListener)); 6743 6744 // Disable wifi 6745 setWifiEnabled(false); 6746 waitForDisconnection(); 6747 6748 WifiLock wifiLowLatencyLock = sWifiManager.createWifiLock( 6749 WifiManager.WIFI_MODE_FULL_LOW_LATENCY, 6750 TAG); 6751 6752 try { 6753 // Register listener then enable wifi 6754 ShellIdentityUtils.invokeWithShellPermissions( 6755 () -> sWifiManager.addWifiLowLatencyLockListener(mExecutor, testListener)); 6756 setWifiEnabled(true); 6757 6758 // Trigger a scan & wait for connection to one of the saved networks. 6759 sWifiManager.startScan(); 6760 waitForConnection(); 6761 6762 // TODO: b/281356259 - Move this to a foreground activity. 6763 ShellIdentityUtils.invokeWithShellPermissions(() -> wifiLowLatencyLock.acquire()); 6764 6765 if (sWifiManager.isLowLatencyModeSupported()) { 6766 PollingCheck.check("Lock is not activated!", 1_000, 6767 () -> testListener.isActivated()); 6768 } 6769 6770 PollingCheck.check("Lock is not owned!", 1_000, 6771 () -> testListener.isLockOwned(myUid())); 6772 6773 if (sWifiManager.isLowLatencyModeSupported()) { 6774 PollingCheck.check("Not an active Lock user!", 1_000, 6775 () -> testListener.isActiveLockUser(myUid())); 6776 } 6777 6778 ShellIdentityUtils.invokeWithShellPermissions(() -> wifiLowLatencyLock.release()); 6779 6780 // Note: The lock cannot be tested for deactivation after release because other 6781 // applications can still keep it active. 6782 6783 PollingCheck.check("Still owns the Lock after release!", 1_000, 6784 () -> !testListener.isLockOwned(myUid())); 6785 } catch (Exception e) { 6786 fail("Unexpected exception " + e); 6787 } finally { 6788 testListener.clear(); 6789 sWifiManager.removeWifiLowLatencyLockListener(testListener); 6790 } 6791 } 6792 6793 /** 6794 * Tests the builder and get methods for {@link OuiKeyedData}. 6795 */ 6796 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6797 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, 6798 codeName = "VanillaIceCream") 6799 @Test testOuiKeyedDataBuilder()6800 public void testOuiKeyedDataBuilder() throws Exception { 6801 int oui = 0x00112233; 6802 PersistableBundle data = new PersistableBundle(); 6803 String key = "intField"; 6804 data.putInt(key, 12345); 6805 6806 assertThrows("Zero OUI should trigger an exception", IllegalArgumentException.class, 6807 () -> new OuiKeyedData.Builder(0, data).build()); 6808 assertThrows(">24-bit OUI should trigger an exception", IllegalArgumentException.class, 6809 () -> new OuiKeyedData.Builder(0x11223344, data).build()); 6810 assertThrows("Null data should trigger an exception", IllegalArgumentException.class, 6811 () -> new OuiKeyedData.Builder(oui, null).build()); 6812 6813 OuiKeyedData ouiKeyedData = new OuiKeyedData.Builder(oui, data).build(); 6814 assertEquals(oui, ouiKeyedData.getOui()); 6815 assertTrue(data.keySet().equals(ouiKeyedData.getData().keySet())); 6816 assertEquals(data.getInt(key), ouiKeyedData.getData().getInt(key)); 6817 } 6818 6819 /** 6820 * Tests {@link WifiManager#isWepSupported()} does not crash. 6821 */ 6822 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6823 @Test testIsWepSupported()6824 public void testIsWepSupported() throws Exception { 6825 sWifiManager.isWepSupported(); 6826 } 6827 6828 /** 6829 * Tests {@link WifiManager#isWpaPersonalSupported()} does not crash. 6830 */ 6831 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6832 @Test testIsWpaPersonalSupported()6833 public void testIsWpaPersonalSupported() throws Exception { 6834 sWifiManager.isWpaPersonalSupported(); 6835 } 6836 6837 /** 6838 * Tests {@link WifiManager#setWepAllowed()} and 6839 * {@link WifiManager#queryWepAllowed()}. 6840 */ 6841 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6842 @Test testSetAndQueryWepAllowed()6843 public void testSetAndQueryWepAllowed() throws Exception { 6844 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6845 Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false); 6846 boolean currentWepAllowed = false; 6847 boolean isRestoreRequired = false; 6848 long now, deadline; 6849 try { 6850 uiAutomation.adoptShellPermissionIdentity(); 6851 Mutable<Boolean> isWepAllowed = new Mutable<Boolean>(false); 6852 sWifiManager.queryWepAllowed(mExecutor, 6853 new Consumer<Boolean>() { 6854 @Override 6855 public void accept(Boolean value) { 6856 synchronized (mLock) { 6857 isWepAllowed.value = value; 6858 isQuerySucceeded.value = true; 6859 mLock.notify(); 6860 } 6861 } 6862 }); 6863 synchronized (mLock) { 6864 now = System.currentTimeMillis(); 6865 deadline = now + TEST_WAIT_DURATION_MS; 6866 while (!isQuerySucceeded.value && now < deadline) { 6867 mLock.wait(deadline - now); 6868 now = System.currentTimeMillis(); 6869 } 6870 } 6871 assertTrue(isQuerySucceeded.value); 6872 // Reset for next query 6873 isQuerySucceeded.value = false; 6874 currentWepAllowed = isWepAllowed.value; 6875 isRestoreRequired = true; 6876 sWifiManager.setWepAllowed(!currentWepAllowed); 6877 sWifiManager.queryWepAllowed(mExecutor, 6878 new Consumer<Boolean>() { 6879 @Override 6880 public void accept(Boolean value) { 6881 synchronized (mLock) { 6882 isWepAllowed.value = value; 6883 isQuerySucceeded.value = true; 6884 mLock.notify(); 6885 } 6886 } 6887 }); 6888 synchronized (mLock) { 6889 now = System.currentTimeMillis(); 6890 deadline = now + TEST_WAIT_DURATION_MS; 6891 while (!isQuerySucceeded.value && now < deadline) { 6892 mLock.wait(deadline - now); 6893 now = System.currentTimeMillis(); 6894 } 6895 } 6896 assertEquals(isWepAllowed.value, !currentWepAllowed); 6897 } finally { 6898 if (isRestoreRequired) { 6899 sWifiManager.setWepAllowed(currentWepAllowed); 6900 } 6901 uiAutomation.dropShellPermissionIdentity(); 6902 } 6903 } 6904 6905 /** 6906 * Tests {@link WifiManager#enableMscs(MscsParams)}, {@link WifiManager#disableMscs()}, 6907 * and all get/set methods in {@link MscsParams}. 6908 */ 6909 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6910 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, 6911 codeName = "VanillaIceCream") 6912 @Test testEnableAndDisableMscs()6913 public void testEnableAndDisableMscs() { 6914 int frameClassifierFields = MscsParams.FRAME_CLASSIFIER_IP_VERSION; 6915 int userPriorityBitmap = 0; // don't match any user priorities using MSCS 6916 int userPriorityLimit = 7; 6917 int streamTimeoutUs = 30000000; // 30 seconds (value is longer than TEST_WAIT_DURATION_MS) 6918 MscsParams params = new MscsParams.Builder() 6919 .setFrameClassifierFields(frameClassifierFields) 6920 .setUserPriorityBitmap(userPriorityBitmap) 6921 .setUserPriorityLimit(userPriorityLimit) 6922 .setStreamTimeoutUs(streamTimeoutUs) 6923 .build(); 6924 assertEquals(frameClassifierFields, params.getFrameClassifierFields()); 6925 assertEquals(userPriorityBitmap, params.getUserPriorityBitmap()); 6926 assertEquals(userPriorityLimit, params.getUserPriorityLimit()); 6927 assertEquals(streamTimeoutUs, params.getStreamTimeoutUs()); 6928 6929 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 6930 try { 6931 uiAutomation.adoptShellPermissionIdentity(); 6932 sWifiManager.enableMscs(params); 6933 synchronized (mLock) { 6934 // Wait for the request to get sent to the AP. 6935 mLock.wait(TEST_WAIT_DURATION_MS); 6936 } 6937 sWifiManager.disableMscs(); 6938 } catch (Exception e) { 6939 fail("testEnableAndDisableMscs encountered an exception: " + e); 6940 } finally { 6941 uiAutomation.dropShellPermissionIdentity(); 6942 } 6943 } 6944 6945 /** 6946 * Tests the result from {@link WifiUriParser#parseUri(String)} can be added. 6947 */ 6948 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6949 @Test testZxingNetworkFromUriParserCanBeAdded()6950 public void testZxingNetworkFromUriParserCanBeAdded() throws Exception { 6951 String testUriZx = "WIFI:S:testAbC;T:nopass"; 6952 UriParserResults result = WifiUriParser.parseUri(testUriZx); 6953 assertNotNull(result); 6954 assertEquals(result.getUriScheme(), UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG); 6955 WifiConfiguration config = result.getWifiConfiguration(); 6956 assertNotNull(config); 6957 // These below API's only work with privileged permissions (obtained via shell identity 6958 // for test) 6959 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation() 6960 .getUiAutomation(); 6961 int networkId = INVALID_NETWORK_ID; 6962 try { 6963 uiAutomation.adoptShellPermissionIdentity(); 6964 // Verify that the network is added 6965 networkId = sWifiManager.addNetwork(config); 6966 assertNotEquals(INVALID_NETWORK_ID, networkId); 6967 } finally { 6968 if (networkId != INVALID_NETWORK_ID) { 6969 // Clean up the previously added network 6970 sWifiManager.removeNetwork(networkId); 6971 } 6972 uiAutomation.dropShellPermissionIdentity(); 6973 } 6974 } 6975 6976 /* 6977 * Tests the builder and get methods for {@link QosCharacteristics}. 6978 */ 6979 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 6980 @Test testQosCharacteristicsBuilder()6981 public void testQosCharacteristicsBuilder() { 6982 int minServiceIntervalMicros = 2000; 6983 int maxServiceIntervalMicros = 5000; 6984 int minDataRateKbps = 500; 6985 int delayBoundMicros = 200; 6986 int maxMsduSizeOctets = 4; 6987 int serviceStartTimeMicros = 250; 6988 int serviceStartTimeLinkId = 0x5; 6989 int meanDataRateKbps = 1500; 6990 int burstSizeOctets = 2; 6991 int msduLifetimeMillis = 400; 6992 int deliveryRatio = QosCharacteristics.DELIVERY_RATIO_99; 6993 int countExponent = 5; 6994 6995 QosCharacteristics qosCharacteristics = new QosCharacteristics.Builder( 6996 minServiceIntervalMicros, maxServiceIntervalMicros, 6997 minDataRateKbps, delayBoundMicros) 6998 .setBurstSizeOctets(burstSizeOctets) 6999 .setMaxMsduSizeOctets(maxMsduSizeOctets) 7000 .setServiceStartTimeInfo(serviceStartTimeMicros, serviceStartTimeLinkId) 7001 .setMeanDataRateKbps(meanDataRateKbps) 7002 .setMsduLifetimeMillis(msduLifetimeMillis) 7003 .setMsduDeliveryInfo(deliveryRatio, countExponent) 7004 .build(); 7005 7006 assertEquals(minServiceIntervalMicros, qosCharacteristics.getMinServiceIntervalMicros()); 7007 assertEquals(maxServiceIntervalMicros, qosCharacteristics.getMaxServiceIntervalMicros()); 7008 assertEquals(minDataRateKbps, qosCharacteristics.getMinDataRateKbps()); 7009 assertEquals(delayBoundMicros, qosCharacteristics.getDelayBoundMicros()); 7010 assertEquals(maxMsduSizeOctets, qosCharacteristics.getMaxMsduSizeOctets()); 7011 assertEquals(serviceStartTimeMicros, qosCharacteristics.getServiceStartTimeMicros()); 7012 assertEquals(serviceStartTimeLinkId, qosCharacteristics.getServiceStartTimeLinkId()); 7013 assertEquals(meanDataRateKbps, qosCharacteristics.getMeanDataRateKbps()); 7014 assertEquals(burstSizeOctets, qosCharacteristics.getBurstSizeOctets()); 7015 assertEquals(msduLifetimeMillis, qosCharacteristics.getMsduLifetimeMillis()); 7016 assertEquals(deliveryRatio, qosCharacteristics.getDeliveryRatio()); 7017 assertEquals(countExponent, qosCharacteristics.getCountExponent()); 7018 } 7019 querySendDhcpHostnameRestrictionSynchronous()7020 private int querySendDhcpHostnameRestrictionSynchronous() throws Exception { 7021 Mutable<Integer> queriedRestriction = new Mutable<>(0); 7022 Mutable<Boolean> isQuerySucceeded = new Mutable<>(false); 7023 sWifiManager.querySendDhcpHostnameRestriction(mExecutor, (value) -> { 7024 synchronized (mLock) { 7025 queriedRestriction.value = value; 7026 isQuerySucceeded.value = true; 7027 mLock.notify(); 7028 } 7029 }); 7030 synchronized (mLock) { 7031 long now = System.currentTimeMillis(); 7032 long deadline = now + TEST_WAIT_DURATION_MS; 7033 while (!isQuerySucceeded.value && now < deadline) { 7034 mLock.wait(deadline - now); 7035 now = System.currentTimeMillis(); 7036 } 7037 } 7038 assertTrue(isQuerySucceeded.value); 7039 return queriedRestriction.value; 7040 } 7041 7042 /** 7043 * Tests {@link WifiManager#setSendDhcpHostnameRestriction(int)} and 7044 * {@link WifiManager#querySendDhcpHostnameRestriction(Executor, IntConsumer)}. 7045 */ 7046 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 7047 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, 7048 codeName = "VanillaIceCream") 7049 @Test testSetAndQuerySendDhcpHostnameRestriction()7050 public void testSetAndQuerySendDhcpHostnameRestriction() throws Exception { 7051 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7052 int previousRestriction = 0; 7053 boolean isRestoreRequired = false; 7054 try { 7055 uiAutomation.adoptShellPermissionIdentity(); 7056 previousRestriction = querySendDhcpHostnameRestrictionSynchronous(); 7057 7058 sWifiManager.setSendDhcpHostnameRestriction( 7059 WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); 7060 isRestoreRequired = true; 7061 assertEquals(querySendDhcpHostnameRestrictionSynchronous(), 7062 WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN); 7063 7064 sWifiManager.setSendDhcpHostnameRestriction( 7065 WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN 7066 | WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE); 7067 assertEquals(querySendDhcpHostnameRestrictionSynchronous(), 7068 WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN 7069 | WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE); 7070 } finally { 7071 if (isRestoreRequired) { 7072 sWifiManager.setSendDhcpHostnameRestriction(previousRestriction); 7073 } 7074 uiAutomation.dropShellPermissionIdentity(); 7075 } 7076 } 7077 7078 /** 7079 * Tests {@link WifiConfiguration#setWifi7Enabled(boolean)}. Validate default behavior, disable 7080 * Wi-Fi 7 and Enable Wi-Fi 7. 7081 */ 7082 @ApiTest(apis = {"android.net.wifi.WifiConfiguration#setWifi7Enabled", 7083 "android.net.wifi.WifiConfiguration#isWifi7Enabled"}) 7084 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 7085 @Test testEnableWifi7()7086 public void testEnableWifi7() throws Exception { 7087 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7088 TestActionListener actionListener = new TestActionListener(mLock); 7089 setWifiEnabled(true); 7090 WifiConfiguration wifi7Network = null; 7091 try { 7092 uiAutomation.adoptShellPermissionIdentity(); 7093 // Make sure device supports Wi-Fi 7 7094 assumeTrue(sWifiManager.isWifiStandardSupported(ScanResult.WIFI_STANDARD_11BE)); 7095 7096 List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks(); 7097 wifi7Network = TestHelper.findFirstAvailableSavedNetwork(sWifiManager, 7098 savedNetworks, TestHelper.AP_CAPABILITY_BIT_WIFI7); 7099 // TODO: b/322011012 7100 assumeTrue("Unable to locate Wi-Fi 7 networks in range.\n", wifi7Network != null); 7101 7102 // Default behavior: check new connection is Wi-Fi 7 7103 sWifiManager.disconnect(); 7104 waitForDisconnection(); 7105 assertTrue(wifi7Network.isWifi7Enabled()); 7106 sWifiManager.connect(wifi7Network.networkId, actionListener); 7107 waitForConnection(); 7108 assertTrue(sWifiManager.getConnectionInfo().getWifiStandard() 7109 == ScanResult.WIFI_STANDARD_11BE); 7110 7111 // Disable Wi-Fi 7 while connected: check new connection is not Wi-Fi 7 7112 wifi7Network.setWifi7Enabled(false); 7113 assertFalse(wifi7Network.isWifi7Enabled()); 7114 sWifiManager.updateNetwork(wifi7Network); 7115 waitForConnection(); 7116 assertTrue(sWifiManager.getConnectionInfo().getWifiStandard() 7117 != ScanResult.WIFI_STANDARD_11BE); 7118 7119 // Enable Wi-Fi 7: check new connection is Wi-Fi 7 7120 sWifiManager.disconnect(); 7121 waitForDisconnection(); 7122 wifi7Network.setWifi7Enabled(true); 7123 assertTrue(wifi7Network.isWifi7Enabled()); 7124 sWifiManager.connect(wifi7Network.networkId, actionListener); 7125 waitForConnection(); 7126 assertTrue(sWifiManager.getConnectionInfo().getWifiStandard() 7127 == ScanResult.WIFI_STANDARD_11BE); 7128 7129 } finally { 7130 // Restore 7131 if (wifi7Network != null) { 7132 wifi7Network.setWifi7Enabled(true); 7133 } 7134 uiAutomation.dropShellPermissionIdentity(); 7135 } 7136 } 7137 7138 class TestTwtSessionCallback implements TwtSessionCallback { 7139 final AtomicReference<TwtSession> mTwtSession = new AtomicReference<>(); 7140 final AtomicInteger mTwtTeardownReasonCode = new AtomicInteger(-1); 7141 final AtomicInteger mTwtErrorCode = new AtomicInteger(-1); 7142 7143 @Override onFailure(int errorCode)7144 public void onFailure(int errorCode) { 7145 synchronized (mLock) { 7146 mTwtErrorCode.set(errorCode); 7147 mLock.notify(); 7148 } 7149 } 7150 7151 @Override onTeardown(int reasonCode)7152 public void onTeardown(int reasonCode) { 7153 synchronized (mLock) { 7154 mTwtTeardownReasonCode.set(reasonCode); 7155 mLock.notify(); 7156 } 7157 } 7158 7159 @Override onCreate(TwtSession twtSession)7160 public void onCreate(TwtSession twtSession) { 7161 synchronized (mLock) { 7162 mTwtSession.set(twtSession); 7163 } 7164 } 7165 } 7166 7167 /** 7168 * Validate setting up a TWT session if device supports and get stats and finally close. If the 7169 * connection is multi-link, pick the first link and set up the TWT session. 7170 */ 7171 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 7172 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, codeName = 7173 "VanillaIceCream") 7174 @Test 7175 @ApiTest(apis = {"android.net.wifi.WifiManager#getTwtCapabilities", 7176 "android.net.wifi.WifiManager#twtSessionSetup", 7177 "android.net.wifi.twt.TwtSession#getStats", 7178 "android.net.wifi.twt.TwtSession#teardown", 7179 "android.net.wifi.twt.TwtSession#getWakeDurationMicros", 7180 "android.net.wifi.twt.TwtSession#getWakeIntervalMicros", 7181 "android.net.wifi.twt.TwtSession#getMloLinkId", 7182 "android.net.wifi.twt.TwtRequest#Builder", 7183 "android.net.wifi.twt.TwtRequest.Builder#setLinkId", 7184 "android.net.wifi.twt.TwtRequest#getMinWakeDurationMicros", 7185 "android.net.wifi.twt.TwtRequest#getMaxWakeDurationMicros", 7186 "android.net.wifi.twt.TwtRequest#getMinWakeIntervalMicros", 7187 "android.net.wifi.twt.TwtRequest#getMaxWakeIntervalMicros", 7188 "android.net.wifi.twt.TwtRequest#getLinkId"}) testTwt()7189 public void testTwt() throws Exception { 7190 AtomicReference<Bundle> twtCapabilities = new AtomicReference<>(); 7191 AtomicReference<Bundle> twtStats = new AtomicReference<>(); 7192 long now, deadline; 7193 Consumer<Bundle> twtCapabilityCallback = capabilities -> { 7194 synchronized (mLock) { 7195 twtCapabilities.set(capabilities); 7196 mLock.notify(); 7197 } 7198 }; 7199 Consumer<Bundle> twtStatsCallback = stats -> { 7200 synchronized (mLock) { 7201 twtStats.set(stats); 7202 mLock.notify(); 7203 } 7204 }; 7205 TestTwtSessionCallback testTwtSessionCallback = new TestTwtSessionCallback(); 7206 TestActionListener actionListener = new TestActionListener(mLock); 7207 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7208 7209 try { 7210 uiAutomation.adoptShellPermissionIdentity(); 7211 sWifiManager.getTwtCapabilities(mExecutor, twtCapabilityCallback); 7212 synchronized (mLock) { 7213 now = System.currentTimeMillis(); 7214 deadline = now + TEST_WAIT_DURATION_MS; 7215 while (twtCapabilities.get() == null && now < deadline) { 7216 mLock.wait(deadline - now); 7217 now = System.currentTimeMillis(); 7218 } 7219 } 7220 assertNotNull("getTwtCapabilities() timed out !", twtCapabilities.get()); 7221 // Assume device is a TWT requester 7222 assumeTrue(twtCapabilities.get().getBoolean( 7223 WifiManager.TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER)); 7224 assertTrue(twtCapabilities.get().getInt( 7225 WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS) >= 0); 7226 assertTrue(twtCapabilities.get().getInt( 7227 WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS) >= 0); 7228 assertTrue(twtCapabilities.get().getLong( 7229 WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS) >= 0); 7230 assertTrue(twtCapabilities.get().getLong( 7231 WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS) >= 0); 7232 7233 // Connect to an available TWT responder network 7234 List<WifiConfiguration> savedNetworks = sWifiManager.getConfiguredNetworks(); 7235 WifiConfiguration twtNetwork = TestHelper.findFirstAvailableSavedNetwork(sWifiManager, 7236 savedNetworks, TestHelper.AP_CAPABILITY_BIT_TWT_RESPONDER); 7237 // TODO: Make it an assert once the TWT setup is available for CTS test 7238 assumeTrue("Unable to locate TWT capable networks in range.\n", twtNetwork != null); 7239 sWifiManager.disconnect(); 7240 waitForDisconnection(); 7241 sWifiManager.connect(twtNetwork.networkId, actionListener); 7242 waitForConnection(); 7243 7244 // Get the first link id, if the connection is multi-link 7245 List<MloLink> mloLinks = sWifiManager.getConnectionInfo().getAssociatedMloLinks(); 7246 int linkId = MloLink.INVALID_MLO_LINK_ID; 7247 if (!mloLinks.isEmpty()) { 7248 linkId = mloLinks.getFirst().getLinkId(); 7249 } 7250 7251 // Build and validate twtRequest 7252 int minWakeDuration = twtCapabilities.get().getInt( 7253 WifiManager.TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS); 7254 int maxWakeDuration = twtCapabilities.get().getInt( 7255 WifiManager.TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS); 7256 long minWakeInterval = twtCapabilities.get().getLong( 7257 WifiManager.TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS); 7258 long maxWakeInterval = twtCapabilities.get().getLong( 7259 WifiManager.TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS); 7260 TwtRequest.Builder builder = new TwtRequest.Builder(minWakeDuration, maxWakeDuration, 7261 minWakeInterval, maxWakeInterval); 7262 if (linkId != MloLink.INVALID_MLO_LINK_ID) { 7263 builder.setLinkId(linkId); 7264 } 7265 TwtRequest twtRequest = builder.build(); 7266 assertEquals(twtRequest.getMinWakeDurationMicros(), minWakeDuration); 7267 assertEquals(twtRequest.getMaxWakeDurationMicros(), maxWakeDuration); 7268 assertEquals(twtRequest.getMinWakeIntervalMicros(), minWakeInterval); 7269 assertEquals(twtRequest.getMaxWakeIntervalMicros(), maxWakeInterval); 7270 assertEquals(twtRequest.getLinkId(), linkId); 7271 7272 // Verify TWT session setup 7273 sWifiManager.setupTwtSession(twtRequest, mExecutor, testTwtSessionCallback); 7274 synchronized (mLock) { 7275 now = System.currentTimeMillis(); 7276 deadline = now + TEST_WAIT_DURATION_MS; 7277 while (testTwtSessionCallback.mTwtSession.get() == null && now < deadline) { 7278 mLock.wait(deadline - now); 7279 now = System.currentTimeMillis(); 7280 } 7281 } 7282 assertNotNull("setupTwtSession() timed out !", 7283 testTwtSessionCallback.mTwtSession.get()); 7284 assertTrue(testTwtSessionCallback.mTwtSession.get().getWakeDurationMicros() > 0); 7285 assertTrue(testTwtSessionCallback.mTwtSession.get().getWakeIntervalMicros() > 0); 7286 assertTrue(testTwtSessionCallback.mTwtSession.get().getMloLinkId() == linkId); 7287 7288 // Verify TWT session get stats 7289 testTwtSessionCallback.mTwtSession.get().getStats(mExecutor, twtStatsCallback); 7290 synchronized (mLock) { 7291 now = System.currentTimeMillis(); 7292 deadline = now + TEST_WAIT_DURATION_MS; 7293 while (twtStats.get() == null && now < deadline) { 7294 mLock.wait(deadline - now); 7295 now = System.currentTimeMillis(); 7296 } 7297 } 7298 assertNotNull("TwtSession#getStats() timed out !", twtStats.get()); 7299 assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_COUNT) 7300 >= 0); 7301 assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_COUNT) 7302 >= 0); 7303 assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_TX_PACKET_SIZE) 7304 >= 0); 7305 assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_RX_PACKET_SIZE) 7306 >= 0); 7307 assertTrue( 7308 twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_AVERAGE_EOSP_DURATION_MICROS) 7309 >= 0); 7310 assertTrue(twtStats.get().getInt(TwtSession.TWT_STATS_KEY_INT_EOSP_COUNT) >= 0); 7311 7312 // Verify TWT session teardown 7313 testTwtSessionCallback.mTwtSession.get().teardown(); 7314 synchronized (mLock) { 7315 now = System.currentTimeMillis(); 7316 deadline = now + TEST_WAIT_DURATION_MS; 7317 while (testTwtSessionCallback.mTwtTeardownReasonCode.get() == -1 7318 && now < deadline) { 7319 mLock.wait(deadline - now); 7320 now = System.currentTimeMillis(); 7321 } 7322 } 7323 assertNotEquals("TwtSession#teardown() timed out !", -1, 7324 testTwtSessionCallback.mTwtTeardownReasonCode.get()); 7325 assertTrue(testTwtSessionCallback.mTwtTeardownReasonCode.get() 7326 == TwtSessionCallback.TWT_REASON_CODE_LOCALLY_REQUESTED); 7327 } finally { 7328 uiAutomation.dropShellPermissionIdentity(); 7329 } 7330 } 7331 7332 /** 7333 * Tests {@link WifiManager#isD2dSupportedWhenInfraStaDisabled()}, 7334 * {@link WifiManager#setD2dAllowedWhenInfraStaDisabled()} and 7335 * {@link WifiManager#queryD2dAllowedWhenInfraStaDisabled()}. 7336 */ 7337 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 7338 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.TIRAMISU) 7339 @Test testD2dAllowedWhenInfraStaDisabled()7340 public void testD2dAllowedWhenInfraStaDisabled() throws Exception { 7341 if (!sWifiManager.isD2dSupportedWhenInfraStaDisabled()) { 7342 // skip the test if feature is not supported. 7343 return; 7344 } 7345 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7346 Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false); 7347 boolean currentD2dAllowed = false; 7348 boolean isRestoreRequired = false; 7349 long now, deadline; 7350 try { 7351 uiAutomation.adoptShellPermissionIdentity(); 7352 Mutable<Boolean> isD2dAllowed = new Mutable<Boolean>(false); 7353 sWifiManager.queryD2dAllowedWhenInfraStaDisabled(mExecutor, 7354 new Consumer<Boolean>() { 7355 @Override 7356 public void accept(Boolean value) { 7357 synchronized (mLock) { 7358 isD2dAllowed.value = value; 7359 isQuerySucceeded.value = true; 7360 mLock.notify(); 7361 } 7362 } 7363 }); 7364 synchronized (mLock) { 7365 now = System.currentTimeMillis(); 7366 deadline = now + TEST_WAIT_DURATION_MS; 7367 while (!isQuerySucceeded.value && now < deadline) { 7368 mLock.wait(deadline - now); 7369 now = System.currentTimeMillis(); 7370 } 7371 } 7372 assertTrue("d2d allowed query fail", isQuerySucceeded.value); 7373 // Reset for next query 7374 isQuerySucceeded.value = false; 7375 currentD2dAllowed = isD2dAllowed.value; 7376 isRestoreRequired = true; 7377 sWifiManager.setD2dAllowedWhenInfraStaDisabled(!currentD2dAllowed); 7378 sWifiManager.queryD2dAllowedWhenInfraStaDisabled(mExecutor, 7379 new Consumer<Boolean>() { 7380 @Override 7381 public void accept(Boolean value) { 7382 synchronized (mLock) { 7383 isD2dAllowed.value = value; 7384 isQuerySucceeded.value = true; 7385 mLock.notify(); 7386 } 7387 } 7388 }); 7389 synchronized (mLock) { 7390 now = System.currentTimeMillis(); 7391 deadline = now + TEST_WAIT_DURATION_MS; 7392 while (!isQuerySucceeded.value && now < deadline) { 7393 mLock.wait(deadline - now); 7394 now = System.currentTimeMillis(); 7395 } 7396 } 7397 assertEquals("set/query d2d allowed should match", 7398 isD2dAllowed.value, !currentD2dAllowed); 7399 } finally { 7400 if (isRestoreRequired) { 7401 sWifiManager.setD2dAllowedWhenInfraStaDisabled(currentD2dAllowed); 7402 } 7403 uiAutomation.dropShellPermissionIdentity(); 7404 } 7405 } 7406 7407 /** 7408 * Tests {@link WifiManager#getBssidBlocklist(List, Executor, Consumer)} 7409 */ 7410 @RequiresFlagsEnabled(Flags.FLAG_GET_BSSID_BLOCKLIST_API) 7411 @Test 7412 @ApiTest(apis = {"android.net.wifi.WifiManager#getBssidBlocklist"}) testGetBssidBlocklist()7413 public void testGetBssidBlocklist() throws Exception { 7414 Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false); 7415 Mutable<Boolean> isResultNonNull = new Mutable<Boolean>(false); 7416 long now, deadline; 7417 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7418 try { 7419 uiAutomation.adoptShellPermissionIdentity(); 7420 sWifiManager.getBssidBlocklist(Collections.EMPTY_LIST, mExecutor, 7421 new Consumer<List<MacAddress>>() { 7422 @Override 7423 public void accept(List<MacAddress> value) { 7424 synchronized (mLock) { 7425 isQuerySucceeded.value = true; 7426 if (value != null) { 7427 isResultNonNull.value = true; 7428 } 7429 mLock.notify(); 7430 } 7431 } 7432 }); 7433 synchronized (mLock) { 7434 now = System.currentTimeMillis(); 7435 deadline = now + TEST_WAIT_DURATION_MS; 7436 while (!isQuerySucceeded.value && now < deadline) { 7437 mLock.wait(deadline - now); 7438 now = System.currentTimeMillis(); 7439 } 7440 } 7441 assertTrue("getBssidBlocklist fail", isQuerySucceeded.value); 7442 assertTrue("getBssidBlocklist returned null list", isResultNonNull.value); 7443 } finally { 7444 uiAutomation.dropShellPermissionIdentity(); 7445 } 7446 } 7447 7448 /** 7449 * Tests {@link WifiManager#retrieveWifiBackupData()}, 7450 * {@link WifiManager#restoreWifiBackupData()}. 7451 */ 7452 @RequiresFlagsEnabled(Flags.FLAG_ANDROID_V_WIFI_API) 7453 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM, 7454 codeName = "VanillaIceCream") 7455 @Test testWifiBackupRestore()7456 public void testWifiBackupRestore() throws Exception { 7457 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 7458 Mutable<Boolean> isQuerySucceeded = new Mutable<Boolean>(false); 7459 Mutable<byte[]> backupWifiData = new Mutable<byte[]>(); 7460 long now, deadline; 7461 try { 7462 uiAutomation.adoptShellPermissionIdentity(); 7463 sWifiManager.retrieveWifiBackupData(mExecutor, 7464 new Consumer<byte[]>() { 7465 @Override 7466 public void accept(byte[] value) { 7467 synchronized (mLock) { 7468 isQuerySucceeded.value = true; 7469 backupWifiData.value = value; 7470 mLock.notify(); 7471 } 7472 } 7473 }); 7474 // Test no crash when calling backup/restore api 7475 synchronized (mLock) { 7476 now = System.currentTimeMillis(); 7477 deadline = now + TEST_WAIT_DURATION_MS; 7478 while (!isQuerySucceeded.value && now < deadline) { 7479 mLock.wait(deadline - now); 7480 now = System.currentTimeMillis(); 7481 } 7482 } 7483 assertTrue("retrieve Wi-Fi backup data fail", isQuerySucceeded.value); 7484 sWifiManager.restoreWifiBackupData(backupWifiData.value); 7485 } finally { 7486 uiAutomation.dropShellPermissionIdentity(); 7487 } 7488 } 7489 } 7490