1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 23 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 24 import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED; 25 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 26 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 27 28 import static com.android.server.wifi.SelfRecovery.REASON_API_CALL; 29 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.net.ConnectivityManager; 35 import android.net.MacAddress; 36 import android.net.Network; 37 import android.net.NetworkCapabilities; 38 import android.net.NetworkRequest; 39 import android.net.wifi.IActionListener; 40 import android.net.wifi.IScoreUpdateObserver; 41 import android.net.wifi.ISoftApCallback; 42 import android.net.wifi.IWifiConnectedNetworkScorer; 43 import android.net.wifi.ScanResult; 44 import android.net.wifi.SoftApCapability; 45 import android.net.wifi.SoftApConfiguration; 46 import android.net.wifi.SoftApInfo; 47 import android.net.wifi.SupplicantState; 48 import android.net.wifi.WifiClient; 49 import android.net.wifi.WifiConfiguration; 50 import android.net.wifi.WifiConnectedSessionInfo; 51 import android.net.wifi.WifiInfo; 52 import android.net.wifi.WifiManager; 53 import android.net.wifi.WifiNetworkSpecifier; 54 import android.net.wifi.WifiNetworkSuggestion; 55 import android.net.wifi.WifiScanner; 56 import android.net.wifi.WifiSsid; 57 import android.os.Binder; 58 import android.os.Process; 59 import android.os.RemoteException; 60 import android.os.SystemClock; 61 import android.telephony.Annotation; 62 import android.telephony.PhysicalChannelConfig; 63 import android.telephony.SubscriptionManager; 64 import android.telephony.TelephonyManager; 65 import android.text.TextUtils; 66 import android.util.Pair; 67 68 import androidx.annotation.NonNull; 69 70 import com.android.internal.annotations.VisibleForTesting; 71 import com.android.modules.utils.BasicShellCommandHandler; 72 import com.android.modules.utils.ParceledListSlice; 73 import com.android.modules.utils.build.SdkLevel; 74 import com.android.server.wifi.ClientMode.LinkProbeCallback; 75 import com.android.server.wifi.coex.CoexManager; 76 import com.android.server.wifi.coex.CoexUtils; 77 import com.android.server.wifi.hotspot2.NetworkDetail; 78 import com.android.server.wifi.util.ApConfigUtil; 79 import com.android.server.wifi.util.ArrayUtils; 80 import com.android.server.wifi.util.ScanResultUtil; 81 82 import java.io.PrintWriter; 83 import java.nio.charset.StandardCharsets; 84 import java.util.ArrayList; 85 import java.util.Arrays; 86 import java.util.Collection; 87 import java.util.Collections; 88 import java.util.Comparator; 89 import java.util.List; 90 import java.util.Map; 91 import java.util.Set; 92 import java.util.concurrent.ArrayBlockingQueue; 93 import java.util.concurrent.ConcurrentHashMap; 94 import java.util.concurrent.CountDownLatch; 95 import java.util.concurrent.TimeUnit; 96 import java.util.stream.Collectors; 97 98 /** 99 * Interprets and executes 'adb shell cmd wifi [args]'. 100 * 101 * To add new commands: 102 * - onCommand: Add a case "<command>" execute. Return a 0 103 * if command executed successfully. 104 * - onHelp: add a description string. 105 * 106 * Permissions: currently root permission is required for some commands. Others will 107 * enforce the corresponding API permissions. 108 */ 109 public class WifiShellCommand extends BasicShellCommandHandler { 110 @VisibleForTesting 111 public static String SHELL_PACKAGE_NAME = "com.android.shell"; 112 113 // These don't require root access. 114 // However, these do perform permission checks in the corresponding WifiService methods. 115 private static final String[] NON_PRIVILEGED_COMMANDS = { 116 "add-suggestion", 117 "add-network", 118 "connect-network", 119 "forget-network", 120 "get-country-code", 121 "help", 122 "-h", 123 "is-verbose-logging", 124 "list-scan-results", 125 "list-networks", 126 "list-suggestions", 127 "remove-suggestion", 128 "remove-all-suggestions", 129 "reset-connected-score", 130 "set-connected-score", 131 "set-scan-always-available", 132 "set-verbose-logging", 133 "set-wifi-enabled", 134 "start-scan", 135 "start-softap", 136 "status", 137 "stop-softap", 138 }; 139 140 private static final Map<String, Pair<NetworkRequest, ConnectivityManager.NetworkCallback>> 141 sActiveRequests = new ConcurrentHashMap<>(); 142 143 private final ActiveModeWarden mActiveModeWarden; 144 private final WifiGlobals mWifiGlobals; 145 private final WifiLockManager mWifiLockManager; 146 private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; 147 private final WifiConfigManager mWifiConfigManager; 148 private final WifiNative mWifiNative; 149 private final CoexManager mCoexManager; 150 private final WifiCountryCode mWifiCountryCode; 151 private final WifiLastResortWatchdog mWifiLastResortWatchdog; 152 private final WifiServiceImpl mWifiService; 153 private final Context mContext; 154 private final ConnectivityManager mConnectivityManager; 155 private final WifiCarrierInfoManager mWifiCarrierInfoManager; 156 private final WifiNetworkFactory mWifiNetworkFactory; 157 private final SelfRecovery mSelfRecovery; 158 private final WifiThreadRunner mWifiThreadRunner; 159 private final WifiApConfigStore mWifiApConfigStore; 160 private int mSapState = WifiManager.WIFI_STATE_UNKNOWN; 161 private final ScanRequestProxy mScanRequestProxy; 162 163 /** 164 * Used for shell command testing of scorer. 165 */ 166 public static class WifiScorer extends IWifiConnectedNetworkScorer.Stub { 167 private final WifiServiceImpl mWifiService; 168 private final CountDownLatch mCountDownLatch; 169 private Integer mSessionId; 170 private IScoreUpdateObserver mScoreUpdateObserver; 171 WifiScorer(WifiServiceImpl wifiService, CountDownLatch countDownLatch)172 public WifiScorer(WifiServiceImpl wifiService, CountDownLatch countDownLatch) { 173 mWifiService = wifiService; 174 mCountDownLatch = countDownLatch; 175 } 176 177 @Override onStart(WifiConnectedSessionInfo sessionInfo)178 public void onStart(WifiConnectedSessionInfo sessionInfo) { 179 mSessionId = sessionInfo.getSessionId(); 180 mCountDownLatch.countDown(); 181 } 182 @Override onStop(int sessionId)183 public void onStop(int sessionId) { 184 // clear the external scorer on disconnect. 185 mWifiService.clearWifiConnectedNetworkScorer(); 186 } 187 @Override onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)188 public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) { 189 mScoreUpdateObserver = observerImpl; 190 mCountDownLatch.countDown(); 191 } 192 getSessionId()193 public Integer getSessionId() { 194 return mSessionId; 195 } 196 getScoreUpdateObserver()197 public IScoreUpdateObserver getScoreUpdateObserver() { 198 return mScoreUpdateObserver; 199 } 200 } 201 WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, Context context, WifiGlobals wifiGlobals, WifiThreadRunner wifiThreadRunner)202 WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, Context context, 203 WifiGlobals wifiGlobals, WifiThreadRunner wifiThreadRunner) { 204 mWifiGlobals = wifiGlobals; 205 mWifiThreadRunner = wifiThreadRunner; 206 mActiveModeWarden = wifiInjector.getActiveModeWarden(); 207 mWifiLockManager = wifiInjector.getWifiLockManager(); 208 mWifiNetworkSuggestionsManager = wifiInjector.getWifiNetworkSuggestionsManager(); 209 mWifiConfigManager = wifiInjector.getWifiConfigManager(); 210 mWifiNative = wifiInjector.getWifiNative(); 211 mCoexManager = wifiInjector.getCoexManager(); 212 mWifiCountryCode = wifiInjector.getWifiCountryCode(); 213 mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); 214 mWifiService = wifiService; 215 mContext = context; 216 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 217 mWifiCarrierInfoManager = wifiInjector.getWifiCarrierInfoManager(); 218 mWifiNetworkFactory = wifiInjector.getWifiNetworkFactory(); 219 mSelfRecovery = wifiInjector.getSelfRecovery(); 220 mWifiApConfigStore = wifiInjector.getWifiApConfigStore(); 221 mScanRequestProxy = wifiInjector.getScanRequestProxy(); 222 } 223 224 @Override onCommand(String cmd)225 public int onCommand(String cmd) { 226 // Treat no command as help command. 227 if (cmd == null || cmd.equals("")) { 228 cmd = "help"; 229 } 230 // Explicit exclusion from root permission 231 if (ArrayUtils.indexOf(NON_PRIVILEGED_COMMANDS, cmd) == -1) { 232 final int uid = Binder.getCallingUid(); 233 if (uid != Process.ROOT_UID) { 234 throw new SecurityException( 235 "Uid " + uid + " does not have access to " + cmd + " wifi command " 236 + "(or such command doesn't exist)"); 237 } 238 } 239 240 final PrintWriter pw = getOutPrintWriter(); 241 try { 242 switch (cmd) { 243 case "set-ipreach-disconnect": { 244 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 245 mWifiGlobals.setIpReachabilityDisconnectEnabled(enabled); 246 return 0; 247 } 248 case "get-ipreach-disconnect": 249 pw.println("IPREACH_DISCONNECT state is " 250 + mWifiGlobals.getIpReachabilityDisconnectEnabled()); 251 return 0; 252 case "set-poll-rssi-interval-msecs": 253 int newPollIntervalMsecs; 254 try { 255 newPollIntervalMsecs = Integer.parseInt(getNextArgRequired()); 256 } catch (NumberFormatException e) { 257 pw.println( 258 "Invalid argument to 'set-poll-rssi-interval-msecs' " 259 + "- must be a positive integer"); 260 return -1; 261 } 262 263 if (newPollIntervalMsecs < 1) { 264 pw.println( 265 "Invalid argument to 'set-poll-rssi-interval-msecs' " 266 + "- must be a positive integer"); 267 return -1; 268 } 269 270 mWifiGlobals.setPollRssiIntervalMillis(newPollIntervalMsecs); 271 return 0; 272 case "get-poll-rssi-interval-msecs": 273 pw.println("WifiGlobals.getPollRssiIntervalMillis() = " 274 + mWifiGlobals.getPollRssiIntervalMillis()); 275 return 0; 276 case "force-hi-perf-mode": { 277 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 278 if (!mWifiLockManager.forceHiPerfMode(enabled)) { 279 pw.println("Command execution failed"); 280 } 281 return 0; 282 } 283 case "force-low-latency-mode": { 284 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 285 if (!mWifiLockManager.forceLowLatencyMode(enabled)) { 286 pw.println("Command execution failed"); 287 } 288 return 0; 289 } 290 case "network-suggestions-set-user-approved": { 291 String packageName = getNextArgRequired(); 292 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 293 mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(approved, 294 Binder.getCallingUid(), packageName); 295 return 0; 296 } 297 case "network-suggestions-has-user-approved": { 298 String packageName = getNextArgRequired(); 299 boolean hasUserApproved = 300 mWifiNetworkSuggestionsManager.hasUserApprovedForApp(packageName); 301 pw.println(hasUserApproved ? "yes" : "no"); 302 return 0; 303 } 304 case "imsi-protection-exemption-set-user-approved-for-carrier": { 305 String arg1 = getNextArgRequired(); 306 int carrierId = -1; 307 try { 308 carrierId = Integer.parseInt(arg1); 309 } catch (NumberFormatException e) { 310 pw.println("Invalid argument to " 311 + "'imsi-protection-exemption-set-user-approved-for-carrier' " 312 + "- carrierId must be an Integer"); 313 return -1; 314 } 315 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 316 mWifiCarrierInfoManager 317 .setHasUserApprovedImsiPrivacyExemptionForCarrier(approved, carrierId); 318 return 0; 319 } 320 case "imsi-protection-exemption-has-user-approved-for-carrier": { 321 String arg1 = getNextArgRequired(); 322 int carrierId = -1; 323 try { 324 carrierId = Integer.parseInt(arg1); 325 } catch (NumberFormatException e) { 326 pw.println("Invalid argument to " 327 + "'imsi-protection-exemption-has-user-approved-for-carrier' " 328 + "- 'carrierId' must be an Integer"); 329 return -1; 330 } 331 boolean hasUserApproved = mWifiCarrierInfoManager 332 .hasUserApprovedImsiPrivacyExemptionForCarrier(carrierId); 333 pw.println(hasUserApproved ? "yes" : "no"); 334 return 0; 335 } 336 case "imsi-protection-exemption-clear-user-approved-for-carrier": { 337 String arg1 = getNextArgRequired(); 338 int carrierId = -1; 339 try { 340 carrierId = Integer.parseInt(arg1); 341 } catch (NumberFormatException e) { 342 pw.println("Invalid argument to " 343 + "'imsi-protection-exemption-clear-user-approved-for-carrier' " 344 + "- 'carrierId' must be an Integer"); 345 return -1; 346 } 347 mWifiCarrierInfoManager.clearImsiPrivacyExemptionForCarrier(carrierId); 348 return 0; 349 } 350 case "network-requests-remove-user-approved-access-points": { 351 String packageName = getNextArgRequired(); 352 mWifiNetworkFactory.removeUserApprovedAccessPointsForApp(packageName); 353 return 0; 354 } 355 case "clear-user-disabled-networks": { 356 mWifiConfigManager.clearUserTemporarilyDisabledList(); 357 return 0; 358 } 359 case "send-link-probe": { 360 return sendLinkProbe(pw); 361 } 362 case "force-softap-band": { 363 boolean forceBandEnabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 364 if (forceBandEnabled) { 365 String forcedBand = getNextArgRequired(); 366 if (forcedBand.equals("2")) { 367 mWifiApConfigStore.enableForceSoftApBandOrChannel( 368 SoftApConfiguration.BAND_2GHZ, 0); 369 } else if (forcedBand.equals("5")) { 370 mWifiApConfigStore.enableForceSoftApBandOrChannel( 371 SoftApConfiguration.BAND_5GHZ, 0); 372 } else if (forcedBand.equals("6")) { 373 mWifiApConfigStore.enableForceSoftApBandOrChannel( 374 SoftApConfiguration.BAND_6GHZ, 0); 375 } else { 376 pw.println("Invalid argument to 'force-softap-band enabled' " 377 + "- must be a valid band integer (2|5|6)"); 378 return -1; 379 } 380 return 0; 381 } else { 382 mWifiApConfigStore.disableForceSoftApBandOrChannel(); 383 return 0; 384 } 385 386 } 387 case "force-softap-channel": { 388 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 389 if (enabled) { 390 int apChannelMHz; 391 try { 392 apChannelMHz = Integer.parseInt(getNextArgRequired()); 393 } catch (NumberFormatException e) { 394 pw.println("Invalid argument to 'force-softap-channel enabled' " 395 + "- must be a positive integer"); 396 return -1; 397 } 398 int apChannel = ScanResult.convertFrequencyMhzToChannelIfSupported( 399 apChannelMHz); 400 int band = ApConfigUtil.convertFrequencyToBand(apChannelMHz); 401 pw.println("channel: " + apChannel + " band: " + band); 402 if (apChannel == -1 || band == -1) { 403 pw.println("Invalid argument to 'force-softap-channel enabled' " 404 + "- must be a valid WLAN channel"); 405 return -1; 406 } 407 boolean isTemporarilyEnablingWifiNeeded = mWifiService.getWifiEnabledState() 408 != WIFI_STATE_ENABLED; 409 if (isTemporarilyEnablingWifiNeeded) { 410 waitForWifiEnabled(true); 411 } 412 // Following calls will fail if wifi is not enabled 413 boolean isValidChannel = isApChannelMHzValid(pw, apChannelMHz); 414 if (isTemporarilyEnablingWifiNeeded) { 415 waitForWifiEnabled(false); 416 } 417 if (!isValidChannel 418 || (band == SoftApConfiguration.BAND_5GHZ 419 && !mWifiService.is5GHzBandSupported()) 420 || (band == SoftApConfiguration.BAND_6GHZ 421 && !mWifiService.is6GHzBandSupported()) 422 || (band == SoftApConfiguration.BAND_60GHZ 423 && !mWifiService.is60GHzBandSupported())) { 424 pw.println("Invalid argument to 'force-softap-channel enabled' " 425 + "- must be a valid WLAN channel" 426 + " in a band supported by the device"); 427 return -1; 428 } 429 mWifiApConfigStore.enableForceSoftApBandOrChannel(band, apChannel); 430 return 0; 431 } else { 432 mWifiApConfigStore.disableForceSoftApBandOrChannel(); 433 return 0; 434 } 435 } 436 case "start-softap": { 437 CountDownLatch countDownLatch = new CountDownLatch(1); 438 ISoftApCallback.Stub softApCallback = new ISoftApCallback.Stub() { 439 @Override 440 public void onStateChanged(int state, int failureReason) { 441 pw.println("onStateChanged with state: " + state 442 + " failure reason: " + failureReason); 443 mSapState = state; 444 if (state == WifiManager.WIFI_AP_STATE_ENABLED) { 445 pw.println(" SAP is enabled successfully"); 446 // Skip countDown() and wait for onInfoChanged() which has 447 // the confirmed softAp channel information 448 } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { 449 pw.println(" SAP is disabled"); 450 } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { 451 pw.println(" SAP failed to start"); 452 countDownLatch.countDown(); 453 } 454 } 455 456 @Override 457 public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, 458 Map<String, List<WifiClient>> clients, boolean isBridged, 459 boolean isRegistration) { 460 if (mSapState == WifiManager.WIFI_AP_STATE_ENABLED) { 461 countDownLatch.countDown(); 462 } 463 } 464 465 @Override 466 public void onCapabilityChanged(SoftApCapability capability) { 467 pw.println("onCapabilityChanged " + capability); 468 } 469 470 @Override 471 public void onBlockedClientConnecting(WifiClient client, int reason) { 472 } 473 474 }; 475 mWifiService.registerSoftApCallback(softApCallback); 476 SoftApConfiguration config = buildSoftApConfiguration(pw); 477 if (!mWifiService.startTetheredHotspot(config, SHELL_PACKAGE_NAME)) { 478 pw.println("Soft AP failed to start. Please check config parameters"); 479 } 480 // Wait for softap to start and complete callback 481 countDownLatch.await(3000, TimeUnit.MILLISECONDS); 482 mWifiService.unregisterSoftApCallback(softApCallback); 483 return 0; 484 } 485 case "stop-softap": { 486 if (mWifiService.stopSoftAp()) { 487 pw.println("Soft AP stopped successfully"); 488 } else { 489 pw.println("Soft AP failed to stop"); 490 } 491 return 0; 492 } 493 case "force-country-code": { 494 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 495 if (enabled) { 496 String countryCode = getNextArgRequired(); 497 if (!WifiCountryCode.isValid(countryCode)) { 498 pw.println("Invalid argument: Country code must be a 2-Character" 499 + " alphanumeric code. But got countryCode " + countryCode 500 + " instead"); 501 return -1; 502 } 503 mWifiCountryCode.setOverrideCountryCode(countryCode); 504 return 0; 505 } else { 506 mWifiCountryCode.clearOverrideCountryCode(); 507 return 0; 508 } 509 } 510 case "get-country-code": { 511 pw.println("Wifi Country Code = " 512 + mWifiCountryCode.getCountryCode()); 513 return 0; 514 } 515 case "set-wifi-watchdog": { 516 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 517 mWifiLastResortWatchdog.setWifiWatchdogFeature(enabled); 518 return 0; 519 } 520 case "get-wifi-watchdog": { 521 pw.println("wifi watchdog state is " 522 + mWifiLastResortWatchdog.getWifiWatchdogFeature()); 523 return 0; 524 } 525 case "set-wifi-enabled": { 526 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 527 mWifiService.setWifiEnabled(SHELL_PACKAGE_NAME, enabled); 528 return 0; 529 } 530 case "set-scan-always-available": { 531 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 532 mWifiService.setScanAlwaysAvailable(enabled, SHELL_PACKAGE_NAME); 533 return 0; 534 } 535 case "get-softap-supported-features": 536 // This command is used for vts to check softap supported features. 537 if (ApConfigUtil.isAcsSupported(mContext)) { 538 pw.println("wifi_softap_acs_supported"); 539 } 540 if (ApConfigUtil.isWpa3SaeSupported(mContext)) { 541 pw.println("wifi_softap_wpa3_sae_supported"); 542 } 543 if ((mWifiService.getSupportedFeatures() 544 & WifiManager.WIFI_FEATURE_BRIDGED_AP) 545 == WifiManager.WIFI_FEATURE_BRIDGED_AP) { 546 pw.println("wifi_softap_bridged_ap_supported"); 547 } 548 if ((mWifiService.getSupportedFeatures() 549 & WifiManager.WIFI_FEATURE_STA_BRIDGED_AP) 550 == WifiManager.WIFI_FEATURE_STA_BRIDGED_AP) { 551 pw.println("wifi_softap_bridged_ap_with_sta_supported"); 552 } 553 return 0; 554 case "settings-reset": 555 mWifiNative.stopFakingScanDetails(); 556 mWifiNative.resetFakeScanDetails(); 557 mWifiService.factoryReset(SHELL_PACKAGE_NAME); 558 return 0; 559 case "list-scan-results": 560 List<ScanResult> scanResults = 561 mWifiService.getScanResults(SHELL_PACKAGE_NAME, null); 562 if (scanResults.isEmpty()) { 563 pw.println("No scan results"); 564 } else { 565 ScanResultUtil.dumpScanResults(pw, scanResults, 566 SystemClock.elapsedRealtime()); 567 } 568 return 0; 569 case "start-scan": 570 mWifiService.startScan(SHELL_PACKAGE_NAME, null); 571 return 0; 572 case "list-networks": 573 ParceledListSlice<WifiConfiguration> networks = 574 mWifiService.getConfiguredNetworks(SHELL_PACKAGE_NAME, null, false); 575 if (networks == null || networks.getList().isEmpty()) { 576 pw.println("No networks"); 577 } else { 578 pw.println("Network Id SSID Security type"); 579 for (WifiConfiguration network : networks.getList()) { 580 String securityType = network.getSecurityParamsList().stream() 581 .map(p -> WifiConfiguration.getSecurityTypeName( 582 p.getSecurityType()) 583 + (p.isAddedByAutoUpgrade() ? "^" : "")) 584 .collect(Collectors.joining("/")); 585 pw.println(String.format("%-12d %-32s %-4s", 586 network.networkId, WifiInfo.sanitizeSsid(network.SSID), 587 securityType)); 588 } 589 } 590 return 0; 591 case "connect-network": { 592 CountDownLatch countDownLatch = new CountDownLatch(1); 593 IActionListener.Stub actionListener = new IActionListener.Stub() { 594 @Override 595 public void onSuccess() throws RemoteException { 596 pw.println("Connection initiated "); 597 countDownLatch.countDown(); 598 } 599 600 @Override 601 public void onFailure(int i) throws RemoteException { 602 pw.println("Connection failed"); 603 countDownLatch.countDown(); 604 } 605 }; 606 WifiConfiguration config = buildWifiConfiguration(pw); 607 mWifiService.connect(config, -1, actionListener); 608 // wait for status. 609 countDownLatch.await(500, TimeUnit.MILLISECONDS); 610 setAutoJoin(pw, config.SSID, config.allowAutojoin); 611 return 0; 612 } 613 case "add-network": { 614 CountDownLatch countDownLatch = new CountDownLatch(1); 615 IActionListener.Stub actionListener = new IActionListener.Stub() { 616 @Override 617 public void onSuccess() throws RemoteException { 618 pw.println("Save successful"); 619 countDownLatch.countDown(); 620 } 621 622 @Override 623 public void onFailure(int i) throws RemoteException { 624 pw.println("Save failed"); 625 countDownLatch.countDown(); 626 } 627 }; 628 WifiConfiguration config = buildWifiConfiguration(pw); 629 mWifiService.save(config, actionListener); 630 // wait for status. 631 countDownLatch.await(500, TimeUnit.MILLISECONDS); 632 setAutoJoin(pw, config.SSID, config.allowAutojoin); 633 return 0; 634 } 635 case "forget-network": { 636 String networkId = getNextArgRequired(); 637 CountDownLatch countDownLatch = new CountDownLatch(1); 638 IActionListener.Stub actionListener = new IActionListener.Stub() { 639 @Override 640 public void onSuccess() throws RemoteException { 641 pw.println("Forget successful"); 642 countDownLatch.countDown(); 643 } 644 645 @Override 646 public void onFailure(int i) throws RemoteException { 647 pw.println("Forget failed"); 648 countDownLatch.countDown(); 649 } 650 }; 651 mWifiService.forget(Integer.parseInt(networkId), actionListener); 652 // wait for status. 653 countDownLatch.await(500, TimeUnit.MILLISECONDS); 654 return 0; 655 } 656 case "pmksa-flush": { 657 String networkId = getNextArgRequired(); 658 int netId = Integer.parseInt(networkId); 659 WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId); 660 if (config == null) { 661 pw.println("No Wifi config corresponding to networkId: " + netId); 662 return -1; 663 } 664 mWifiNative.removeNetworkCachedData(netId); 665 return 0; 666 } 667 case "status": 668 printStatus(pw); 669 return 0; 670 case "set-verbose-logging": { 671 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 672 mWifiService.enableVerboseLogging(enabled ? 1 : 0); 673 return 0; 674 } 675 case "is-verbose-logging": { 676 int enabled = mWifiService.getVerboseLoggingLevel(); 677 pw.println(enabled > 0 ? "enabled" : "disabled"); 678 return 0; 679 } 680 case "start-restricting-auto-join-to-subscription-id": { 681 if (!SdkLevel.isAtLeastS()) { 682 pw.println("This feature is only supported on SdkLevel S or later."); 683 return -1; 684 } 685 int subId = Integer.parseInt(getNextArgRequired()); 686 mWifiService.startRestrictingAutoJoinToSubscriptionId(subId); 687 return 0; 688 } 689 case "stop-restricting-auto-join-to-subscription-id": { 690 if (!SdkLevel.isAtLeastS()) { 691 pw.println("This feature is only supported on SdkLevel S or later."); 692 return -1; 693 } 694 mWifiService.stopRestrictingAutoJoinToSubscriptionId(); 695 return 0; 696 } 697 case "add-suggestion": { 698 WifiNetworkSuggestion suggestion = buildSuggestion(pw); 699 if (suggestion == null) { 700 pw.println("Invalid network suggestion parameter"); 701 return -1; 702 } 703 int errorCode = mWifiService.addNetworkSuggestions( 704 Arrays.asList(suggestion), SHELL_PACKAGE_NAME, null); 705 if (errorCode != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 706 pw.println("Add network suggestion failed with error code: " + errorCode); 707 return -1; 708 } 709 // untrusted/oem-paid networks need a corresponding NetworkRequest. 710 if (suggestion.isUntrusted() 711 || (SdkLevel.isAtLeastS() 712 && (suggestion.isOemPaid() || suggestion.isOemPrivate()))) { 713 NetworkRequest.Builder networkRequestBuilder = 714 new NetworkRequest.Builder() 715 .addTransportType(TRANSPORT_WIFI); 716 if (suggestion.isUntrusted()) { 717 networkRequestBuilder.removeCapability(NET_CAPABILITY_TRUSTED); 718 } 719 if (SdkLevel.isAtLeastS()) { 720 if (suggestion.isOemPaid()) { 721 networkRequestBuilder.addCapability(NET_CAPABILITY_OEM_PAID); 722 } 723 if (suggestion.isOemPrivate()) { 724 networkRequestBuilder.addCapability(NET_CAPABILITY_OEM_PRIVATE); 725 } 726 } 727 NetworkRequest networkRequest = networkRequestBuilder.build(); 728 ConnectivityManager.NetworkCallback networkCallback = 729 new ConnectivityManager.NetworkCallback(); 730 pw.println("Adding request: " + networkRequest); 731 mConnectivityManager.requestNetwork(networkRequest, networkCallback); 732 sActiveRequests.put( 733 suggestion.getSsid(), Pair.create(networkRequest, networkCallback)); 734 } 735 return 0; 736 } 737 case "remove-suggestion": { 738 String ssid = getNextArgRequired(); 739 List<WifiNetworkSuggestion> suggestions = 740 mWifiService.getNetworkSuggestions(SHELL_PACKAGE_NAME); 741 WifiNetworkSuggestion suggestion = suggestions.stream() 742 .filter(s -> s.getSsid().equals(ssid)) 743 .findAny() 744 .orElse(null); 745 if (suggestion == null) { 746 pw.println("No matching suggestion to remove"); 747 return -1; 748 } 749 mWifiService.removeNetworkSuggestions( 750 Arrays.asList(suggestion), SHELL_PACKAGE_NAME); 751 // untrusted/oem-paid networks need a corresponding NetworkRequest. 752 if (suggestion.isUntrusted() 753 || (SdkLevel.isAtLeastS() 754 && (suggestion.isOemPaid() || suggestion.isOemPrivate()))) { 755 Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc = 756 sActiveRequests.remove(suggestion.getSsid()); 757 if (nrAndNc == null) { 758 pw.println("No matching request to remove"); 759 return -1; 760 } 761 pw.println("Removing request: " + nrAndNc.first); 762 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 763 } 764 return 0; 765 } 766 case "remove-all-suggestions": 767 mWifiService.removeNetworkSuggestions( 768 Collections.emptyList(), SHELL_PACKAGE_NAME); 769 return 0; 770 case "list-suggestions": { 771 List<WifiNetworkSuggestion> suggestions = 772 mWifiService.getNetworkSuggestions(SHELL_PACKAGE_NAME); 773 printWifiNetworkSuggestions(pw, suggestions); 774 return 0; 775 } 776 case "list-all-suggestions": { 777 Set<WifiNetworkSuggestion> suggestions = 778 mWifiNetworkSuggestionsManager.getAllNetworkSuggestions(); 779 printWifiNetworkSuggestions(pw, suggestions); 780 return 0; 781 } 782 case "list-suggestions-from-app": { 783 String packageName = getNextArgRequired(); 784 List<WifiNetworkSuggestion> suggestions = 785 mWifiService.getNetworkSuggestions(packageName); 786 printWifiNetworkSuggestions(pw, suggestions); 787 return 0; 788 } 789 case "add-request": { 790 NetworkRequest networkRequest = buildNetworkRequest(pw); 791 ConnectivityManager.NetworkCallback networkCallback = 792 new ConnectivityManager.NetworkCallback(); 793 pw.println("Adding request: " + networkRequest); 794 mConnectivityManager.requestNetwork(networkRequest, networkCallback); 795 String ssid = getAllArgs()[1]; 796 sActiveRequests.put(ssid, Pair.create(networkRequest, networkCallback)); 797 return 0; 798 } 799 case "remove-request": { 800 String ssid = getNextArgRequired(); 801 Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc = 802 sActiveRequests.remove(ssid); 803 if (nrAndNc == null) { 804 pw.println("No matching request to remove"); 805 return -1; 806 } 807 pw.println("Removing request: " + nrAndNc.first); 808 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 809 return 0; 810 } 811 case "remove-all-requests": 812 if (sActiveRequests.isEmpty()) { 813 pw.println("No active requests"); 814 return -1; 815 } 816 for (Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc 817 : sActiveRequests.values()) { 818 pw.println("Removing request: " + nrAndNc.first); 819 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 820 } 821 sActiveRequests.clear(); 822 return 0; 823 case "list-requests": 824 if (sActiveRequests.isEmpty()) { 825 pw.println("No active requests"); 826 } else { 827 pw.println("SSID NetworkRequest"); 828 for (Map.Entry<String, 829 Pair<NetworkRequest, ConnectivityManager.NetworkCallback>> entry : 830 sActiveRequests.entrySet()) { 831 pw.println(String.format("%-32s %-4s", 832 entry.getKey(), entry.getValue().first)); 833 } 834 } 835 return 0; 836 case "network-requests-set-user-approved": { 837 String packageName = getNextArgRequired(); 838 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 839 mWifiNetworkFactory.setUserApprovedApp(packageName, approved); 840 return 0; 841 } 842 case "network-requests-has-user-approved": { 843 String packageName = getNextArgRequired(); 844 boolean hasUserApproved = mWifiNetworkFactory.hasUserApprovedApp(packageName); 845 pw.println(hasUserApproved ? "yes" : "no"); 846 return 0; 847 } 848 case "set-coex-cell-channels": { 849 if (!SdkLevel.isAtLeastS()) { 850 return handleDefaultCommands(cmd); 851 } 852 mCoexManager.setMockCellChannels(buildCoexCellChannels()); 853 return 0; 854 } 855 case "reset-coex-cell-channels": { 856 if (!SdkLevel.isAtLeastS()) { 857 return handleDefaultCommands(cmd); 858 } 859 mCoexManager.resetMockCellChannels(); 860 return 0; 861 } 862 case "get-coex-cell-channels": { 863 if (!SdkLevel.isAtLeastS()) { 864 return handleDefaultCommands(cmd); 865 } 866 pw.println("Cell channels: " + mCoexManager.getCellChannels()); 867 return 0; 868 } 869 case "set-connected-score": { 870 int score = Integer.parseInt(getNextArgRequired()); 871 CountDownLatch countDownLatch = new CountDownLatch(2); 872 mWifiService.clearWifiConnectedNetworkScorer(); // clear any previous scorer 873 WifiScorer connectedScorer = new WifiScorer(mWifiService, countDownLatch); 874 if (mWifiService.setWifiConnectedNetworkScorer(new Binder(), connectedScorer)) { 875 // wait for retrieving the session id & score observer. 876 countDownLatch.await(1000, TimeUnit.MILLISECONDS); 877 } 878 if (connectedScorer.getSessionId() == null 879 || connectedScorer.getScoreUpdateObserver() == null) { 880 pw.println("Did not receive session id and/or the score update observer. " 881 + "Is the device connected to a wifi network?"); 882 mWifiService.clearWifiConnectedNetworkScorer(); 883 return -1; 884 } 885 pw.println("Updating score: " + score + " for session id: " 886 + connectedScorer.getSessionId()); 887 try { 888 connectedScorer.getScoreUpdateObserver().notifyScoreUpdate( 889 connectedScorer.getSessionId(), score); 890 } catch (RemoteException e) { 891 pw.println("Failed to send the score update"); 892 mWifiService.clearWifiConnectedNetworkScorer(); 893 return -1; 894 } 895 return 0; 896 } 897 case "reset-connected-score": { 898 mWifiService.clearWifiConnectedNetworkScorer(); // clear any previous scorer 899 return 0; 900 } 901 case "network-suggestions-set-as-carrier-provider": { 902 String packageName = getNextArgRequired(); 903 boolean enabled = getNextArgRequiredTrueOrFalse("yes", "no"); 904 mWifiNetworkSuggestionsManager 905 .setAppWorkingAsCrossCarrierProvider(packageName, enabled); 906 return 0; 907 } 908 case "is-network-suggestions-set-as-carrier-provider": { 909 String packageName = getNextArgRequired(); 910 pw.println(mWifiNetworkSuggestionsManager 911 .isAppWorkingAsCrossCarrierProvider(packageName) ? "yes" : "no"); 912 return 0; 913 } 914 case "remove-shell-app-from-suggestion_database <packageName>": { 915 String packageName = getNextArgRequired(); 916 mWifiNetworkSuggestionsManager.removeApp(packageName); 917 return 0; 918 } 919 case "set-emergency-callback-mode": { 920 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 921 mActiveModeWarden.emergencyCallbackModeChanged(enabled); 922 return 0; 923 } 924 case "set-emergency-call-state": { 925 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 926 mActiveModeWarden.emergencyCallStateChanged(enabled); 927 return 0; 928 } 929 case "trigger-recovery": { 930 mSelfRecovery.trigger(REASON_API_CALL); 931 return 0; 932 } 933 case "add-fake-scan": { 934 String ssid = getNextArgRequired(); 935 String bssid = getNextArgRequired(); 936 String capabilities = getNextArgRequired(); 937 int frequency; 938 int dbm; 939 String freqStr = getNextArgRequired(); 940 try { 941 frequency = Integer.parseInt(freqStr); 942 } catch (NumberFormatException e) { 943 pw.println( 944 "Invalid frequency argument to 'add-fake-scan' " 945 + "- must be an integer: " + freqStr); 946 return -1; 947 } 948 if (frequency <= 0) { 949 pw.println("Invalid frequency argument to 'add-fake-scan' - must be a " 950 + "positive integer: " + freqStr); 951 } 952 String dbmString = getNextArgRequired(); 953 try { 954 dbm = Integer.parseInt(dbmString); 955 } catch (NumberFormatException e) { 956 pw.println( 957 "Invalid dbm argument to 'add-fake-scan' " 958 + "- must be an integer: " + dbmString); 959 return -1; 960 } 961 ScanResult.InformationElement ieSSid = new ScanResult.InformationElement( 962 ScanResult.InformationElement.EID_SSID, 963 0, 964 ssid.getBytes(StandardCharsets.UTF_8)); 965 ScanResult.InformationElement[] ies = 966 new ScanResult.InformationElement[]{ieSSid}; 967 ScanDetail sd = new ScanDetail(new NetworkDetail(bssid, ies, null, frequency), 968 WifiSsid.createFromAsciiEncoded(ssid), bssid, capabilities, dbm, 969 frequency, SystemClock.elapsedRealtime() * 1000, ies, null, null); 970 mWifiNative.addFakeScanDetail(sd); 971 return 0; 972 } 973 case "reset-fake-scans": 974 mWifiNative.resetFakeScanDetails(); 975 return 0; 976 case "start-faking-scans": 977 mWifiNative.startFakingScanDetails(); 978 mWifiService.startScan(SHELL_PACKAGE_NAME, null); // to trigger update 979 return 0; 980 case "stop-faking-scans": 981 mWifiNative.stopFakingScanDetails(); 982 return 0; 983 case "enable-scanning": 984 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 985 boolean hiddenEnabled = false; 986 String option = getNextOption(); 987 if (option != null) { 988 if (option.equals("-h")) { 989 hiddenEnabled = true; 990 } else { 991 pw.println("Invalid argument to 'enable-scanning' " 992 + "- only allowed option is '-h'"); 993 return -1; 994 } 995 } 996 mScanRequestProxy.enableScanning(enabled, hiddenEnabled); 997 return 0; 998 default: 999 return handleDefaultCommands(cmd); 1000 } 1001 } catch (IllegalArgumentException e) { 1002 pw.println("Invalid args for " + cmd + ": " + e); 1003 return -1; 1004 } catch (Exception e) { 1005 pw.println("Exception while executing WifiShellCommand: "); 1006 e.printStackTrace(pw); 1007 return -1; 1008 } 1009 } 1010 getNextArgRequiredTrueOrFalse(String trueString, String falseString)1011 private boolean getNextArgRequiredTrueOrFalse(String trueString, String falseString) 1012 throws IllegalArgumentException { 1013 String nextArg = getNextArgRequired(); 1014 if (trueString.equals(nextArg)) { 1015 return true; 1016 } else if (falseString.equals(nextArg)) { 1017 return false; 1018 } else { 1019 throw new IllegalArgumentException("Expected '" + trueString + "' or '" + falseString 1020 + "' as next arg but got '" + nextArg + "'"); 1021 } 1022 } 1023 buildWifiConfiguration(PrintWriter pw)1024 private WifiConfiguration buildWifiConfiguration(PrintWriter pw) { 1025 String ssid = getNextArgRequired(); 1026 String type = getNextArgRequired(); 1027 WifiConfiguration configuration = new WifiConfiguration(); 1028 configuration.SSID = "\"" + ssid + "\""; 1029 if (TextUtils.equals(type, "wpa3")) { 1030 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 1031 configuration.preSharedKey = "\"" + getNextArgRequired() + "\""; 1032 } else if (TextUtils.equals(type, "wpa2")) { 1033 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 1034 configuration.preSharedKey = "\"" + getNextArgRequired() + "\""; 1035 } else if (TextUtils.equals(type, "owe")) { 1036 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 1037 } else if (TextUtils.equals(type, "open")) { 1038 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 1039 } else { 1040 throw new IllegalArgumentException("Unknown network type " + type); 1041 } 1042 String option = getNextOption(); 1043 while (option != null) { 1044 if (option.equals("-m")) { 1045 configuration.meteredOverride = METERED_OVERRIDE_METERED; 1046 } else if (option.equals("-d")) { 1047 configuration.allowAutojoin = false; 1048 } else if (option.equals("-b")) { 1049 configuration.BSSID = getNextArgRequired(); 1050 } else if (option.equals("-r")) { 1051 String macRandomizationScheme = getNextArgRequired(); 1052 if (macRandomizationScheme.equals("auto")) { 1053 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; 1054 } else if (macRandomizationScheme.equals("none")) { 1055 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; 1056 } else if (macRandomizationScheme.equals("persistent")) { 1057 configuration.macRandomizationSetting = 1058 WifiConfiguration.RANDOMIZATION_PERSISTENT; 1059 } else if (macRandomizationScheme.equals("non_persistent")) { 1060 if (SdkLevel.isAtLeastS()) { 1061 configuration.macRandomizationSetting = 1062 WifiConfiguration.RANDOMIZATION_NON_PERSISTENT; 1063 } else { 1064 throw new IllegalArgumentException( 1065 "-r non_persistent MAC randomization not supported before S"); 1066 } 1067 } 1068 } else if (option.equals("-h")) { 1069 configuration.hiddenSSID = true; 1070 } else if (option.equals("-p")) { 1071 configuration.shared = false; 1072 } else { 1073 pw.println("Ignoring unknown option " + option); 1074 } 1075 option = getNextOption(); 1076 } 1077 return configuration; 1078 } 1079 buildSoftApConfiguration(PrintWriter pw)1080 private SoftApConfiguration buildSoftApConfiguration(PrintWriter pw) { 1081 String ssid = getNextArgRequired(); 1082 String type = getNextArgRequired(); 1083 SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); 1084 configBuilder.setSsid(ssid); 1085 if (TextUtils.equals(type, "wpa2")) { 1086 configBuilder.setPassphrase(getNextArgRequired(), 1087 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 1088 } else if (TextUtils.equals(type, "wpa3")) { 1089 configBuilder.setPassphrase(getNextArgRequired(), 1090 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); 1091 } else if (TextUtils.equals(type, "wpa3_transition")) { 1092 configBuilder.setPassphrase(getNextArgRequired(), 1093 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); 1094 } else if (TextUtils.equals(type, "open")) { 1095 configBuilder.setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN); 1096 } else { 1097 throw new IllegalArgumentException("Unknown network type " + type); 1098 } 1099 String option = getNextOption(); 1100 while (option != null) { 1101 if (option.equals("-b")) { 1102 String preferredBand = getNextArgRequired(); 1103 if (preferredBand.equals("2")) { 1104 configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); 1105 } else if (preferredBand.equals("5")) { 1106 configBuilder.setBand(SoftApConfiguration.BAND_5GHZ); 1107 } else if (preferredBand.equals("6")) { 1108 configBuilder.setBand(SoftApConfiguration.BAND_6GHZ); 1109 } else if (preferredBand.equals("any")) { 1110 configBuilder.setBand(SoftApConfiguration.BAND_2GHZ 1111 | SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_6GHZ); 1112 } else if (preferredBand.equals("bridged")) { 1113 if (SdkLevel.isAtLeastS()) { 1114 int[] dualBands = new int[] { 1115 SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ}; 1116 configBuilder.setBands(dualBands); 1117 } else { 1118 throw new IllegalArgumentException( 1119 "-b bridged option is not supported before S"); 1120 } 1121 } else { 1122 throw new IllegalArgumentException("Invalid band option " + preferredBand); 1123 } 1124 } else { 1125 pw.println("Ignoring unknown option " + option); 1126 } 1127 option = getNextOption(); 1128 } 1129 return configBuilder.build(); 1130 } 1131 buildSuggestion(PrintWriter pw)1132 private WifiNetworkSuggestion buildSuggestion(PrintWriter pw) { 1133 String ssid = getNextArgRequired(); 1134 String type = getNextArgRequired(); 1135 WifiNetworkSuggestion.Builder suggestionBuilder = 1136 new WifiNetworkSuggestion.Builder(); 1137 suggestionBuilder.setSsid(ssid); 1138 if (TextUtils.equals(type, "wpa3")) { 1139 suggestionBuilder.setWpa3Passphrase(getNextArgRequired()); 1140 } else if (TextUtils.equals(type, "wpa2")) { 1141 suggestionBuilder.setWpa2Passphrase(getNextArgRequired()); 1142 } else if (TextUtils.equals(type, "owe")) { 1143 suggestionBuilder.setIsEnhancedOpen(true); 1144 } else if (TextUtils.equals(type, "open")) { 1145 // nothing to do. 1146 } else { 1147 throw new IllegalArgumentException("Unknown network type " + type); 1148 } 1149 boolean isCarrierMerged = false; 1150 String option = getNextOption(); 1151 while (option != null) { 1152 if (option.equals("-u")) { 1153 suggestionBuilder.setUntrusted(true); 1154 } else if (option.equals("-o")) { 1155 if (SdkLevel.isAtLeastS()) { 1156 suggestionBuilder.setOemPaid(true); 1157 } else { 1158 throw new IllegalArgumentException( 1159 "-o OEM paid suggestions not supported before S"); 1160 } 1161 } else if (option.equals("-p")) { 1162 if (SdkLevel.isAtLeastS()) { 1163 suggestionBuilder.setOemPrivate(true); 1164 } else { 1165 throw new IllegalArgumentException( 1166 "-p OEM private suggestions not supported before S"); 1167 } 1168 } else if (option.equals("-m")) { 1169 suggestionBuilder.setIsMetered(true); 1170 } else if (option.equals("-s")) { 1171 suggestionBuilder.setCredentialSharedWithUser(true); 1172 } else if (option.equals("-d")) { 1173 suggestionBuilder.setIsInitialAutojoinEnabled(false); 1174 } else if (option.equals("-b")) { 1175 suggestionBuilder.setBssid(MacAddress.fromString(getNextArgRequired())); 1176 } else if (option.equals("-r")) { 1177 if (SdkLevel.isAtLeastS()) { 1178 suggestionBuilder.setMacRandomizationSetting( 1179 WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT); 1180 } else { 1181 throw new IllegalArgumentException( 1182 "-r non_persistent MAC randomization not supported before S"); 1183 } 1184 } else if (option.equals("-a")) { 1185 if (SdkLevel.isAtLeastS()) { 1186 isCarrierMerged = true; 1187 } else { 1188 throw new IllegalArgumentException("-a option is not supported before S"); 1189 } 1190 } else if (option.equals("-i")) { 1191 if (SdkLevel.isAtLeastS()) { 1192 int subId = Integer.parseInt(getNextArgRequired()); 1193 suggestionBuilder.setSubscriptionId(subId); 1194 } else { 1195 throw new IllegalArgumentException( 1196 "-i subscription ID option is not supported before S"); 1197 } 1198 } else if (option.equals("-c")) { 1199 int carrierId = Integer.parseInt(getNextArgRequired()); 1200 suggestionBuilder.setCarrierId(carrierId); 1201 } else if (option.equals("-h")) { 1202 suggestionBuilder.setIsHiddenSsid(true); 1203 } else { 1204 pw.println("Ignoring unknown option " + option); 1205 } 1206 option = getNextOption(); 1207 } 1208 WifiNetworkSuggestion suggestion = suggestionBuilder.build(); 1209 if (isCarrierMerged) { 1210 if (suggestion.wifiConfiguration.subscriptionId 1211 == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1212 pw.println("Carrier merged network must have valid subscription Id"); 1213 return null; 1214 } 1215 suggestion.wifiConfiguration.carrierMerged = true; 1216 } 1217 return suggestion; 1218 } 1219 buildNetworkRequest(PrintWriter pw)1220 private NetworkRequest buildNetworkRequest(PrintWriter pw) { 1221 String ssid = getNextArgRequired(); 1222 String type = getNextArgRequired(); 1223 WifiNetworkSpecifier.Builder specifierBuilder = 1224 new WifiNetworkSpecifier.Builder(); 1225 specifierBuilder.setSsid(ssid); 1226 if (TextUtils.equals(type, "wpa3")) { 1227 specifierBuilder.setWpa3Passphrase(getNextArgRequired()); 1228 } else if (TextUtils.equals(type, "wpa3_transition")) { 1229 specifierBuilder.setWpa3Passphrase(getNextArgRequired()); 1230 } else if (TextUtils.equals(type, "wpa2")) { 1231 specifierBuilder.setWpa2Passphrase(getNextArgRequired()); 1232 } else if (TextUtils.equals(type, "owe")) { 1233 specifierBuilder.setIsEnhancedOpen(true); 1234 } else if (TextUtils.equals(type, "open")) { 1235 // nothing to do. 1236 } else { 1237 throw new IllegalArgumentException("Unknown network type " + type); 1238 } 1239 String bssid = null; 1240 String option = getNextOption(); 1241 while (option != null) { 1242 if (option.equals("-b")) { 1243 bssid = getNextArgRequired(); 1244 } else { 1245 pw.println("Ignoring unknown option " + option); 1246 } 1247 option = getNextOption(); 1248 } 1249 1250 // Permission approval bypass is only available to requests with both ssid & bssid set. 1251 // So, find scan result with the best rssi level to set in the request. 1252 if (bssid == null) { 1253 ScanResult matchingScanResult = 1254 mWifiService.getScanResults(SHELL_PACKAGE_NAME, null) 1255 .stream() 1256 .filter(s -> s.SSID.equals(ssid)) 1257 .max(Comparator.comparingInt(s -> s.level)) 1258 .orElse(null); 1259 if (matchingScanResult != null) { 1260 bssid = matchingScanResult.BSSID; 1261 } else { 1262 pw.println("No matching bssid found, request will need UI approval"); 1263 } 1264 } 1265 if (bssid != null) specifierBuilder.setBssid(MacAddress.fromString(bssid)); 1266 return new NetworkRequest.Builder() 1267 .addTransportType(TRANSPORT_WIFI) 1268 .removeCapability(NET_CAPABILITY_INTERNET) 1269 .setNetworkSpecifier(specifierBuilder.build()) 1270 .build(); 1271 } 1272 1273 @NonNull buildCoexCellChannels()1274 private List<CoexUtils.CoexCellChannel> buildCoexCellChannels() { 1275 List<CoexUtils.CoexCellChannel> cellChannels = new ArrayList<>(); 1276 while (getRemainingArgsCount() > 0) { 1277 final @Annotation.NetworkType int rat; 1278 final String ratArg = getNextArgRequired(); 1279 if (TextUtils.equals(ratArg, "lte")) { 1280 rat = TelephonyManager.NETWORK_TYPE_LTE; 1281 } else if (TextUtils.equals(ratArg, "nr")) { 1282 rat = TelephonyManager.NETWORK_TYPE_NR; 1283 } else { 1284 throw new IllegalArgumentException("Unknown rat type " + ratArg); 1285 } 1286 final int band = Integer.parseInt(getNextArgRequired()); 1287 if (band < 1 || band > 261) { 1288 throw new IllegalArgumentException("Band is " + band 1289 + " but should be a value from 1 to 261"); 1290 } 1291 final int downlinkFreqKhz = Integer.parseInt(getNextArgRequired()); 1292 if (downlinkFreqKhz < 0 && downlinkFreqKhz != PhysicalChannelConfig.FREQUENCY_UNKNOWN) { 1293 throw new IllegalArgumentException("Downlink frequency is " + downlinkFreqKhz 1294 + " but should be >= 0 or UNKNOWN: " 1295 + PhysicalChannelConfig.FREQUENCY_UNKNOWN); 1296 } 1297 final int downlinkBandwidthKhz = Integer.parseInt(getNextArgRequired()); 1298 if (downlinkBandwidthKhz <= 0 1299 && downlinkBandwidthKhz != PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN) { 1300 throw new IllegalArgumentException("Downlink bandwidth is " + downlinkBandwidthKhz 1301 + " but should be > 0 or UNKNOWN: " 1302 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN); 1303 } 1304 final int uplinkFreqKhz = Integer.parseInt(getNextArgRequired()); 1305 if (uplinkFreqKhz < 0 && uplinkFreqKhz != PhysicalChannelConfig.FREQUENCY_UNKNOWN) { 1306 throw new IllegalArgumentException("Uplink frequency is " + uplinkFreqKhz 1307 + " but should be >= 0 or UNKNOWN: " 1308 + PhysicalChannelConfig.FREQUENCY_UNKNOWN); 1309 } 1310 final int uplinkBandwidthKhz = Integer.parseInt(getNextArgRequired()); 1311 if (uplinkBandwidthKhz <= 0 1312 && uplinkBandwidthKhz != PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN) { 1313 throw new IllegalArgumentException("Uplink bandwidth is " + uplinkBandwidthKhz 1314 + " but should be > 0 or UNKNOWN: " 1315 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN); 1316 } 1317 cellChannels.add(new CoexUtils.CoexCellChannel(rat, band, 1318 downlinkFreqKhz, downlinkBandwidthKhz, uplinkFreqKhz, uplinkBandwidthKhz, 1319 SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 1320 } 1321 return cellChannels; 1322 } 1323 setAutoJoin(PrintWriter pw, String ssid, boolean allowAutojoin)1324 private void setAutoJoin(PrintWriter pw, String ssid, boolean allowAutojoin) { 1325 // For suggestions, this will work only if the config has already been added 1326 // to WifiConfigManager. 1327 WifiConfiguration retrievedConfig = 1328 mWifiService.getPrivilegedConfiguredNetworks(SHELL_PACKAGE_NAME, null) 1329 .getList() 1330 .stream() 1331 .filter(n -> n.SSID.equals(ssid)) 1332 .findAny() 1333 .orElse(null); 1334 if (retrievedConfig == null) { 1335 pw.println("Cannot retrieve config, autojoin setting skipped."); 1336 return; 1337 } 1338 mWifiService.allowAutojoin(retrievedConfig.networkId, allowAutojoin); 1339 } 1340 sendLinkProbe(PrintWriter pw)1341 private int sendLinkProbe(PrintWriter pw) throws InterruptedException { 1342 // Note: should match WifiNl80211Manager#SEND_MGMT_FRAME_TIMEOUT_MS 1343 final int sendMgmtFrameTimeoutMs = 1000; 1344 1345 ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1); 1346 mWifiThreadRunner.post(() -> 1347 mActiveModeWarden.getPrimaryClientModeManager().probeLink(new LinkProbeCallback() { 1348 @Override 1349 public void onAck(int elapsedTimeMs) { 1350 queue.offer("Link probe succeeded after " + elapsedTimeMs + " ms"); 1351 } 1352 1353 @Override 1354 public void onFailure(int reason) { 1355 queue.offer("Link probe failed with reason " 1356 + LinkProbeCallback.failureReasonToString(reason)); 1357 } 1358 }, -1)); 1359 1360 // block until msg is received, or timed out 1361 String msg = queue.poll(sendMgmtFrameTimeoutMs + 1000, TimeUnit.MILLISECONDS); 1362 if (msg == null) { 1363 pw.println("Link probe timed out"); 1364 } else { 1365 pw.println(msg); 1366 } 1367 return 0; 1368 } 1369 isApChannelMHzValid(PrintWriter pw, int apChannelMHz)1370 private boolean isApChannelMHzValid(PrintWriter pw, int apChannelMHz) { 1371 int[] allowed2gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); 1372 int[] allowed5gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ); 1373 int[] allowed5gDfsFreq = 1374 mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY); 1375 int[] allowed6gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ); 1376 int[] allowed60gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_60_GHZ); 1377 if (allowed2gFreq == null) { 1378 allowed2gFreq = new int[0]; 1379 } 1380 if (allowed5gFreq == null) { 1381 allowed5gFreq = new int[0]; 1382 } 1383 if (allowed5gDfsFreq == null) { 1384 allowed5gDfsFreq = new int[0]; 1385 } 1386 if (allowed6gFreq == null) { 1387 allowed6gFreq = new int[0]; 1388 } 1389 if (allowed60gFreq == null) { 1390 allowed60gFreq = new int[0]; 1391 } 1392 pw.println("2G freq: " + Arrays.toString(allowed2gFreq)); 1393 pw.println("5G freq: " + Arrays.toString(allowed5gFreq)); 1394 pw.println("5G DFS: " + Arrays.toString(allowed5gDfsFreq)); 1395 pw.println("6G freq: " + Arrays.toString(allowed6gFreq)); 1396 pw.println("60G freq: " + Arrays.toString(allowed60gFreq)); 1397 return (Arrays.binarySearch(allowed2gFreq, apChannelMHz) >= 0 1398 || Arrays.binarySearch(allowed5gFreq, apChannelMHz) >= 0 1399 || Arrays.binarySearch(allowed5gDfsFreq, apChannelMHz) >= 0) 1400 || Arrays.binarySearch(allowed6gFreq, apChannelMHz) >= 0 1401 || Arrays.binarySearch(allowed60gFreq, apChannelMHz) >= 0; 1402 } 1403 waitForWifiEnabled(boolean enabled)1404 private void waitForWifiEnabled(boolean enabled) throws InterruptedException { 1405 CountDownLatch countDownLatch = new CountDownLatch(1); 1406 BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { 1407 @Override 1408 public void onReceive(Context context, Intent intent) { 1409 String action = intent.getAction(); 1410 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 1411 int state = mWifiService.getWifiEnabledState(); 1412 if ((enabled && state == WIFI_STATE_ENABLED) 1413 || (!enabled && state == WIFI_STATE_DISABLED)) { 1414 countDownLatch.countDown(); 1415 } 1416 } 1417 } 1418 }; 1419 IntentFilter filter = new IntentFilter(); 1420 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 1421 mContext.registerReceiver(broadcastReceiver, filter); 1422 mWifiService.setWifiEnabled(SHELL_PACKAGE_NAME, enabled); 1423 countDownLatch.await(5000, TimeUnit.MILLISECONDS); 1424 mContext.unregisterReceiver(broadcastReceiver); 1425 } 1426 printWifiInfo(PrintWriter pw, WifiInfo info)1427 private void printWifiInfo(PrintWriter pw, WifiInfo info) { 1428 if (info.getSupplicantState() != SupplicantState.COMPLETED) { 1429 pw.println("Wifi is not connected"); 1430 return; 1431 } 1432 pw.println("Wifi is connected to " + info.getSSID()); 1433 pw.println("WifiInfo: " + info); 1434 // additional diagnostics not printed by WifiInfo.toString() 1435 pw.println("successfulTxPackets: " + info.txSuccess); 1436 pw.println("successfulTxPacketsPerSecond: " + info.getSuccessfulTxPacketsPerSecond()); 1437 pw.println("retriedTxPackets: " + info.txRetries); 1438 pw.println("retriedTxPacketsPerSecond: " + info.getRetriedTxPacketsPerSecond()); 1439 pw.println("lostTxPackets: " + info.txBad); 1440 pw.println("lostTxPacketsPerSecond: " + info.getLostTxPacketsPerSecond()); 1441 pw.println("successfulRxPackets: " + info.rxSuccess); 1442 pw.println("successfulRxPacketsPerSecond: " + info.getSuccessfulRxPacketsPerSecond()); 1443 } 1444 printStatus(PrintWriter pw)1445 private void printStatus(PrintWriter pw) { 1446 boolean wifiEnabled = mWifiService.getWifiEnabledState() == WIFI_STATE_ENABLED; 1447 pw.println("Wifi is " + (wifiEnabled ? "enabled" : "disabled")); 1448 pw.println("Wifi scanning is " 1449 + (mWifiService.isScanAlwaysAvailable() 1450 ? "always available" : "only available when wifi is enabled")); 1451 if (!wifiEnabled) { 1452 return; 1453 } 1454 if (Binder.getCallingUid() != Process.ROOT_UID) { 1455 // not privileged, just dump the primary client mode manager manager status 1456 // (public API contents). 1457 pw.println("==== Primary ClientModeManager instance ===="); 1458 printWifiInfo(pw, mWifiService.getConnectionInfo(SHELL_PACKAGE_NAME, null)); 1459 } else { 1460 // privileged, dump out all the client mode manager manager statuses 1461 for (ClientModeManager cm : mActiveModeWarden.getClientModeManagers()) { 1462 pw.println("==== ClientModeManager instance: " + cm + " ===="); 1463 WifiInfo info = cm.syncRequestConnectionInfo(); 1464 printWifiInfo(pw, info); 1465 if (info.getSupplicantState() != SupplicantState.COMPLETED) { 1466 continue; 1467 } 1468 Network network = cm.syncGetCurrentNetwork(); 1469 NetworkCapabilities capabilities = 1470 mConnectivityManager.getNetworkCapabilities(network); 1471 pw.println("NetworkCapabilities: " + capabilities); 1472 } 1473 } 1474 } 1475 onHelpNonPrivileged(PrintWriter pw)1476 private void onHelpNonPrivileged(PrintWriter pw) { 1477 pw.println(" get-country-code"); 1478 pw.println(" Gets country code as a two-letter string"); 1479 pw.println(" set-wifi-enabled enabled|disabled"); 1480 pw.println(" Enables/disables Wifi on this device."); 1481 pw.println(" set-scan-always-available enabled|disabled"); 1482 pw.println(" Sets whether scanning should be available even when wifi is off."); 1483 pw.println(" list-scan-results"); 1484 pw.println(" Lists the latest scan results"); 1485 pw.println(" start-scan"); 1486 pw.println(" Start a new scan"); 1487 pw.println(" list-networks"); 1488 pw.println(" Lists the saved networks"); 1489 pw.println(" connect-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d] " 1490 + "[-b <bssid>] [-r auto|none|persistent|non_persistent]"); 1491 pw.println(" Connect to a network with provided params and add to saved networks list"); 1492 pw.println(" <ssid> - SSID of the network"); 1493 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 1494 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 1495 pw.println(" - 'open' - Open networks (Most prevalent)"); 1496 pw.println(" - 'owe' - Enhanced open networks"); 1497 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 1498 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 1499 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 1500 pw.println(" -m - Mark the network metered."); 1501 pw.println(" -d - Mark the network autojoin disabled."); 1502 pw.println(" -h - Mark the network hidden."); 1503 pw.println(" -p - Mark the network private (not shared)."); 1504 pw.println(" -b <bssid> - Set specific BSSID."); 1505 pw.println(" -r auto|none|persistent|non_persistent - MAC randomization scheme for the" 1506 + " network"); 1507 pw.println(" add-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m] [-d] " 1508 + "[-b <bssid>] [-r auto|none|persistent|non_persistent]"); 1509 pw.println(" Add/update saved network with provided params"); 1510 pw.println(" <ssid> - SSID of the network"); 1511 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 1512 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 1513 pw.println(" - 'open' - Open networks (Most prevalent)"); 1514 pw.println(" - 'owe' - Enhanced open networks"); 1515 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 1516 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 1517 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 1518 pw.println(" -m - Mark the network metered."); 1519 pw.println(" -d - Mark the network autojoin disabled."); 1520 pw.println(" -h - Mark the network hidden."); 1521 pw.println(" -p - Mark the network private (not shared)."); 1522 pw.println(" -b <bssid> - Set specific BSSID."); 1523 pw.println(" -r auto|none|persistent|non_persistent - MAC randomization scheme for the" 1524 + " network"); 1525 pw.println(" forget-network <networkId>"); 1526 pw.println(" Remove the network mentioned by <networkId>"); 1527 pw.println(" - Use list-networks to retrieve <networkId> for the network"); 1528 pw.println(" status"); 1529 pw.println(" Current wifi status"); 1530 pw.println(" set-verbose-logging enabled|disabled "); 1531 pw.println(" Set the verbose logging enabled or disabled"); 1532 pw.println(" is-verbose-logging"); 1533 pw.println(" Check whether verbose logging enabled or disabled"); 1534 pw.println(" start-restricting-auto-join-to-subscription-id subId"); 1535 pw.println(" temporarily disable all wifi networks except merged carrier networks with" 1536 + " the given subId"); 1537 pw.println(" stop-restricting-auto-join-to-subscription-id"); 1538 pw.println(" Undo the effects of " 1539 + "start-restricting-auto-join-to-subscription-id"); 1540 pw.println(" add-suggestion <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-u] [-o] [-p] [-m] " 1541 + " [-s] [-d] [-b <bssid>] [-e] [-i] [-a <carrierId>] [-c <subscriptionId>]"); 1542 pw.println(" Add a network suggestion with provided params"); 1543 pw.println(" Use 'network-suggestions-set-user-approved " + SHELL_PACKAGE_NAME + " yes'" 1544 + " to approve suggestions added via shell (Needs root access)"); 1545 pw.println(" <ssid> - SSID of the network"); 1546 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 1547 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 1548 pw.println(" - 'open' - Open networks (Most prevalent)"); 1549 pw.println(" - 'owe' - Enhanced open networks"); 1550 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 1551 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 1552 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 1553 pw.println(" -u - Mark the suggestion untrusted."); 1554 pw.println(" -o - Mark the suggestion oem paid."); 1555 pw.println(" -p - Mark the suggestion oem private."); 1556 pw.println(" -m - Mark the suggestion metered."); 1557 pw.println(" -h - Mark the network hidden."); 1558 pw.println(" -s - Share the suggestion with user."); 1559 pw.println(" -d - Mark the suggestion autojoin disabled."); 1560 pw.println(" -b <bssid> - Set specific BSSID."); 1561 pw.println(" -r - Enable non_persistent randomization (disabled by default)"); 1562 pw.println(" -a - Mark the suggestion carrier merged"); 1563 pw.println(" -c <carrierId> - set carrier Id"); 1564 pw.println(" -i <subscriptionId> - set subscription Id, if -a is used, " 1565 + "this must be set"); 1566 pw.println(" remove-suggestion <ssid>"); 1567 pw.println(" Remove a network suggestion with provided SSID of the network"); 1568 pw.println(" remove-all-suggestions"); 1569 pw.println(" Removes all suggestions added via shell"); 1570 pw.println(" list-suggestions"); 1571 pw.println(" Lists the suggested networks added via shell"); 1572 if (SdkLevel.isAtLeastS()) { 1573 pw.println(" set-coex-cell-channels [lte|nr <bandNumber 1-261> " 1574 + "<downlinkFreqKhz or UNKNOWN: " 1575 + PhysicalChannelConfig.FREQUENCY_UNKNOWN + "> " 1576 + "<downlinkBandwidthKhz or UNKNOWN: " 1577 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN + "> " 1578 + "<uplinkFreqKhz or UNKNOWN: " 1579 + PhysicalChannelConfig.FREQUENCY_UNKNOWN + "> " 1580 + "<uplinkBandwidthKhz or UNKNOWN: " 1581 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN + ">] ..."); 1582 pw.println(" Sets a list of zero or more cell channels to use for coex calculations." 1583 + " Actual device reported cell channels will be ignored until" 1584 + " reset-coex-cell-channels is called."); 1585 pw.println(" reset-coex-cell-channels"); 1586 pw.println(" Removes all cell channels set in set-coex-cell-channels and returns to " 1587 + "listening on actual device reported cell channels"); 1588 pw.println(" get-coex-cell-channels"); 1589 pw.println(" Prints the cell channels being used for coex."); 1590 } 1591 pw.println(" set-connected-score <score>"); 1592 pw.println(" Set connected wifi network score (to choose between LTE & Wifi for " 1593 + "default route)."); 1594 pw.println(" This turns off the active connected scorer (default or external)."); 1595 pw.println(" Only works while connected to a wifi network. This score will stay in " 1596 + "effect until you call reset-connected-score or the device disconnects from the " 1597 + "current network."); 1598 pw.println(" <score> - Integer score should be in the range of 0 - 60"); 1599 pw.println(" reset-connected-score"); 1600 pw.println(" Turns on the default connected scorer."); 1601 pw.println(" Note: Will clear any external scorer set."); 1602 pw.println(" start-softap <ssid> (open|wpa2|wpa3|wpa3_transition) <passphrase> " 1603 + "[-b 2|5|6|any]"); 1604 pw.println(" Start softap with provided params"); 1605 pw.println(" Note that the shell command doesn't activate internet tethering. In some " 1606 + "devices, internet sharing is possible when Wi-Fi STA is also enabled and is" 1607 + "associated to another AP with internet access."); 1608 pw.println(" <ssid> - SSID of the network"); 1609 pw.println(" open|wpa2|wpa3|wpa3_transition - Security type of the network."); 1610 pw.println(" - Use 'open' for networks with no passphrase"); 1611 pw.println(" - Use 'wpa2', 'wpa3', 'wpa3_transition' for networks with passphrase"); 1612 pw.println(" -b 2|5|6|any|bridged - select the preferred band."); 1613 pw.println(" - Use '2' to select 2.4GHz band as the preferred band"); 1614 pw.println(" - Use '5' to select 5GHz band as the preferred band"); 1615 pw.println(" - Use '6' to select 6GHz band as the preferred band"); 1616 pw.println(" - Use 'any' to indicate no band preference"); 1617 pw.println(" - Use 'bridged' to indicate bridged AP which enables APs on both " 1618 + "2.4G + 5G"); 1619 pw.println(" Note: If the band option is not provided, 2.4GHz is the preferred band."); 1620 pw.println(" The exact channel is auto-selected by FW unless overridden by " 1621 + "force-softap-channel command"); 1622 pw.println(" stop-softap"); 1623 pw.println(" Stop softap (hotspot)"); 1624 pw.println(" pmksa-flush <networkId>"); 1625 pw.println(" - Flush the local PMKSA cache associated with the network id." 1626 + " Use list-networks to retrieve <networkId> for the network"); 1627 } 1628 onHelpPrivileged(PrintWriter pw)1629 private void onHelpPrivileged(PrintWriter pw) { 1630 pw.println(" set-ipreach-disconnect enabled|disabled"); 1631 pw.println(" Sets whether CMD_IP_REACHABILITY_LOST events should trigger disconnects."); 1632 pw.println(" get-ipreach-disconnect"); 1633 pw.println(" Gets setting of CMD_IP_REACHABILITY_LOST events triggering disconnects."); 1634 pw.println(" set-poll-rssi-interval-msecs <int>"); 1635 pw.println(" Sets the interval between RSSI polls to <int> milliseconds."); 1636 pw.println(" get-poll-rssi-interval-msecs"); 1637 pw.println(" Gets current interval between RSSI polls, in milliseconds."); 1638 pw.println(" force-hi-perf-mode enabled|disabled"); 1639 pw.println(" Sets whether hi-perf mode is forced or left for normal operation."); 1640 pw.println(" force-low-latency-mode enabled|disabled"); 1641 pw.println(" Sets whether low latency mode is forced or left for normal operation."); 1642 pw.println(" network-suggestions-set-user-approved <package name> yes|no"); 1643 pw.println(" Sets whether network suggestions from the app is approved or not."); 1644 pw.println(" network-suggestions-has-user-approved <package name>"); 1645 pw.println(" Queries whether network suggestions from the app is approved or not."); 1646 pw.println(" imsi-protection-exemption-set-user-approved-for-carrier <carrier id> yes|no"); 1647 pw.println(" Sets whether Imsi protection exemption for carrier is approved or not"); 1648 pw.println(" imsi-protection-exemption-has-user-approved-for-carrier <carrier id>"); 1649 pw.println(" Queries whether Imsi protection exemption for carrier is approved or not"); 1650 pw.println(" imsi-protection-exemption-clear-user-approved-for-carrier <carrier id>"); 1651 pw.println(" Clear the user choice on Imsi protection exemption for carrier"); 1652 pw.println(" network-requests-remove-user-approved-access-points <package name>"); 1653 pw.println(" Removes all user approved network requests for the app."); 1654 pw.println(" clear-user-disabled-networks"); 1655 pw.println(" Clears the user disabled networks list."); 1656 pw.println(" send-link-probe"); 1657 pw.println(" Manually triggers a link probe."); 1658 pw.println(" force-softap-band enabled <int> | disabled"); 1659 pw.println(" Forces soft AP band to 2|5|6"); 1660 pw.println(" force-softap-channel enabled <int> | disabled"); 1661 pw.println(" Sets whether soft AP channel is forced to <int> MHz"); 1662 pw.println(" or left for normal operation."); 1663 pw.println(" force-country-code enabled <two-letter code> | disabled "); 1664 pw.println(" Sets country code to <two-letter code> or left for normal value"); 1665 pw.println(" set-wifi-watchdog enabled|disabled"); 1666 pw.println(" Sets whether wifi watchdog should trigger recovery"); 1667 pw.println(" get-wifi-watchdog"); 1668 pw.println(" Gets setting of wifi watchdog trigger recovery."); 1669 pw.println(" get-softap-supported-features"); 1670 pw.println(" Gets softap supported features. Will print 'wifi_softap_acs_supported'"); 1671 pw.println(" and/or 'wifi_softap_wpa3_sae_supported',"); 1672 pw.println(" and/or 'wifi_softap_bridged_ap_supported',"); 1673 pw.println(" and/or 'wifi_softap_bridged_ap_with_sta_supported',"); 1674 pw.println(" each on a separate line."); 1675 pw.println(" settings-reset"); 1676 pw.println(" Initiates wifi settings reset"); 1677 pw.println(" add-request <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-b <bssid>]"); 1678 pw.println(" Add a network request with provided params"); 1679 pw.println(" Use 'network-requests-set-user-approved android yes'" 1680 + " to pre-approve requests added via rooted shell (Not persisted)"); 1681 pw.println(" <ssid> - SSID of the network"); 1682 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 1683 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 1684 pw.println(" - 'open' - Open networks (Most prevalent)"); 1685 pw.println(" - 'owe' - Enhanced open networks"); 1686 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 1687 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 1688 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 1689 pw.println(" -b <bssid> - Set specific BSSID."); 1690 pw.println(" remove-request <ssid>"); 1691 pw.println(" Remove a network request with provided SSID of the network"); 1692 pw.println(" remove-all-requests"); 1693 pw.println(" Removes all active requests added via shell"); 1694 pw.println(" list-requests"); 1695 pw.println(" Lists the requested networks added via shell"); 1696 pw.println(" network-requests-set-user-approved <package name> yes|no"); 1697 pw.println(" Sets whether network requests from the app is approved or not."); 1698 pw.println(" Note: Only 1 such app can be approved from the shell at a time"); 1699 pw.println(" network-requests-has-user-approved <package name>"); 1700 pw.println(" Queries whether network requests from the app is approved or not."); 1701 pw.println(" Note: This only returns whether the app was set via the " 1702 + "'network-requests-set-user-approved' shell command"); 1703 pw.println(" list-all-suggestions"); 1704 pw.println(" Lists all suggested networks on this device"); 1705 pw.println(" list-suggestions-from-app <package name>"); 1706 pw.println(" Lists the suggested networks from the app"); 1707 pw.println(" set-emergency-callback-mode enabled|disabled"); 1708 pw.println(" Sets whether Emergency Callback Mode (ECBM) is enabled."); 1709 pw.println(" Equivalent to receiving the " 1710 + "TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED broadcast."); 1711 pw.println(" set-emergency-call-state enabled|disabled"); 1712 pw.println(" Sets whether we are in the middle of an emergency call."); 1713 pw.println("Equivalent to receiving the " 1714 + "TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED broadcast."); 1715 pw.println(" network-suggestions-set-as-carrier-provider <packageName> yes|no"); 1716 pw.println(" Set the <packageName> work as carrier provider or not."); 1717 pw.println(" is-network-suggestions-set-as-carrier-provider <packageName>"); 1718 pw.println(" Queries whether the <packageName> is working as carrier provider or not."); 1719 pw.println(" remove-app-from-suggestion_database <packageName>"); 1720 pw.println(" Remove <packageName> from the suggestion database, all suggestions and user" 1721 + " approval will be deleted, it is the same as uninstalling this app."); 1722 pw.println(" trigger-recovery"); 1723 pw.println(" Trigger Wi-Fi subsystem restart."); 1724 pw.println(" start-faking-scans"); 1725 pw.println(" Start faking scan results into the framework (configured with " 1726 + "'add-fake-scan'), stop with 'stop-faking-scans'."); 1727 pw.println(" stop-faking-scans"); 1728 pw.println(" Stop faking scan results - started with 'start-faking-scans'."); 1729 pw.println(" add-fake-scan <ssid> <bssid> <capabilities> <frequency> <dbm>"); 1730 pw.println(" Add a fake scan result to be used when enabled via `start-faking-scans'."); 1731 pw.println(" Example WPA2: add-fake-scan fakeWpa2 80:01:02:03:04:05 " 1732 + "\"[WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS]\" 2412 -55"); 1733 pw.println(" Example WPA3: add-fake-scan fakeWpa3 80:01:02:03:04:06 " 1734 + "\"[RSN-SAE+FT/SAE-CCMP][ESS]\" 2412 -55"); 1735 pw.println( 1736 " Example Open: add-fake-scan fakeOpen 80:01:02:03:04:07 \"[ESS]\" 2412 -55"); 1737 pw.println(" Example OWE: add-fake-scan fakeOwe 80:01:02:03:04:08 \"[RSN-OWE-CCMP]\" " 1738 + "2412 -55"); 1739 pw.println( 1740 " Example WPA2/WPA3 transition mode: add-fake-scan fakeWpa2t3 80:01:02:03:04:09 " 1741 + "\"[WPA2-PSK-CCMP][RSN-PSK+SAE-CCMP][ESS][MFPC]\" 2412 -55"); 1742 pw.println( 1743 " Example Open/OWE transition mode: add-fake-scan fakeOpenOwe 80:01:02:03:04:0A " 1744 + "\"[RSN-OWE_TRANSITION-CCMP][ESS]\" 2412 -55"); 1745 pw.println( 1746 " Example Passpoint: add-fake-scan fakePasspoint 80:01:02:03:04:0B " 1747 + "\"[WPA2-EAP/SHA1-CCMP][RSN-EAP/SHA1-CCMP][ESS][MFPR][MFPC]" 1748 + "[PASSPOINT]\" 2412 -55"); 1749 pw.println(" reset-fake-scans"); 1750 pw.println(" Resets all fake scan results added by 'add-fake-scan'."); 1751 pw.println(" enable-scanning enabled|disabled [-h]"); 1752 pw.println(" Sets whether all scanning should be enabled or disabled"); 1753 pw.println(" -h - Enable scanning for hidden networks."); 1754 } 1755 1756 @Override onHelp()1757 public void onHelp() { 1758 final PrintWriter pw = getOutPrintWriter(); 1759 pw.println("Wi-Fi (wifi) commands:"); 1760 pw.println(" help or -h"); 1761 pw.println(" Print this help text."); 1762 onHelpNonPrivileged(pw); 1763 if (Binder.getCallingUid() == Process.ROOT_UID) { 1764 onHelpPrivileged(pw); 1765 } 1766 pw.println(); 1767 } 1768 printWifiNetworkSuggestions(PrintWriter pw, Collection<WifiNetworkSuggestion> suggestions)1769 private void printWifiNetworkSuggestions(PrintWriter pw, 1770 Collection<WifiNetworkSuggestion> suggestions) { 1771 if (suggestions == null || suggestions.isEmpty()) { 1772 pw.println("No suggestions on this device"); 1773 } else { 1774 pw.println("SSID Security type(s)"); 1775 for (WifiNetworkSuggestion suggestion : suggestions) { 1776 pw.println(String.format("%-32s %-4s", 1777 WifiInfo.sanitizeSsid(suggestion.getWifiConfiguration().SSID), 1778 suggestion.getWifiConfiguration().getSecurityParamsList().stream() 1779 .map(p -> WifiConfiguration.getSecurityTypeName( 1780 p.getSecurityType()) 1781 + (p.isAddedByAutoUpgrade() ? "^" : "")) 1782 .collect(Collectors.joining("/")))); 1783 } 1784 } 1785 } 1786 } 1787