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.ACTION_REMOVE_SUGGESTION_DISCONNECT; 26 import static android.net.wifi.WifiManager.ACTION_REMOVE_SUGGESTION_LINGER; 27 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED; 28 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 29 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 30 31 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP; 32 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE; 33 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_NAN; 34 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_P2P; 35 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA; 36 import static com.android.server.wifi.SelfRecovery.REASON_API_CALL; 37 38 import android.content.BroadcastReceiver; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.hardware.display.DisplayManager; 43 import android.net.ConnectivityManager; 44 import android.net.MacAddress; 45 import android.net.Network; 46 import android.net.NetworkCapabilities; 47 import android.net.NetworkRequest; 48 import android.net.wifi.IActionListener; 49 import android.net.wifi.IDppCallback; 50 import android.net.wifi.ILocalOnlyHotspotCallback; 51 import android.net.wifi.IPnoScanResultsCallback; 52 import android.net.wifi.IScoreUpdateObserver; 53 import android.net.wifi.ISoftApCallback; 54 import android.net.wifi.IWifiConnectedNetworkScorer; 55 import android.net.wifi.ScanResult; 56 import android.net.wifi.SoftApCapability; 57 import android.net.wifi.SoftApConfiguration; 58 import android.net.wifi.SoftApInfo; 59 import android.net.wifi.SupplicantState; 60 import android.net.wifi.WifiClient; 61 import android.net.wifi.WifiConfiguration; 62 import android.net.wifi.WifiConnectedSessionInfo; 63 import android.net.wifi.WifiContext; 64 import android.net.wifi.WifiInfo; 65 import android.net.wifi.WifiManager; 66 import android.net.wifi.WifiNetworkSpecifier; 67 import android.net.wifi.WifiNetworkSuggestion; 68 import android.net.wifi.WifiScanner; 69 import android.net.wifi.WifiSsid; 70 import android.net.wifi.util.ScanResultUtil; 71 import android.os.Binder; 72 import android.os.Build; 73 import android.os.Bundle; 74 import android.os.PatternMatcher; 75 import android.os.Process; 76 import android.os.RemoteException; 77 import android.os.SystemClock; 78 import android.os.WorkSource; 79 import android.telephony.Annotation; 80 import android.telephony.PhysicalChannelConfig; 81 import android.telephony.SubscriptionManager; 82 import android.telephony.TelephonyManager; 83 import android.text.TextUtils; 84 import android.util.Log; 85 import android.util.Pair; 86 import android.util.SparseArray; 87 import android.view.Display; 88 89 import androidx.annotation.NonNull; 90 import androidx.annotation.Nullable; 91 import androidx.annotation.RequiresApi; 92 93 import com.android.internal.annotations.VisibleForTesting; 94 import com.android.modules.utils.BasicShellCommandHandler; 95 import com.android.modules.utils.ParceledListSlice; 96 import com.android.modules.utils.build.SdkLevel; 97 import com.android.server.wifi.ClientMode.LinkProbeCallback; 98 import com.android.server.wifi.coex.CoexManager; 99 import com.android.server.wifi.coex.CoexUtils; 100 import com.android.server.wifi.hotspot2.NetworkDetail; 101 import com.android.server.wifi.util.ApConfigUtil; 102 import com.android.server.wifi.util.ArrayUtils; 103 104 import libcore.util.HexEncoding; 105 106 import java.io.PrintWriter; 107 import java.nio.charset.StandardCharsets; 108 import java.util.ArrayList; 109 import java.util.Arrays; 110 import java.util.Collection; 111 import java.util.Collections; 112 import java.util.Comparator; 113 import java.util.List; 114 import java.util.Map; 115 import java.util.Set; 116 import java.util.concurrent.ArrayBlockingQueue; 117 import java.util.concurrent.ConcurrentHashMap; 118 import java.util.concurrent.CountDownLatch; 119 import java.util.concurrent.TimeUnit; 120 import java.util.stream.Collectors; 121 122 /** 123 * Interprets and executes 'adb shell cmd wifi [args]'. 124 * 125 * To add new commands: 126 * - onCommand: Add a case "<command>" execute. Return a 0 127 * if command executed successfully. 128 * - onHelp: add a description string. 129 * 130 * Permissions: currently root permission is required for some commands. Others will 131 * enforce the corresponding API permissions. 132 */ 133 public class WifiShellCommand extends BasicShellCommandHandler { 134 @VisibleForTesting 135 public static String SHELL_PACKAGE_NAME = "com.android.shell"; 136 137 // These don't require root access. 138 // However, these do perform permission checks in the corresponding WifiService methods. 139 private static final String[] NON_PRIVILEGED_COMMANDS = { 140 "add-suggestion", 141 "forget-network", 142 "get-country-code", 143 "help", 144 "-h", 145 "is-verbose-logging", 146 "list-scan-results", 147 "list-networks", 148 "list-suggestions", 149 "remove-suggestion", 150 "remove-all-suggestions", 151 "reset-connected-score", 152 "set-connected-score", 153 "set-scan-always-available", 154 "set-verbose-logging", 155 "set-wifi-enabled", 156 "set-passpoint-enabled", 157 "set-multi-internet-state", 158 "start-scan", 159 "start-softap", 160 "status", 161 "stop-softap", 162 "query-interface", 163 "interface-priority-interactive-mode", 164 "set-one-shot-screen-on-delay-ms", 165 "set-ipreach-disconnect", 166 "get-ipreach-disconnect", 167 }; 168 169 private static final Map<String, Pair<NetworkRequest, ConnectivityManager.NetworkCallback>> 170 sActiveRequests = new ConcurrentHashMap<>(); 171 172 private final ActiveModeWarden mActiveModeWarden; 173 private final WifiGlobals mWifiGlobals; 174 private final WifiLockManager mWifiLockManager; 175 private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; 176 private final WifiConfigManager mWifiConfigManager; 177 private final WifiNative mWifiNative; 178 private final CoexManager mCoexManager; 179 private final WifiCountryCode mWifiCountryCode; 180 private final WifiLastResortWatchdog mWifiLastResortWatchdog; 181 private final WifiServiceImpl mWifiService; 182 private final WifiContext mContext; 183 private final ConnectivityManager mConnectivityManager; 184 private final WifiCarrierInfoManager mWifiCarrierInfoManager; 185 private final WifiNetworkFactory mWifiNetworkFactory; 186 private final SelfRecovery mSelfRecovery; 187 private final WifiThreadRunner mWifiThreadRunner; 188 private final WifiApConfigStore mWifiApConfigStore; 189 private int mSapState = WifiManager.WIFI_STATE_UNKNOWN; 190 private final ScanRequestProxy mScanRequestProxy; 191 private final @NonNull WifiDialogManager mWifiDialogManager; 192 private final HalDeviceManager mHalDeviceManager; 193 private final InterfaceConflictManager mInterfaceConflictManager; 194 195 private class SoftApCallbackProxy extends ISoftApCallback.Stub { 196 private final PrintWriter mPrintWriter; 197 private final CountDownLatch mCountDownLatch; 198 SoftApCallbackProxy(PrintWriter printWriter, CountDownLatch countDownLatch)199 SoftApCallbackProxy(PrintWriter printWriter, CountDownLatch countDownLatch) { 200 mPrintWriter = printWriter; 201 mCountDownLatch = countDownLatch; 202 } 203 204 @Override onStateChanged(int state, int failureReason)205 public void onStateChanged(int state, int failureReason) { 206 mPrintWriter.println("onStateChanged with state: " + state 207 + " failure reason: " + failureReason); 208 mSapState = state; 209 if (state == WifiManager.WIFI_AP_STATE_ENABLED) { 210 mPrintWriter.println(" SAP is enabled successfully"); 211 // Skip countDown() and wait for onInfoChanged() which has 212 // the confirmed softAp channel information 213 } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { 214 mPrintWriter.println(" SAP is disabled"); 215 } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { 216 mPrintWriter.println(" SAP failed to start"); 217 mCountDownLatch.countDown(); 218 } 219 } 220 221 @Override onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration)222 public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, 223 Map<String, List<WifiClient>> clients, boolean isBridged, 224 boolean isRegistration) { 225 mPrintWriter.println("onConnectedClientsOrInfoChanged, infos: " + infos 226 + ", clients: " + clients + ", isBridged: " + isBridged); 227 if (mSapState == WifiManager.WIFI_AP_STATE_ENABLED && infos.size() != 0) { 228 mCountDownLatch.countDown(); 229 } 230 } 231 232 @Override onCapabilityChanged(SoftApCapability capability)233 public void onCapabilityChanged(SoftApCapability capability) { 234 mPrintWriter.println("onCapabilityChanged " + capability); 235 } 236 237 @Override onBlockedClientConnecting(WifiClient client, int reason)238 public void onBlockedClientConnecting(WifiClient client, int reason) { 239 } 240 } 241 242 /** 243 * Used for shell command testing of DPP feature. 244 */ 245 public static class DppCallbackProxy extends IDppCallback.Stub { 246 private final PrintWriter mPrintWriter; 247 private final CountDownLatch mCountDownLatch; 248 private static final int STATUS_SUCCESS = 0; 249 private static final int STATUS_PROGRESS = 1; 250 private static final int STATUS_FAILURE = 2; 251 DppCallbackProxy(PrintWriter printWriter, CountDownLatch countDownLatch)252 DppCallbackProxy(PrintWriter printWriter, CountDownLatch countDownLatch) { 253 mPrintWriter = printWriter; 254 mCountDownLatch = countDownLatch; 255 } 256 257 @Override onSuccessConfigReceived(int networkId)258 public void onSuccessConfigReceived(int networkId) { 259 mPrintWriter.println("onSuccessConfigReceived. netId=" + networkId); 260 mCountDownLatch.countDown(); 261 } 262 263 @Override onSuccess(int status)264 public void onSuccess(int status) { 265 mPrintWriter.println("onSuccess status=" + statusToString(STATUS_SUCCESS, status)); 266 mCountDownLatch.countDown(); 267 } 268 269 @Override onFailure(int status, String ssid, String channelList, int[] bandArray)270 public void onFailure(int status, String ssid, String channelList, int[] bandArray) { 271 mPrintWriter.println("onFailure. status=" + statusToString(STATUS_FAILURE, status) 272 + "ssid=" + ssid + "channelList=" + channelList); 273 mCountDownLatch.countDown(); 274 } 275 276 @Override onProgress(int status)277 public void onProgress(int status) { 278 mPrintWriter.println("onProgress status=" + statusToString(STATUS_PROGRESS, status)); 279 } 280 281 @Override onBootstrapUriGenerated(String uri)282 public void onBootstrapUriGenerated(String uri) { 283 mPrintWriter.println("onBootstrapUriGenerated URI = " + uri); 284 } 285 statusToString(int type, int status)286 private String statusToString(int type, int status) { 287 switch (type) { 288 case STATUS_SUCCESS: { 289 switch (status) { 290 case 0: 291 return "CONFIGURATION_SENT"; 292 case 1: 293 return "CONFIGURATION_APPLIED"; 294 default: 295 return "Unknown success code"; 296 } 297 } 298 case STATUS_PROGRESS: { 299 switch (status) { 300 case 0: 301 return "AUTHENTICATION_SUCCESS"; 302 case 1: 303 return "RESPONSE_PENDING"; 304 case 2: 305 return "CONFIGURATION_SENT_WAITING_RESPONSE"; 306 case 3: 307 return "CONFIGURATION_ACCEPTED"; 308 default: 309 return "Unknown progress code"; 310 } 311 } 312 case STATUS_FAILURE: { 313 switch (status) { 314 case -1: 315 return "INVALID_URI"; 316 case -2: 317 return "AUTHENTICATION"; 318 case -3: 319 return "NOT_COMPATIBLE"; 320 case -4: 321 return "CONFIGURATION"; 322 case -5: 323 return "BUSY"; 324 case -6: 325 return "TIMEOUT"; 326 case -7: 327 return "GENERIC"; 328 case -8: 329 return "NOT_SUPPORTED"; 330 case -9: 331 return "INVALID_NETWORK"; 332 case -10: 333 return "CANNOT_FIND_NETWORK"; 334 case -11: 335 return "ENROLLEE_AUTHENTICATION"; 336 case -12: 337 return "ENROLLEE_REJECTED_CONFIGURATION"; 338 case -13: 339 return "URI_GENERATION"; 340 case -14: 341 return "ENROLLEE_FAILED_TO_SCAN_NETWORK_CHANNEL"; 342 default: 343 return "Unknown failure code"; 344 } 345 } 346 default : 347 return "Unknown status type"; 348 } 349 } 350 } 351 352 /** 353 * Used for shell command testing of scorer. 354 */ 355 public static class WifiScorer extends IWifiConnectedNetworkScorer.Stub { 356 private final WifiServiceImpl mWifiService; 357 private final CountDownLatch mCountDownLatch; 358 private Integer mSessionId; 359 private IScoreUpdateObserver mScoreUpdateObserver; 360 WifiScorer(WifiServiceImpl wifiService, CountDownLatch countDownLatch)361 public WifiScorer(WifiServiceImpl wifiService, CountDownLatch countDownLatch) { 362 mWifiService = wifiService; 363 mCountDownLatch = countDownLatch; 364 } 365 366 @Override onStart(WifiConnectedSessionInfo sessionInfo)367 public void onStart(WifiConnectedSessionInfo sessionInfo) { 368 mSessionId = sessionInfo.getSessionId(); 369 mCountDownLatch.countDown(); 370 } 371 @Override onStop(int sessionId)372 public void onStop(int sessionId) { 373 // clear the external scorer on disconnect. 374 mWifiService.clearWifiConnectedNetworkScorer(); 375 } 376 @Override onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)377 public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) { 378 mScoreUpdateObserver = observerImpl; 379 mCountDownLatch.countDown(); 380 } 381 getSessionId()382 public Integer getSessionId() { 383 return mSessionId; 384 } 385 getScoreUpdateObserver()386 public IScoreUpdateObserver getScoreUpdateObserver() { 387 return mScoreUpdateObserver; 388 } 389 } 390 WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, WifiContext context, WifiGlobals wifiGlobals, WifiThreadRunner wifiThreadRunner)391 WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, WifiContext context, 392 WifiGlobals wifiGlobals, WifiThreadRunner wifiThreadRunner) { 393 mWifiGlobals = wifiGlobals; 394 mWifiThreadRunner = wifiThreadRunner; 395 mActiveModeWarden = wifiInjector.getActiveModeWarden(); 396 mWifiLockManager = wifiInjector.getWifiLockManager(); 397 mWifiNetworkSuggestionsManager = wifiInjector.getWifiNetworkSuggestionsManager(); 398 mWifiConfigManager = wifiInjector.getWifiConfigManager(); 399 mWifiNative = wifiInjector.getWifiNative(); 400 mCoexManager = wifiInjector.getCoexManager(); 401 mWifiCountryCode = wifiInjector.getWifiCountryCode(); 402 mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); 403 mWifiService = wifiService; 404 mContext = context; 405 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 406 mWifiCarrierInfoManager = wifiInjector.getWifiCarrierInfoManager(); 407 mWifiNetworkFactory = wifiInjector.getWifiNetworkFactory(); 408 mSelfRecovery = wifiInjector.getSelfRecovery(); 409 mWifiApConfigStore = wifiInjector.getWifiApConfigStore(); 410 mScanRequestProxy = wifiInjector.getScanRequestProxy(); 411 mWifiDialogManager = wifiInjector.getWifiDialogManager(); 412 mHalDeviceManager = wifiInjector.getHalDeviceManager(); 413 mInterfaceConflictManager = wifiInjector.getInterfaceConflictManager(); 414 } 415 416 @Override onCommand(String cmd)417 public int onCommand(String cmd) { 418 // Treat no command as help command. 419 if (TextUtils.isEmpty(cmd)) { 420 cmd = "help"; 421 } 422 // Explicit exclusion from root permission 423 if (ArrayUtils.indexOf(NON_PRIVILEGED_COMMANDS, cmd) == -1) { 424 final int uid = Binder.getCallingUid(); 425 if (uid != Process.ROOT_UID) { 426 throw new SecurityException( 427 "Uid " + uid + " does not have access to " + cmd + " wifi command " 428 + "(or such command doesn't exist)"); 429 } 430 } 431 final PrintWriter pw = getOutPrintWriter(); 432 try { 433 switch (cmd) { 434 case "set-ipreach-disconnect": { 435 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 436 mWifiGlobals.setIpReachabilityDisconnectEnabled(enabled); 437 return 0; 438 } 439 case "get-ipreach-disconnect": 440 pw.println("IPREACH_DISCONNECT state is " 441 + mWifiGlobals.getIpReachabilityDisconnectEnabled()); 442 return 0; 443 case "set-poll-rssi-interval-msecs": 444 int newPollIntervalMsecs; 445 try { 446 newPollIntervalMsecs = Integer.parseInt(getNextArgRequired()); 447 } catch (NumberFormatException e) { 448 pw.println( 449 "Invalid argument to 'set-poll-rssi-interval-msecs' " 450 + "- must be a positive integer"); 451 return -1; 452 } 453 454 if (newPollIntervalMsecs < 1) { 455 pw.println( 456 "Invalid argument to 'set-poll-rssi-interval-msecs' " 457 + "- must be a positive integer"); 458 return -1; 459 } 460 461 mWifiGlobals.setPollRssiIntervalMillis(newPollIntervalMsecs); 462 return 0; 463 case "get-poll-rssi-interval-msecs": 464 pw.println("WifiGlobals.getPollRssiIntervalMillis() = " 465 + mWifiGlobals.getPollRssiIntervalMillis()); 466 return 0; 467 case "force-hi-perf-mode": { 468 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 469 if (!mWifiLockManager.forceHiPerfMode(enabled)) { 470 pw.println("Command execution failed"); 471 } 472 return 0; 473 } 474 case "force-low-latency-mode": { 475 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 476 if (!mWifiLockManager.forceLowLatencyMode(enabled)) { 477 pw.println("Command execution failed"); 478 } 479 return 0; 480 } 481 case "network-suggestions-set-user-approved": { 482 String packageName = getNextArgRequired(); 483 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 484 mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(approved, 485 Binder.getCallingUid(), packageName); 486 return 0; 487 } 488 case "network-suggestions-has-user-approved": { 489 String packageName = getNextArgRequired(); 490 boolean hasUserApproved = 491 mWifiNetworkSuggestionsManager.hasUserApprovedForApp(packageName); 492 pw.println(hasUserApproved ? "yes" : "no"); 493 return 0; 494 } 495 case "imsi-protection-exemption-set-user-approved-for-carrier": { 496 String arg1 = getNextArgRequired(); 497 int carrierId = -1; 498 try { 499 carrierId = Integer.parseInt(arg1); 500 } catch (NumberFormatException e) { 501 pw.println("Invalid argument to " 502 + "'imsi-protection-exemption-set-user-approved-for-carrier' " 503 + "- carrierId must be an Integer"); 504 return -1; 505 } 506 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 507 mWifiCarrierInfoManager 508 .setHasUserApprovedImsiPrivacyExemptionForCarrier(approved, carrierId); 509 return 0; 510 } 511 case "imsi-protection-exemption-has-user-approved-for-carrier": { 512 String arg1 = getNextArgRequired(); 513 int carrierId = -1; 514 try { 515 carrierId = Integer.parseInt(arg1); 516 } catch (NumberFormatException e) { 517 pw.println("Invalid argument to " 518 + "'imsi-protection-exemption-has-user-approved-for-carrier' " 519 + "- 'carrierId' must be an Integer"); 520 return -1; 521 } 522 boolean hasUserApproved = mWifiCarrierInfoManager 523 .hasUserApprovedImsiPrivacyExemptionForCarrier(carrierId); 524 pw.println(hasUserApproved ? "yes" : "no"); 525 return 0; 526 } 527 case "imsi-protection-exemption-clear-user-approved-for-carrier": { 528 String arg1 = getNextArgRequired(); 529 int carrierId = -1; 530 try { 531 carrierId = Integer.parseInt(arg1); 532 } catch (NumberFormatException e) { 533 pw.println("Invalid argument to " 534 + "'imsi-protection-exemption-clear-user-approved-for-carrier' " 535 + "- 'carrierId' must be an Integer"); 536 return -1; 537 } 538 mWifiCarrierInfoManager.clearImsiPrivacyExemptionForCarrier(carrierId); 539 return 0; 540 } 541 case "network-requests-remove-user-approved-access-points": { 542 String packageName = getNextArgRequired(); 543 mWifiNetworkFactory.removeUserApprovedAccessPointsForApp(packageName); 544 return 0; 545 } 546 case "clear-user-disabled-networks": { 547 mWifiConfigManager.clearUserTemporarilyDisabledList(); 548 return 0; 549 } 550 case "send-link-probe": { 551 return sendLinkProbe(pw); 552 } 553 case "force-softap-band": { 554 boolean forceBandEnabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 555 if (forceBandEnabled) { 556 String forcedBand = getNextArgRequired(); 557 if (forcedBand.equals("2")) { 558 mWifiApConfigStore.enableForceSoftApBandOrChannel( 559 SoftApConfiguration.BAND_2GHZ, 0); 560 } else if (forcedBand.equals("5")) { 561 mWifiApConfigStore.enableForceSoftApBandOrChannel( 562 SoftApConfiguration.BAND_5GHZ, 0); 563 } else if (forcedBand.equals("6")) { 564 mWifiApConfigStore.enableForceSoftApBandOrChannel( 565 SoftApConfiguration.BAND_6GHZ, 0); 566 } else { 567 pw.println("Invalid argument to 'force-softap-band enabled' " 568 + "- must be a valid band integer (2|5|6)"); 569 return -1; 570 } 571 return 0; 572 } else { 573 mWifiApConfigStore.disableForceSoftApBandOrChannel(); 574 return 0; 575 } 576 577 } 578 case "force-softap-channel": { 579 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 580 if (enabled) { 581 int apChannelMHz; 582 try { 583 apChannelMHz = Integer.parseInt(getNextArgRequired()); 584 } catch (NumberFormatException e) { 585 pw.println("Invalid argument to 'force-softap-channel enabled' " 586 + "- must be a positive integer"); 587 return -1; 588 } 589 int apChannel = ScanResult.convertFrequencyMhzToChannelIfSupported( 590 apChannelMHz); 591 int band = ApConfigUtil.convertFrequencyToBand(apChannelMHz); 592 pw.println("channel: " + apChannel + " band: " + band); 593 if (apChannel == -1 || band == -1) { 594 pw.println("Invalid argument to 'force-softap-channel enabled' " 595 + "- must be a valid WLAN channel"); 596 return -1; 597 } 598 boolean isTemporarilyEnablingWifiNeeded = mWifiService.getWifiEnabledState() 599 != WIFI_STATE_ENABLED; 600 if (isTemporarilyEnablingWifiNeeded) { 601 waitForWifiEnabled(true); 602 } 603 // Following calls will fail if wifi is not enabled 604 boolean isValidChannel = isApChannelMHzValid(pw, apChannelMHz); 605 if (isTemporarilyEnablingWifiNeeded) { 606 waitForWifiEnabled(false); 607 } 608 if (!isValidChannel 609 || (band == SoftApConfiguration.BAND_5GHZ 610 && !mWifiService.is5GHzBandSupported()) 611 || (band == SoftApConfiguration.BAND_6GHZ 612 && !mWifiService.is6GHzBandSupported()) 613 || (band == SoftApConfiguration.BAND_60GHZ 614 && !mWifiService.is60GHzBandSupported())) { 615 pw.println("Invalid argument to 'force-softap-channel enabled' " 616 + "- must be a valid WLAN channel" 617 + " in a band supported by the device"); 618 return -1; 619 } 620 mWifiApConfigStore.enableForceSoftApBandOrChannel(band, apChannel); 621 return 0; 622 } else { 623 mWifiApConfigStore.disableForceSoftApBandOrChannel(); 624 return 0; 625 } 626 } 627 case "set-pno-request": { 628 if (!SdkLevel.isAtLeastT()) { 629 pw.println("This feature is only supported on SdkLevel T or later."); 630 return -1; 631 } 632 String ssid = getNextArgRequired(); 633 int frequency = -1; 634 WifiSsid wifiSsid = WifiSsid.fromString("\"" + ssid + "\""); 635 String option = getNextOption(); 636 if (option != null) { 637 if (option.equals("-f")) { 638 frequency = Integer.parseInt(getNextArgRequired()); 639 } else { 640 pw.println("Invalid argument to 'set-pno-request' " 641 + "- only allowed option is '-f'"); 642 return -1; 643 } 644 } 645 int[] frequencies = frequency == -1 ? new int[0] : new int[] {frequency}; 646 IPnoScanResultsCallback.Stub callback = new IPnoScanResultsCallback.Stub() { 647 @Override 648 public void onScanResultsAvailable(List<ScanResult> scanResults) { 649 Log.v(TAG, "PNO scan results available:"); 650 for (ScanResult result : scanResults) { 651 Log.v(TAG, result.getWifiSsid().toString()); 652 } 653 } 654 @Override 655 public void onRegisterSuccess() { 656 Log.v(TAG, "PNO scan request register success"); 657 } 658 659 @Override 660 public void onRegisterFailed(int reason) { 661 Log.v(TAG, "PNO scan request register failed reason=" + reason); 662 } 663 664 @Override 665 public void onRemoved(int reason) { 666 Log.v(TAG, "PNO scan request callback removed reason=" + reason); 667 } 668 }; 669 pw.println("requesting PNO scan for: " + wifiSsid); 670 mWifiService.setExternalPnoScanRequest(new Binder(), callback, 671 Arrays.asList(wifiSsid), frequencies, mContext.getOpPackageName(), 672 mContext.getAttributionTag()); 673 return 0; 674 } 675 case "clear-pno-request": { 676 if (!SdkLevel.isAtLeastT()) { 677 pw.println("This feature is only supported on SdkLevel T or later."); 678 return -1; 679 } 680 mWifiService.clearExternalPnoScanRequest(); 681 return 0; 682 } 683 case "start-lohs": { 684 CountDownLatch countDownLatch = new CountDownLatch(2); 685 SoftApConfiguration config = buildSoftApConfiguration(pw); 686 ILocalOnlyHotspotCallback.Stub lohsCallback = 687 new ILocalOnlyHotspotCallback.Stub() { 688 @Override 689 public void onHotspotStarted(SoftApConfiguration config) { 690 pw.println("Lohs onStarted, config = " + config); 691 countDownLatch.countDown(); 692 } 693 694 @Override 695 public void onHotspotStopped() { 696 pw.println("Lohs onStopped"); 697 countDownLatch.countDown(); 698 } 699 700 @Override 701 public void onHotspotFailed(int reason) { 702 pw.println("Lohs onFailed: " + reason); 703 countDownLatch.countDown(); 704 } 705 }; 706 SoftApCallbackProxy softApCallback = 707 new SoftApCallbackProxy(pw, countDownLatch); 708 Bundle extras = new Bundle(); 709 if (SdkLevel.isAtLeastS()) { 710 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, 711 mContext.getAttributionSource()); 712 } 713 mWifiService.registerLocalOnlyHotspotSoftApCallback(softApCallback, extras); 714 if (REQUEST_REGISTERED != mWifiService.startLocalOnlyHotspot( 715 lohsCallback, SHELL_PACKAGE_NAME, null /* featureId */, 716 config, extras)) { 717 pw.println("Lohs failed to start. Please check config parameters"); 718 } 719 // Wait for lohs to start and complete callback 720 countDownLatch.await(10000, TimeUnit.MILLISECONDS); 721 mWifiService.unregisterLocalOnlyHotspotSoftApCallback(softApCallback, extras); 722 return 0; 723 } 724 case "start-softap": { 725 CountDownLatch countDownLatch = new CountDownLatch(1); 726 SoftApConfiguration config = buildSoftApConfiguration(pw); 727 SoftApCallbackProxy softApCallback = 728 new SoftApCallbackProxy(pw, countDownLatch); 729 mWifiService.registerSoftApCallback(softApCallback); 730 if (!mWifiService.startTetheredHotspot(config, SHELL_PACKAGE_NAME)) { 731 pw.println("Soft AP failed to start. Please check config parameters"); 732 } 733 // Wait for softap to start and complete callback 734 countDownLatch.await(10000, TimeUnit.MILLISECONDS); 735 mWifiService.unregisterSoftApCallback(softApCallback); 736 return 0; 737 } 738 case "stop-lohs": { 739 mWifiService.stopLocalOnlyHotspot(); 740 pw.println("Lohs stopped successfully"); 741 return 0; 742 } 743 case "stop-softap": { 744 if (mWifiService.stopSoftAp()) { 745 pw.println("Soft AP stopped successfully"); 746 } else { 747 pw.println("Soft AP failed to stop"); 748 } 749 return 0; 750 } 751 case "reload-resources": { 752 mContext.resetResourceCache(); 753 return 0; 754 } 755 case "force-country-code": { 756 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 757 if (enabled) { 758 String countryCode = getNextArgRequired(); 759 if (!WifiCountryCode.isValid(countryCode)) { 760 pw.println("Invalid argument: Country code must be a 2-Character" 761 + " alphanumeric code. But got countryCode " + countryCode 762 + " instead"); 763 return -1; 764 } 765 mWifiCountryCode.setOverrideCountryCode(countryCode); 766 return 0; 767 } else { 768 mWifiCountryCode.clearOverrideCountryCode(); 769 return 0; 770 } 771 } 772 case "get-country-code": { 773 pw.println("Wifi Country Code = " 774 + mWifiCountryCode.getCountryCode()); 775 return 0; 776 } 777 case "set-wifi-watchdog": { 778 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 779 mWifiLastResortWatchdog.setWifiWatchdogFeature(enabled); 780 return 0; 781 } 782 case "get-wifi-watchdog": { 783 pw.println("wifi watchdog state is " 784 + mWifiLastResortWatchdog.getWifiWatchdogFeature()); 785 return 0; 786 } 787 case "set-wifi-enabled": { 788 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 789 mWifiService.setWifiEnabled(SHELL_PACKAGE_NAME, enabled); 790 return 0; 791 } 792 case "set-passpoint-enabled": { 793 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 794 mWifiService.setWifiPasspointEnabled(enabled); 795 return 0; 796 } 797 case "set-multi-internet-mode": { 798 int mode = Integer.parseInt(getNextArgRequired()); 799 mWifiService.setStaConcurrencyForMultiInternetMode(mode); 800 return 0; 801 } 802 case "set-scan-always-available": { 803 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 804 mWifiService.setScanAlwaysAvailable(enabled, SHELL_PACKAGE_NAME); 805 return 0; 806 } 807 case "get-softap-supported-features": 808 // This command is used for vts to check softap supported features. 809 if (ApConfigUtil.isAcsSupported(mContext)) { 810 pw.println("wifi_softap_acs_supported"); 811 } 812 if (ApConfigUtil.isWpa3SaeSupported(mContext)) { 813 pw.println("wifi_softap_wpa3_sae_supported"); 814 } 815 if ((mWifiService.getSupportedFeatures() 816 & WifiManager.WIFI_FEATURE_BRIDGED_AP) 817 == WifiManager.WIFI_FEATURE_BRIDGED_AP) { 818 pw.println("wifi_softap_bridged_ap_supported"); 819 } 820 if ((mWifiService.getSupportedFeatures() 821 & WifiManager.WIFI_FEATURE_STA_BRIDGED_AP) 822 == WifiManager.WIFI_FEATURE_STA_BRIDGED_AP) { 823 pw.println("wifi_softap_bridged_ap_with_sta_supported"); 824 } 825 return 0; 826 case "settings-reset": 827 mWifiNative.stopFakingScanDetails(); 828 mWifiNative.resetFakeScanDetails(); 829 mWifiService.factoryReset(SHELL_PACKAGE_NAME); 830 return 0; 831 case "list-scan-results": 832 List<ScanResult> scanResults = 833 mWifiService.getScanResults(SHELL_PACKAGE_NAME, null); 834 if (scanResults.isEmpty()) { 835 pw.println("No scan results"); 836 } else { 837 ScanResultUtil.dumpScanResults(pw, scanResults, 838 SystemClock.elapsedRealtime()); 839 } 840 return 0; 841 case "start-scan": 842 mWifiService.startScan(SHELL_PACKAGE_NAME, null); 843 return 0; 844 case "list-networks": 845 ParceledListSlice<WifiConfiguration> networks = 846 mWifiService.getConfiguredNetworks(SHELL_PACKAGE_NAME, null, false); 847 if (networks == null || networks.getList().isEmpty()) { 848 pw.println("No networks"); 849 } else { 850 pw.println("Network Id SSID Security type"); 851 for (WifiConfiguration network : networks.getList()) { 852 String securityType = network.getSecurityParamsList().stream() 853 .map(p -> WifiConfiguration.getSecurityTypeName( 854 p.getSecurityType()) 855 + (p.isAddedByAutoUpgrade() ? "^" : "")) 856 .collect(Collectors.joining("/")); 857 pw.println(String.format("%-12d %-32s %-4s", 858 network.networkId, WifiInfo.sanitizeSsid(network.SSID), 859 securityType)); 860 } 861 } 862 return 0; 863 case "connect-network": { 864 CountDownLatch countDownLatch = new CountDownLatch(1); 865 IActionListener.Stub actionListener = new IActionListener.Stub() { 866 @Override 867 public void onSuccess() throws RemoteException { 868 pw.println("Connection initiated "); 869 countDownLatch.countDown(); 870 } 871 872 @Override 873 public void onFailure(int i) throws RemoteException { 874 pw.println("Connection failed"); 875 countDownLatch.countDown(); 876 } 877 }; 878 WifiConfiguration config = buildWifiConfiguration(pw); 879 mWifiService.connect(config, -1, actionListener, SHELL_PACKAGE_NAME); 880 // wait for status. 881 countDownLatch.await(500, TimeUnit.MILLISECONDS); 882 setAutoJoin(pw, config.SSID, config.allowAutojoin); 883 return 0; 884 } 885 case "add-network": { 886 CountDownLatch countDownLatch = new CountDownLatch(1); 887 IActionListener.Stub actionListener = new IActionListener.Stub() { 888 @Override 889 public void onSuccess() throws RemoteException { 890 pw.println("Save successful"); 891 countDownLatch.countDown(); 892 } 893 894 @Override 895 public void onFailure(int i) throws RemoteException { 896 pw.println("Save failed"); 897 countDownLatch.countDown(); 898 } 899 }; 900 WifiConfiguration config = buildWifiConfiguration(pw); 901 mWifiService.save(config, actionListener, SHELL_PACKAGE_NAME); 902 // wait for status. 903 countDownLatch.await(500, TimeUnit.MILLISECONDS); 904 setAutoJoin(pw, config.SSID, config.allowAutojoin); 905 return 0; 906 } 907 case "forget-network": { 908 String networkId = getNextArgRequired(); 909 CountDownLatch countDownLatch = new CountDownLatch(1); 910 IActionListener.Stub actionListener = new IActionListener.Stub() { 911 @Override 912 public void onSuccess() throws RemoteException { 913 pw.println("Forget successful"); 914 countDownLatch.countDown(); 915 } 916 917 @Override 918 public void onFailure(int i) throws RemoteException { 919 pw.println("Forget failed"); 920 countDownLatch.countDown(); 921 } 922 }; 923 mWifiService.forget(Integer.parseInt(networkId), actionListener); 924 // wait for status. 925 countDownLatch.await(500, TimeUnit.MILLISECONDS); 926 return 0; 927 } 928 case "pmksa-flush": { 929 String networkId = getNextArgRequired(); 930 int netId = Integer.parseInt(networkId); 931 WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId); 932 if (config == null) { 933 pw.println("No Wifi config corresponding to networkId: " + netId); 934 return -1; 935 } 936 mWifiNative.removeNetworkCachedData(netId); 937 return 0; 938 } 939 case "status": 940 printStatus(pw); 941 return 0; 942 case "set-verbose-logging": { 943 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 944 mWifiService.enableVerboseLogging(enabled ? 1 : 0); 945 return 0; 946 } 947 case "is-verbose-logging": { 948 int enabled = mWifiService.getVerboseLoggingLevel(); 949 pw.println(enabled > 0 ? "enabled" : "disabled"); 950 return 0; 951 } 952 case "start-restricting-auto-join-to-subscription-id": { 953 if (!SdkLevel.isAtLeastS()) { 954 pw.println("This feature is only supported on SdkLevel S or later."); 955 return -1; 956 } 957 int subId = Integer.parseInt(getNextArgRequired()); 958 mWifiService.startRestrictingAutoJoinToSubscriptionId(subId); 959 return 0; 960 } 961 case "stop-restricting-auto-join-to-subscription-id": { 962 if (!SdkLevel.isAtLeastS()) { 963 pw.println("This feature is only supported on SdkLevel S or later."); 964 return -1; 965 } 966 mWifiService.stopRestrictingAutoJoinToSubscriptionId(); 967 return 0; 968 } 969 case "add-suggestion": { 970 WifiNetworkSuggestion suggestion = buildSuggestion(pw); 971 if (suggestion == null) { 972 pw.println("Invalid network suggestion parameter"); 973 return -1; 974 } 975 int errorCode = mWifiService.addNetworkSuggestions( 976 Arrays.asList(suggestion), SHELL_PACKAGE_NAME, null); 977 if (errorCode != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 978 pw.println("Add network suggestion failed with error code: " + errorCode); 979 return -1; 980 } 981 // untrusted/oem-paid networks need a corresponding NetworkRequest. 982 if (suggestion.isUntrusted() 983 || (SdkLevel.isAtLeastS() 984 && (suggestion.isOemPaid() || suggestion.isOemPrivate()))) { 985 NetworkRequest.Builder networkRequestBuilder = 986 new NetworkRequest.Builder() 987 .addTransportType(TRANSPORT_WIFI); 988 if (suggestion.isUntrusted()) { 989 networkRequestBuilder.removeCapability(NET_CAPABILITY_TRUSTED); 990 } 991 if (SdkLevel.isAtLeastS()) { 992 if (suggestion.isOemPaid()) { 993 networkRequestBuilder.addCapability(NET_CAPABILITY_OEM_PAID); 994 } 995 if (suggestion.isOemPrivate()) { 996 networkRequestBuilder.addCapability(NET_CAPABILITY_OEM_PRIVATE); 997 } 998 } 999 NetworkRequest networkRequest = networkRequestBuilder.build(); 1000 ConnectivityManager.NetworkCallback networkCallback = 1001 new ConnectivityManager.NetworkCallback(); 1002 pw.println("Adding request: " + networkRequest); 1003 mConnectivityManager.requestNetwork(networkRequest, networkCallback); 1004 sActiveRequests.put( 1005 suggestion.getSsid(), Pair.create(networkRequest, networkCallback)); 1006 } 1007 return 0; 1008 } 1009 case "remove-suggestion": { 1010 String ssid = getNextArgRequired(); 1011 String action = getNextArg(); 1012 int actionCode = ACTION_REMOVE_SUGGESTION_DISCONNECT; 1013 if (action != null && action.equals("lingering")) { 1014 actionCode = ACTION_REMOVE_SUGGESTION_LINGER; 1015 } 1016 List<WifiNetworkSuggestion> suggestions = 1017 mWifiService.getNetworkSuggestions(SHELL_PACKAGE_NAME); 1018 WifiNetworkSuggestion suggestion = suggestions.stream() 1019 .filter(s -> s.getSsid().equals(ssid)) 1020 .findAny() 1021 .orElse(null); 1022 if (suggestion == null) { 1023 pw.println("No matching suggestion to remove"); 1024 return -1; 1025 } 1026 mWifiService.removeNetworkSuggestions( 1027 Arrays.asList(suggestion), SHELL_PACKAGE_NAME, actionCode); 1028 // untrusted/oem-paid networks need a corresponding NetworkRequest. 1029 if (suggestion.isUntrusted() 1030 || (SdkLevel.isAtLeastS() 1031 && (suggestion.isOemPaid() || suggestion.isOemPrivate()))) { 1032 Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc = 1033 sActiveRequests.remove(suggestion.getSsid()); 1034 if (nrAndNc == null) { 1035 pw.println("No matching request to remove"); 1036 return -1; 1037 } 1038 pw.println("Removing request: " + nrAndNc.first); 1039 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 1040 } 1041 return 0; 1042 } 1043 case "remove-all-suggestions": 1044 mWifiService.removeNetworkSuggestions( 1045 Collections.emptyList(), SHELL_PACKAGE_NAME, 1046 WifiManager.ACTION_REMOVE_SUGGESTION_DISCONNECT); 1047 return 0; 1048 case "list-suggestions": { 1049 List<WifiNetworkSuggestion> suggestions = 1050 mWifiService.getNetworkSuggestions(SHELL_PACKAGE_NAME); 1051 printWifiNetworkSuggestions(pw, suggestions); 1052 return 0; 1053 } 1054 case "list-all-suggestions": { 1055 Set<WifiNetworkSuggestion> suggestions = 1056 mWifiNetworkSuggestionsManager.getAllNetworkSuggestions(); 1057 printWifiNetworkSuggestions(pw, suggestions); 1058 return 0; 1059 } 1060 case "list-suggestions-from-app": { 1061 String packageName = getNextArgRequired(); 1062 List<WifiNetworkSuggestion> suggestions = 1063 mWifiService.getNetworkSuggestions(packageName); 1064 printWifiNetworkSuggestions(pw, suggestions); 1065 return 0; 1066 } 1067 case "add-request": { 1068 Pair<String, NetworkRequest> result = buildNetworkRequest(pw); 1069 String ssid = result.first; 1070 NetworkRequest networkRequest = result.second; 1071 ConnectivityManager.NetworkCallback networkCallback = 1072 new ConnectivityManager.NetworkCallback(); 1073 pw.println("Adding request: " + networkRequest); 1074 mConnectivityManager.requestNetwork(networkRequest, networkCallback); 1075 sActiveRequests.put(ssid, Pair.create(networkRequest, networkCallback)); 1076 return 0; 1077 } 1078 case "remove-request": { 1079 String ssid = getNextArgRequired(); 1080 Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc = 1081 sActiveRequests.remove(ssid); 1082 if (nrAndNc == null) { 1083 pw.println("No matching request to remove"); 1084 return -1; 1085 } 1086 pw.println("Removing request: " + nrAndNc.first); 1087 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 1088 return 0; 1089 } 1090 case "remove-all-requests": 1091 if (sActiveRequests.isEmpty()) { 1092 pw.println("No active requests"); 1093 return -1; 1094 } 1095 for (Pair<NetworkRequest, ConnectivityManager.NetworkCallback> nrAndNc 1096 : sActiveRequests.values()) { 1097 pw.println("Removing request: " + nrAndNc.first); 1098 mConnectivityManager.unregisterNetworkCallback(nrAndNc.second); 1099 } 1100 sActiveRequests.clear(); 1101 return 0; 1102 case "list-requests": 1103 if (sActiveRequests.isEmpty()) { 1104 pw.println("No active requests"); 1105 } else { 1106 pw.println("SSID NetworkRequest"); 1107 for (Map.Entry<String, 1108 Pair<NetworkRequest, ConnectivityManager.NetworkCallback>> entry : 1109 sActiveRequests.entrySet()) { 1110 pw.println(String.format("%-32s %-4s", 1111 entry.getKey(), entry.getValue().first)); 1112 } 1113 } 1114 return 0; 1115 case "network-requests-set-user-approved": { 1116 String packageName = getNextArgRequired(); 1117 boolean approved = getNextArgRequiredTrueOrFalse("yes", "no"); 1118 mWifiNetworkFactory.setUserApprovedApp(packageName, approved); 1119 return 0; 1120 } 1121 case "network-requests-has-user-approved": { 1122 String packageName = getNextArgRequired(); 1123 boolean hasUserApproved = mWifiNetworkFactory.hasUserApprovedApp(packageName); 1124 pw.println(hasUserApproved ? "yes" : "no"); 1125 return 0; 1126 } 1127 case "set-coex-cell-channels": { 1128 if (!SdkLevel.isAtLeastS()) { 1129 return handleDefaultCommands(cmd); 1130 } 1131 mCoexManager.setMockCellChannels(buildCoexCellChannels()); 1132 return 0; 1133 } 1134 case "reset-coex-cell-channels": { 1135 if (!SdkLevel.isAtLeastS()) { 1136 return handleDefaultCommands(cmd); 1137 } 1138 mCoexManager.resetMockCellChannels(); 1139 return 0; 1140 } 1141 case "get-coex-cell-channels": { 1142 if (!SdkLevel.isAtLeastS()) { 1143 return handleDefaultCommands(cmd); 1144 } 1145 pw.println("Cell channels: " + mCoexManager.getCellChannels()); 1146 return 0; 1147 } 1148 case "set-connected-score": { 1149 int score = Integer.parseInt(getNextArgRequired()); 1150 CountDownLatch countDownLatch = new CountDownLatch(2); 1151 mWifiService.clearWifiConnectedNetworkScorer(); // clear any previous scorer 1152 WifiScorer connectedScorer = new WifiScorer(mWifiService, countDownLatch); 1153 if (mWifiService.setWifiConnectedNetworkScorer(new Binder(), connectedScorer)) { 1154 // wait for retrieving the session id & score observer. 1155 countDownLatch.await(1000, TimeUnit.MILLISECONDS); 1156 } 1157 if (connectedScorer.getSessionId() == null 1158 || connectedScorer.getScoreUpdateObserver() == null) { 1159 pw.println("Did not receive session id and/or the score update observer. " 1160 + "Is the device connected to a wifi network?"); 1161 mWifiService.clearWifiConnectedNetworkScorer(); 1162 return -1; 1163 } 1164 pw.println("Updating score: " + score + " for session id: " 1165 + connectedScorer.getSessionId()); 1166 try { 1167 connectedScorer.getScoreUpdateObserver().notifyScoreUpdate( 1168 connectedScorer.getSessionId(), score); 1169 } catch (RemoteException e) { 1170 pw.println("Failed to send the score update"); 1171 mWifiService.clearWifiConnectedNetworkScorer(); 1172 return -1; 1173 } 1174 return 0; 1175 } 1176 case "reset-connected-score": { 1177 mWifiService.clearWifiConnectedNetworkScorer(); // clear any previous scorer 1178 return 0; 1179 } 1180 case "network-suggestions-set-as-carrier-provider": { 1181 String packageName = getNextArgRequired(); 1182 boolean enabled = getNextArgRequiredTrueOrFalse("yes", "no"); 1183 mWifiNetworkSuggestionsManager 1184 .setAppWorkingAsCrossCarrierProvider(packageName, enabled); 1185 return 0; 1186 } 1187 case "is-network-suggestions-set-as-carrier-provider": { 1188 String packageName = getNextArgRequired(); 1189 pw.println(mWifiNetworkSuggestionsManager 1190 .isAppWorkingAsCrossCarrierProvider(packageName) ? "yes" : "no"); 1191 return 0; 1192 } 1193 case "remove-shell-app-from-suggestion_database <packageName>": { 1194 String packageName = getNextArgRequired(); 1195 mWifiNetworkSuggestionsManager.removeApp(packageName); 1196 return 0; 1197 } 1198 case "set-emergency-callback-mode": { 1199 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 1200 mActiveModeWarden.emergencyCallbackModeChanged(enabled); 1201 return 0; 1202 } 1203 case "set-emergency-call-state": { 1204 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 1205 mActiveModeWarden.emergencyCallStateChanged(enabled); 1206 return 0; 1207 } 1208 case "trigger-recovery": { 1209 mSelfRecovery.trigger(REASON_API_CALL); 1210 return 0; 1211 } 1212 case "add-fake-scan": { 1213 String option = getNextOption(); 1214 boolean isHex = (option != null && option.equals("-x")); 1215 WifiSsid wifiSsid = WifiSsid.fromBytes(isHex 1216 ? HexEncoding.decode(getNextArgRequired()) 1217 : getNextArgRequired().getBytes(StandardCharsets.UTF_8)); 1218 String bssid = getNextArgRequired(); 1219 String capabilities = getNextArgRequired(); 1220 int frequency; 1221 int dbm; 1222 String freqStr = getNextArgRequired(); 1223 try { 1224 frequency = Integer.parseInt(freqStr); 1225 } catch (NumberFormatException e) { 1226 pw.println( 1227 "Invalid frequency argument to 'add-fake-scan' " 1228 + "- must be an integer: " + freqStr); 1229 return -1; 1230 } 1231 if (frequency <= 0) { 1232 pw.println("Invalid frequency argument to 'add-fake-scan' - must be a " 1233 + "positive integer: " + freqStr); 1234 } 1235 String dbmString = getNextArgRequired(); 1236 try { 1237 dbm = Integer.parseInt(dbmString); 1238 } catch (NumberFormatException e) { 1239 pw.println( 1240 "Invalid dbm argument to 'add-fake-scan' " 1241 + "- must be an integer: " + dbmString); 1242 return -1; 1243 } 1244 ScanResult.InformationElement ieSSid = new ScanResult.InformationElement( 1245 ScanResult.InformationElement.EID_SSID, 1246 0, 1247 wifiSsid.getBytes()); 1248 ScanResult.InformationElement[] ies = 1249 new ScanResult.InformationElement[]{ieSSid}; 1250 ScanDetail sd = new ScanDetail(new NetworkDetail(bssid, ies, null, frequency), 1251 wifiSsid, bssid, capabilities, dbm, 1252 frequency, SystemClock.elapsedRealtime() * 1000, ies, null, null); 1253 mWifiNative.addFakeScanDetail(sd); 1254 return 0; 1255 } 1256 case "reset-fake-scans": 1257 mWifiNative.resetFakeScanDetails(); 1258 return 0; 1259 case "start-faking-scans": 1260 mWifiNative.startFakingScanDetails(); 1261 mWifiService.startScan(SHELL_PACKAGE_NAME, null); // to trigger update 1262 return 0; 1263 case "stop-faking-scans": 1264 mWifiNative.stopFakingScanDetails(); 1265 return 0; 1266 case "enable-scanning": { 1267 boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled"); 1268 boolean hiddenEnabled = false; 1269 String option = getNextOption(); 1270 if (option != null) { 1271 if (option.equals("-h")) { 1272 hiddenEnabled = true; 1273 } else { 1274 pw.println("Invalid argument to 'enable-scanning' " 1275 + "- only allowed option is '-h'"); 1276 return -1; 1277 } 1278 } 1279 mScanRequestProxy.enableScanning(enabled, hiddenEnabled); 1280 return 0; 1281 } 1282 case "launch-dialog-simple": 1283 String title = null; 1284 String message = null; 1285 String messageUrl = null; 1286 int messageUrlStart = 0; 1287 int messageUrlEnd = 0; 1288 String positiveButtonText = null; 1289 String negativeButtonText = null; 1290 String neutralButtonText = null; 1291 String dialogOption = getNextOption(); 1292 boolean simpleTimeoutSpecified = false; 1293 long simpleTimeoutMs = 0; 1294 while (dialogOption != null) { 1295 switch (dialogOption) { 1296 case "-t": 1297 title = getNextArgRequired(); 1298 break; 1299 case "-m": 1300 message = getNextArgRequired(); 1301 break; 1302 case "-l": 1303 messageUrl = getNextArgRequired(); 1304 messageUrlStart = Integer.valueOf(getNextArgRequired()); 1305 messageUrlEnd = Integer.valueOf(getNextArgRequired()); 1306 break; 1307 case "-y": 1308 positiveButtonText = getNextArgRequired(); 1309 break; 1310 case "-n": 1311 negativeButtonText = getNextArgRequired(); 1312 break; 1313 case "-x": 1314 neutralButtonText = getNextArgRequired(); 1315 break; 1316 case "-c": 1317 simpleTimeoutMs = Integer.parseInt(getNextArgRequired()); 1318 simpleTimeoutSpecified = true; 1319 break; 1320 default: 1321 pw.println("Ignoring unknown option " + dialogOption); 1322 break; 1323 } 1324 dialogOption = getNextOption(); 1325 } 1326 ArrayBlockingQueue<String> simpleQueue = new ArrayBlockingQueue<>(1); 1327 WifiDialogManager.SimpleDialogCallback wifiEnableRequestCallback = 1328 new WifiDialogManager.SimpleDialogCallback() { 1329 @Override 1330 public void onPositiveButtonClicked() { 1331 simpleQueue.offer("Positive button was clicked."); 1332 } 1333 1334 @Override 1335 public void onNegativeButtonClicked() { 1336 simpleQueue.offer("Negative button was clicked."); 1337 } 1338 1339 @Override 1340 public void onNeutralButtonClicked() { 1341 simpleQueue.offer("Neutral button was clicked."); 1342 } 1343 1344 @Override 1345 public void onCancelled() { 1346 simpleQueue.offer("Dialog was cancelled."); 1347 } 1348 }; 1349 WifiDialogManager.DialogHandle simpleDialogHandle = 1350 mWifiDialogManager.createSimpleDialogWithUrl( 1351 title, 1352 message, 1353 messageUrl, 1354 messageUrlStart, 1355 messageUrlEnd, 1356 positiveButtonText, 1357 negativeButtonText, 1358 neutralButtonText, 1359 wifiEnableRequestCallback, 1360 mWifiThreadRunner); 1361 if (simpleTimeoutSpecified) { 1362 simpleDialogHandle.launchDialog(simpleTimeoutMs); 1363 pw.println("Launched dialog with " + simpleTimeoutMs + " millisecond" 1364 + " timeout. Waiting for user response..."); 1365 pw.flush(); 1366 String dialogResponse = simpleQueue.take(); 1367 if (dialogResponse == null) { 1368 pw.println("No response received."); 1369 } else { 1370 pw.println(dialogResponse); 1371 } 1372 } else { 1373 simpleDialogHandle.launchDialog(); 1374 pw.println("Launched dialog. Waiting up to 15 seconds for user response" 1375 + " before dismissing..."); 1376 pw.flush(); 1377 String dialogResponse = simpleQueue.poll(15, TimeUnit.SECONDS); 1378 if (dialogResponse == null) { 1379 pw.println("No response received. Dismissing dialog."); 1380 simpleDialogHandle.dismissDialog(); 1381 } else { 1382 pw.println(dialogResponse); 1383 } 1384 } 1385 return 0; 1386 case "launch-dialog-p2p-invitation-sent": { 1387 int displayId = Display.DEFAULT_DISPLAY; 1388 String deviceName = getNextArgRequired(); 1389 String displayPin = getNextArgRequired(); 1390 String cmdOption = getNextOption(); 1391 if (cmdOption != null && cmdOption.equals("-i")) { 1392 String displayIdStr = getNextArgRequired(); 1393 try { 1394 displayId = Integer.parseInt(displayIdStr); 1395 } catch (NumberFormatException e) { 1396 pw.println("Invalid <display-id> argument to " 1397 + "'launch-dialog-p2p-invitation-sent' " 1398 + "- must be an integer: " 1399 + displayIdStr); 1400 return -1; 1401 } 1402 DisplayManager dm = mContext.getSystemService(DisplayManager.class); 1403 Display[] displays = dm.getDisplays(); 1404 for (Display display : displays) { 1405 pw.println("Display: id=" + display.getDisplayId() + ", info=" 1406 + display.getDeviceProductInfo()); 1407 } 1408 } 1409 mWifiDialogManager.createP2pInvitationSentDialog(deviceName, displayPin, 1410 displayId).launchDialog(); 1411 pw.println("Launched dialog."); 1412 return 0; 1413 } 1414 case "launch-dialog-p2p-invitation-received": { 1415 String deviceName = getNextArgRequired(); 1416 boolean isPinRequested = false; 1417 String displayPin = null; 1418 String pinOption = getNextOption(); 1419 int displayId = Display.DEFAULT_DISPLAY; 1420 boolean p2pInvRecTimeoutSpecified = false; 1421 long p2pInvRecTimeout = 0; 1422 while (pinOption != null) { 1423 if (pinOption.equals("-p")) { 1424 isPinRequested = true; 1425 } else if (pinOption.equals("-d")) { 1426 displayPin = getNextArgRequired(); 1427 } else if (pinOption.equals("-i")) { 1428 String displayIdStr = getNextArgRequired(); 1429 try { 1430 displayId = Integer.parseInt(displayIdStr); 1431 } catch (NumberFormatException e) { 1432 pw.println("Invalid <display-id> argument to " 1433 + "'launch-dialog-p2p-invitation-received' " 1434 + "- must be an integer: " 1435 + displayIdStr); 1436 return -1; 1437 } 1438 DisplayManager dm = mContext.getSystemService(DisplayManager.class); 1439 Display[] displays = dm.getDisplays(); 1440 for (Display display : displays) { 1441 pw.println("Display: id=" + display.getDisplayId() + ", info=" 1442 + display.getDeviceProductInfo()); 1443 } 1444 } else if (pinOption.equals("-c")) { 1445 p2pInvRecTimeout = Integer.parseInt(getNextArgRequired()); 1446 p2pInvRecTimeoutSpecified = true; 1447 } else { 1448 pw.println("Ignoring unknown option " + pinOption); 1449 } 1450 pinOption = getNextOption(); 1451 } 1452 ArrayBlockingQueue<String> p2pInvRecQueue = new ArrayBlockingQueue<>(1); 1453 WifiDialogManager.P2pInvitationReceivedDialogCallback callback = 1454 new WifiDialogManager.P2pInvitationReceivedDialogCallback() { 1455 @Override 1456 public void onAccepted(@Nullable String optionalPin) { 1457 p2pInvRecQueue.offer("Invitation accepted with optionalPin=" 1458 + optionalPin); 1459 } 1460 1461 @Override 1462 public void onDeclined() { 1463 p2pInvRecQueue.offer("Invitation declined"); 1464 } 1465 }; 1466 WifiDialogManager.DialogHandle p2pInvitationReceivedDialogHandle = 1467 mWifiDialogManager.createP2pInvitationReceivedDialog( 1468 deviceName, 1469 isPinRequested, 1470 displayPin, 1471 displayId, 1472 callback, 1473 mWifiThreadRunner); 1474 if (p2pInvRecTimeoutSpecified) { 1475 p2pInvitationReceivedDialogHandle.launchDialog(p2pInvRecTimeout); 1476 pw.println("Launched dialog with " + p2pInvRecTimeout + " millisecond" 1477 + " timeout. Waiting for user response..."); 1478 pw.flush(); 1479 String dialogResponse = p2pInvRecQueue.take(); 1480 if (dialogResponse == null) { 1481 pw.println("No response received."); 1482 } else { 1483 pw.println(dialogResponse); 1484 } 1485 } else { 1486 p2pInvitationReceivedDialogHandle.launchDialog(); 1487 pw.println("Launched dialog. Waiting up to 15 seconds for user response" 1488 + " before dismissing..."); 1489 pw.flush(); 1490 String dialogResponse = p2pInvRecQueue.poll(15, TimeUnit.SECONDS); 1491 if (dialogResponse == null) { 1492 pw.println("No response received. Dismissing dialog."); 1493 p2pInvitationReceivedDialogHandle.dismissDialog(); 1494 } else { 1495 pw.println(dialogResponse); 1496 } 1497 } 1498 return 0; 1499 } 1500 case "query-interface": { 1501 String uidArg = getNextArgRequired(); 1502 int uid = 0; 1503 try { 1504 uid = Integer.parseInt(uidArg); 1505 } catch (NumberFormatException e) { 1506 pw.println( 1507 "Invalid UID specified, can't convert to an integer - " + uidArg); 1508 return -1; 1509 } 1510 String packageName = getNextArgRequired(); 1511 1512 String interfaceTypeArg = getNextArgRequired(); 1513 int interfaceType; 1514 switch (interfaceTypeArg) { 1515 case "STA": 1516 interfaceType = HDM_CREATE_IFACE_STA; 1517 break; 1518 case "AP": 1519 interfaceType = HDM_CREATE_IFACE_AP; 1520 break; 1521 case "AWARE": 1522 interfaceType = HDM_CREATE_IFACE_NAN; 1523 break; 1524 case "DIRECT": 1525 interfaceType = HDM_CREATE_IFACE_P2P; 1526 break; 1527 default: 1528 pw.println("Invalid interface type - expected STA|AP|AWARE|DIRECT: " 1529 + interfaceTypeArg); 1530 return -1; 1531 } 1532 boolean queryForNewInterface = false; 1533 String optArg = getNextArg(); 1534 if (optArg != null) { 1535 if (TextUtils.equals("-new", optArg)) { 1536 queryForNewInterface = true; 1537 } else { 1538 pw.println("Unknown extra arg --- " + optArg); 1539 return -1; 1540 } 1541 } 1542 List<Pair<Integer, WorkSource>> details = 1543 mHalDeviceManager.reportImpactToCreateIface(interfaceType, 1544 queryForNewInterface, new WorkSource(uid, packageName)); 1545 final SparseArray<String> ifaceMap = new SparseArray<String>() {{ 1546 put(HDM_CREATE_IFACE_STA, "STA"); 1547 put(HDM_CREATE_IFACE_AP, "AP"); 1548 put(HDM_CREATE_IFACE_AP_BRIDGE, "AP"); 1549 put(HDM_CREATE_IFACE_P2P, "DIRECT"); 1550 put(HDM_CREATE_IFACE_NAN, "AWARE"); 1551 }}; 1552 if (details == null) { 1553 pw.println("Can't create interface: " + interfaceTypeArg); 1554 } else if (details.size() == 0) { 1555 pw.println("Interface " + interfaceTypeArg 1556 + " can be created without destroying any other interfaces"); 1557 } else { 1558 pw.println("Interface " + interfaceTypeArg 1559 + " can be created. Following interfaces will be destroyed:"); 1560 for (Pair<Integer, WorkSource> detail : details) { 1561 pw.println(" Type=" + ifaceMap.get(detail.first) + ", WS=" 1562 + detail.second); 1563 } 1564 } 1565 return 0; 1566 } 1567 case "interface-priority-interactive-mode": { 1568 String flag = getNextArgRequired(); // enable|disable|default 1569 switch (flag) { 1570 case "enable": 1571 mInterfaceConflictManager.setUserApprovalNeededOverride(true, true); 1572 break; 1573 case "disable": 1574 mInterfaceConflictManager.setUserApprovalNeededOverride(true, false); 1575 break; 1576 case "default": 1577 mInterfaceConflictManager.setUserApprovalNeededOverride( 1578 false, /* don't care */ false); 1579 break; 1580 default: 1581 pw.println( 1582 "Invalid argument to `interface-priority-interactive-mode` - " 1583 + flag); 1584 return -1; 1585 } 1586 return 0; 1587 } 1588 case "set-one-shot-screen-on-delay-ms": { 1589 if (!SdkLevel.isAtLeastT()) { 1590 pw.println("This feature is only supported on SdkLevel T or later."); 1591 return -1; 1592 } 1593 int delay = Integer.parseInt(getNextArgRequired()); 1594 mWifiService.setOneShotScreenOnConnectivityScanDelayMillis(delay); 1595 return 0; 1596 } 1597 case "start-dpp-enrollee-responder": { 1598 CountDownLatch countDownLatch = new CountDownLatch(1); 1599 String option = getNextOption(); 1600 String info = null; 1601 int curve = 0; 1602 while (option != null) { 1603 if (option.equals("-i")) { 1604 info = getNextArgRequired(); 1605 } else if (option.equals("-c")) { 1606 curve = Integer.parseInt(getNextArgRequired()); 1607 } else { 1608 pw.println("Ignoring unknown option " + option); 1609 } 1610 option = getNextOption(); 1611 } 1612 mWifiService.startDppAsEnrolleeResponder(new Binder(), info, curve, 1613 new DppCallbackProxy(pw, countDownLatch)); 1614 // Wait for DPP callback 1615 countDownLatch.await(10000, TimeUnit.MILLISECONDS); 1616 return 0; 1617 } 1618 case "start-dpp-configurator-initiator": { 1619 CountDownLatch countDownLatch = new CountDownLatch(1); 1620 int netId = Integer.parseInt(getNextArgRequired()); 1621 int role = Integer.parseInt(getNextArgRequired()); 1622 String enrolleeUri = getNextArgRequired(); 1623 mWifiService.startDppAsConfiguratorInitiator(new Binder(), SHELL_PACKAGE_NAME, 1624 enrolleeUri, netId, role, new DppCallbackProxy(pw, countDownLatch)); 1625 // Wait for DPP callback 1626 countDownLatch.await(10000, TimeUnit.MILLISECONDS); 1627 return 0; 1628 } 1629 case "stop-dpp": 1630 mWifiService.stopDppSession(); 1631 return 0; 1632 default: 1633 return handleDefaultCommands(cmd); 1634 } 1635 } catch (IllegalArgumentException e) { 1636 pw.println("Invalid args for " + cmd + ": " + e); 1637 return -1; 1638 } catch (Exception e) { 1639 pw.println("Exception while executing WifiShellCommand: "); 1640 e.printStackTrace(pw); 1641 return -1; 1642 } 1643 } 1644 getNextArgRequiredTrueOrFalse(String trueString, String falseString)1645 private boolean getNextArgRequiredTrueOrFalse(String trueString, String falseString) 1646 throws IllegalArgumentException { 1647 String nextArg = getNextArgRequired(); 1648 if (trueString.equals(nextArg)) { 1649 return true; 1650 } else if (falseString.equals(nextArg)) { 1651 return false; 1652 } else { 1653 throw new IllegalArgumentException("Expected '" + trueString + "' or '" + falseString 1654 + "' as next arg but got '" + nextArg + "'"); 1655 } 1656 } 1657 buildWifiConfiguration(PrintWriter pw)1658 private WifiConfiguration buildWifiConfiguration(PrintWriter pw) { 1659 String ssid = getNextArgRequired(); 1660 String type = getNextArgRequired(); 1661 WifiConfiguration configuration = new WifiConfiguration(); 1662 // Wrap the SSID in double quotes for UTF-8. The quotes may be removed if the SSID is in 1663 // hexadecimal digits, specified by the [-x] option below. 1664 configuration.SSID = "\"" + ssid + "\""; 1665 if (TextUtils.equals(type, "wpa3")) { 1666 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 1667 configuration.preSharedKey = "\"" + getNextArgRequired() + "\""; 1668 } else if (TextUtils.equals(type, "wpa2")) { 1669 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 1670 configuration.preSharedKey = "\"" + getNextArgRequired() + "\""; 1671 } else if (TextUtils.equals(type, "owe")) { 1672 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 1673 } else if (TextUtils.equals(type, "open")) { 1674 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 1675 } else if (TextUtils.equals(type, "dpp")) { 1676 configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_DPP); 1677 } else { 1678 throw new IllegalArgumentException("Unknown network type " + type); 1679 } 1680 String option = getNextOption(); 1681 while (option != null) { 1682 if (option.equals("-x")) { 1683 configuration.SSID = ssid; 1684 } else if (option.equals("-m")) { 1685 configuration.meteredOverride = METERED_OVERRIDE_METERED; 1686 } else if (option.equals("-d")) { 1687 configuration.allowAutojoin = false; 1688 } else if (option.equals("-b")) { 1689 configuration.BSSID = getNextArgRequired(); 1690 } else if (option.equals("-r")) { 1691 String macRandomizationScheme = getNextArgRequired(); 1692 if (macRandomizationScheme.equals("auto")) { 1693 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO; 1694 } else if (macRandomizationScheme.equals("none")) { 1695 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; 1696 } else if (macRandomizationScheme.equals("persistent")) { 1697 configuration.macRandomizationSetting = 1698 WifiConfiguration.RANDOMIZATION_PERSISTENT; 1699 } else if (macRandomizationScheme.equals("non_persistent")) { 1700 if (SdkLevel.isAtLeastS()) { 1701 configuration.macRandomizationSetting = 1702 WifiConfiguration.RANDOMIZATION_NON_PERSISTENT; 1703 } else { 1704 throw new IllegalArgumentException( 1705 "-r non_persistent MAC randomization not supported before S"); 1706 } 1707 } 1708 } else if (option.equals("-h")) { 1709 configuration.hiddenSSID = true; 1710 } else if (option.equals("-p")) { 1711 configuration.shared = false; 1712 } else { 1713 pw.println("Ignoring unknown option " + option); 1714 } 1715 option = getNextOption(); 1716 } 1717 return configuration; 1718 } 1719 buildSoftApConfiguration(PrintWriter pw)1720 private SoftApConfiguration buildSoftApConfiguration(PrintWriter pw) { 1721 String ssidStr = getNextArgRequired(); 1722 String type = getNextArgRequired(); 1723 SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); 1724 configBuilder.setSsid(ssidStr); 1725 if (TextUtils.equals(type, "wpa2")) { 1726 configBuilder.setPassphrase(getNextArgRequired(), 1727 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); 1728 } else if (TextUtils.equals(type, "wpa3")) { 1729 configBuilder.setPassphrase(getNextArgRequired(), 1730 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE); 1731 } else if (TextUtils.equals(type, "wpa3_transition")) { 1732 configBuilder.setPassphrase(getNextArgRequired(), 1733 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION); 1734 } else if (TextUtils.equals(type, "open")) { 1735 configBuilder.setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN); 1736 } else if (TextUtils.equals(type, "owe_transition")) { 1737 configBuilder.setPassphrase(null, 1738 SoftApConfiguration.SECURITY_TYPE_WPA3_OWE_TRANSITION); 1739 } else if (TextUtils.equals(type, "owe")) { 1740 configBuilder.setPassphrase(null, 1741 SoftApConfiguration.SECURITY_TYPE_WPA3_OWE); 1742 } else { 1743 throw new IllegalArgumentException("Unknown network type " + type); 1744 } 1745 String option = getNextOption(); 1746 while (option != null) { 1747 if (option.equals("-b")) { 1748 String preferredBand = getNextArgRequired(); 1749 if (preferredBand.equals("2")) { 1750 configBuilder.setBand(SoftApConfiguration.BAND_2GHZ); 1751 } else if (preferredBand.equals("5")) { 1752 configBuilder.setBand(SoftApConfiguration.BAND_5GHZ); 1753 } else if (preferredBand.equals("6")) { 1754 configBuilder.setBand(SoftApConfiguration.BAND_6GHZ); 1755 } else if (preferredBand.equals("any")) { 1756 configBuilder.setBand(SoftApConfiguration.BAND_2GHZ 1757 | SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_6GHZ); 1758 } else if (preferredBand.equals("bridged")) { 1759 if (SdkLevel.isAtLeastS()) { 1760 int[] dualBands = new int[] { 1761 SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ}; 1762 configBuilder.setBands(dualBands); 1763 } else { 1764 throw new IllegalArgumentException( 1765 "-b bridged option is not supported before S"); 1766 } 1767 } else { 1768 throw new IllegalArgumentException("Invalid band option " + preferredBand); 1769 } 1770 } else if (SdkLevel.isAtLeastT() && option.equals("-x")) { 1771 configBuilder.setWifiSsid(WifiSsid.fromString(ssidStr)); 1772 } else { 1773 pw.println("Ignoring unknown option " + option); 1774 } 1775 option = getNextOption(); 1776 } 1777 return configBuilder.build(); 1778 } 1779 buildSuggestion(PrintWriter pw)1780 private WifiNetworkSuggestion buildSuggestion(PrintWriter pw) { 1781 String ssid = getNextArgRequired(); 1782 String type = getNextArgRequired(); 1783 WifiNetworkSuggestion.Builder suggestionBuilder = 1784 new WifiNetworkSuggestion.Builder(); 1785 suggestionBuilder.setSsid(ssid); 1786 if (TextUtils.equals(type, "wpa3")) { 1787 suggestionBuilder.setWpa3Passphrase(getNextArgRequired()); 1788 } else if (TextUtils.equals(type, "wpa2")) { 1789 suggestionBuilder.setWpa2Passphrase(getNextArgRequired()); 1790 } else if (TextUtils.equals(type, "owe")) { 1791 suggestionBuilder.setIsEnhancedOpen(true); 1792 } else if (TextUtils.equals(type, "open")) { 1793 // nothing to do. 1794 } else { 1795 throw new IllegalArgumentException("Unknown network type " + type); 1796 } 1797 boolean isCarrierMerged = false; 1798 String option = getNextOption(); 1799 while (option != null) { 1800 if (option.equals("-u")) { 1801 suggestionBuilder.setUntrusted(true); 1802 } else if (option.equals("-o")) { 1803 if (SdkLevel.isAtLeastS()) { 1804 suggestionBuilder.setOemPaid(true); 1805 } else { 1806 throw new IllegalArgumentException( 1807 "-o OEM paid suggestions not supported before S"); 1808 } 1809 } else if (option.equals("-p")) { 1810 if (SdkLevel.isAtLeastS()) { 1811 suggestionBuilder.setOemPrivate(true); 1812 } else { 1813 throw new IllegalArgumentException( 1814 "-p OEM private suggestions not supported before S"); 1815 } 1816 } else if (option.equals("-m")) { 1817 suggestionBuilder.setIsMetered(true); 1818 } else if (option.equals("-s")) { 1819 suggestionBuilder.setCredentialSharedWithUser(true); 1820 } else if (option.equals("-d")) { 1821 suggestionBuilder.setIsInitialAutojoinEnabled(false); 1822 } else if (option.equals("-b")) { 1823 suggestionBuilder.setBssid(MacAddress.fromString(getNextArgRequired())); 1824 } else if (option.equals("-r")) { 1825 if (SdkLevel.isAtLeastS()) { 1826 suggestionBuilder.setMacRandomizationSetting( 1827 WifiNetworkSuggestion.RANDOMIZATION_NON_PERSISTENT); 1828 } else { 1829 throw new IllegalArgumentException( 1830 "-r non_persistent MAC randomization not supported before S"); 1831 } 1832 } else if (option.equals("-a")) { 1833 if (SdkLevel.isAtLeastS()) { 1834 isCarrierMerged = true; 1835 } else { 1836 throw new IllegalArgumentException("-a option is not supported before S"); 1837 } 1838 } else if (option.equals("-i")) { 1839 if (SdkLevel.isAtLeastS()) { 1840 int subId = Integer.parseInt(getNextArgRequired()); 1841 suggestionBuilder.setSubscriptionId(subId); 1842 } else { 1843 throw new IllegalArgumentException( 1844 "-i subscription ID option is not supported before S"); 1845 } 1846 } else if (option.equals("-c")) { 1847 int carrierId = Integer.parseInt(getNextArgRequired()); 1848 suggestionBuilder.setCarrierId(carrierId); 1849 } else if (option.equals("-h")) { 1850 suggestionBuilder.setIsHiddenSsid(true); 1851 } else { 1852 pw.println("Ignoring unknown option " + option); 1853 } 1854 option = getNextOption(); 1855 } 1856 WifiNetworkSuggestion suggestion = suggestionBuilder.build(); 1857 if (isCarrierMerged) { 1858 if (suggestion.wifiConfiguration.subscriptionId 1859 == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1860 pw.println("Carrier merged network must have valid subscription Id"); 1861 return null; 1862 } 1863 suggestion.wifiConfiguration.carrierMerged = true; 1864 } 1865 return suggestion; 1866 } 1867 buildNetworkRequest(PrintWriter pw)1868 private Pair<String, NetworkRequest> buildNetworkRequest(PrintWriter pw) { 1869 String firstOpt = getNextOption(); 1870 boolean isGlob = "-g".equals(firstOpt); 1871 boolean noSsid = "-s".equals(firstOpt); 1872 String ssid = noSsid ? "NoSsid" : getNextArgRequired(); 1873 String type = noSsid ? null : getNextArgRequired(); 1874 WifiNetworkSpecifier.Builder specifierBuilder = 1875 new WifiNetworkSpecifier.Builder(); 1876 if (isGlob) { 1877 specifierBuilder.setSsidPattern( 1878 new PatternMatcher(ssid, PatternMatcher.PATTERN_ADVANCED_GLOB)); 1879 } else { 1880 if (ssid != null && !noSsid) specifierBuilder.setSsid(ssid); 1881 } 1882 if (type != null) { 1883 if (TextUtils.equals(type, "wpa3")) { 1884 specifierBuilder.setWpa3Passphrase(getNextArgRequired()); 1885 } else if (TextUtils.equals(type, "wpa3_transition")) { 1886 specifierBuilder.setWpa3Passphrase(getNextArgRequired()); 1887 } else if (TextUtils.equals(type, "wpa2")) { 1888 specifierBuilder.setWpa2Passphrase(getNextArgRequired()); 1889 } else if (TextUtils.equals(type, "owe")) { 1890 specifierBuilder.setIsEnhancedOpen(true); 1891 } else if (TextUtils.equals(type, "open")) { 1892 // nothing to do. 1893 } else { 1894 throw new IllegalArgumentException("Unknown network type " + type); 1895 } 1896 } 1897 String bssid = null; 1898 String option = getNextOption(); 1899 String ssidKey = ssid; 1900 boolean nullBssid = false; 1901 boolean hasInternet = false; 1902 while (option != null) { 1903 if (option.equals("-b")) { 1904 bssid = getNextArgRequired(); 1905 } else if (option.equals("-n")) { 1906 nullBssid = true; 1907 } else if (option.equals("-d")) { 1908 String band = getNextArgRequired(); 1909 ssidKey = ssidKey + "_" + band + "g"; 1910 if (band.equals("2")) { 1911 specifierBuilder.setBand(ScanResult.WIFI_BAND_24_GHZ); 1912 } else if (band.equals("5")) { 1913 specifierBuilder.setBand(ScanResult.WIFI_BAND_5_GHZ); 1914 } else if (band.equals("6")) { 1915 specifierBuilder.setBand(ScanResult.WIFI_BAND_6_GHZ); 1916 } else if (band.equals("60")) { 1917 specifierBuilder.setBand(ScanResult.WIFI_BAND_60_GHZ); 1918 } else { 1919 throw new IllegalArgumentException("Unknown band " + band); 1920 } 1921 } else if (option.equals("-i")) { 1922 ssidKey = ssidKey + "_internet"; 1923 hasInternet = true; 1924 } else { 1925 pw.println("Ignoring unknown option " + option); 1926 } 1927 option = getNextOption(); 1928 } 1929 if (bssid != null && nullBssid) { 1930 throw new IllegalArgumentException("Invalid option combination: " 1931 + "Should not use both -b and -n at the same time."); 1932 } 1933 1934 // Permission approval bypass is only available to requests with both ssid & bssid set. 1935 // So, find scan result with the best rssi level to set in the request. 1936 if (bssid == null && !nullBssid) { 1937 ScanResult matchingScanResult = 1938 mWifiService.getScanResults(SHELL_PACKAGE_NAME, null) 1939 .stream() 1940 .filter(s -> s.SSID.equals(ssid)) 1941 .max(Comparator.comparingInt(s -> s.level)) 1942 .orElse(null); 1943 if (matchingScanResult != null) { 1944 bssid = matchingScanResult.BSSID; 1945 } else { 1946 pw.println("No matching bssid found, request will need UI approval"); 1947 } 1948 } 1949 if (bssid != null && !nullBssid) specifierBuilder.setBssid(MacAddress.fromString(bssid)); 1950 NetworkRequest.Builder builder = new NetworkRequest.Builder() 1951 .addTransportType(TRANSPORT_WIFI); 1952 if (hasInternet) { 1953 builder.addCapability(NET_CAPABILITY_INTERNET); 1954 } else { 1955 builder.removeCapability(NET_CAPABILITY_INTERNET); 1956 } 1957 return new Pair<String, NetworkRequest>(ssidKey, 1958 builder.setNetworkSpecifier(specifierBuilder.build()).build()); 1959 } 1960 1961 @RequiresApi(Build.VERSION_CODES.S) 1962 @NonNull buildCoexCellChannels()1963 private List<CoexUtils.CoexCellChannel> buildCoexCellChannels() { 1964 List<CoexUtils.CoexCellChannel> cellChannels = new ArrayList<>(); 1965 while (getRemainingArgsCount() > 0) { 1966 final @Annotation.NetworkType int rat; 1967 final String ratArg = getNextArgRequired(); 1968 if (TextUtils.equals(ratArg, "lte")) { 1969 rat = TelephonyManager.NETWORK_TYPE_LTE; 1970 } else if (TextUtils.equals(ratArg, "nr")) { 1971 rat = TelephonyManager.NETWORK_TYPE_NR; 1972 } else { 1973 throw new IllegalArgumentException("Unknown rat type " + ratArg); 1974 } 1975 final int band = Integer.parseInt(getNextArgRequired()); 1976 if (band < 1 || band > 261) { 1977 throw new IllegalArgumentException("Band is " + band 1978 + " but should be a value from 1 to 261"); 1979 } 1980 final int downlinkFreqKhz = Integer.parseInt(getNextArgRequired()); 1981 if (downlinkFreqKhz < 0 && downlinkFreqKhz != PhysicalChannelConfig.FREQUENCY_UNKNOWN) { 1982 throw new IllegalArgumentException("Downlink frequency is " + downlinkFreqKhz 1983 + " but should be >= 0 or UNKNOWN: " 1984 + PhysicalChannelConfig.FREQUENCY_UNKNOWN); 1985 } 1986 final int downlinkBandwidthKhz = Integer.parseInt(getNextArgRequired()); 1987 if (downlinkBandwidthKhz <= 0 1988 && downlinkBandwidthKhz != PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN) { 1989 throw new IllegalArgumentException("Downlink bandwidth is " + downlinkBandwidthKhz 1990 + " but should be > 0 or UNKNOWN: " 1991 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN); 1992 } 1993 final int uplinkFreqKhz = Integer.parseInt(getNextArgRequired()); 1994 if (uplinkFreqKhz < 0 && uplinkFreqKhz != PhysicalChannelConfig.FREQUENCY_UNKNOWN) { 1995 throw new IllegalArgumentException("Uplink frequency is " + uplinkFreqKhz 1996 + " but should be >= 0 or UNKNOWN: " 1997 + PhysicalChannelConfig.FREQUENCY_UNKNOWN); 1998 } 1999 final int uplinkBandwidthKhz = Integer.parseInt(getNextArgRequired()); 2000 if (uplinkBandwidthKhz <= 0 2001 && uplinkBandwidthKhz != PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN) { 2002 throw new IllegalArgumentException("Uplink bandwidth is " + uplinkBandwidthKhz 2003 + " but should be > 0 or UNKNOWN: " 2004 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN); 2005 } 2006 cellChannels.add(new CoexUtils.CoexCellChannel(rat, band, 2007 downlinkFreqKhz, downlinkBandwidthKhz, uplinkFreqKhz, uplinkBandwidthKhz, 2008 SubscriptionManager.INVALID_SUBSCRIPTION_ID)); 2009 } 2010 return cellChannels; 2011 } 2012 setAutoJoin(PrintWriter pw, String ssid, boolean allowAutojoin)2013 private void setAutoJoin(PrintWriter pw, String ssid, boolean allowAutojoin) { 2014 // For suggestions, this will work only if the config has already been added 2015 // to WifiConfigManager. 2016 Bundle extras = new Bundle(); 2017 if (SdkLevel.isAtLeastS()) { 2018 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE, 2019 mContext.getAttributionSource()); 2020 } 2021 WifiConfiguration retrievedConfig = 2022 mWifiService.getPrivilegedConfiguredNetworks(SHELL_PACKAGE_NAME, null, extras) 2023 .getList() 2024 .stream() 2025 .filter(n -> n.SSID.equals(ssid)) 2026 .findAny() 2027 .orElse(null); 2028 if (retrievedConfig == null) { 2029 pw.println("Cannot retrieve config, autojoin setting skipped."); 2030 return; 2031 } 2032 mWifiService.allowAutojoin(retrievedConfig.networkId, allowAutojoin); 2033 } 2034 sendLinkProbe(PrintWriter pw)2035 private int sendLinkProbe(PrintWriter pw) throws InterruptedException { 2036 // Note: should match WifiNl80211Manager#SEND_MGMT_FRAME_TIMEOUT_MS 2037 final int sendMgmtFrameTimeoutMs = 1000; 2038 2039 ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1); 2040 mWifiThreadRunner.post(() -> 2041 mActiveModeWarden.getPrimaryClientModeManager().probeLink(new LinkProbeCallback() { 2042 @Override 2043 public void onAck(int elapsedTimeMs) { 2044 queue.offer("Link probe succeeded after " + elapsedTimeMs + " ms"); 2045 } 2046 2047 @Override 2048 public void onFailure(int reason) { 2049 queue.offer("Link probe failed with reason " 2050 + LinkProbeCallback.failureReasonToString(reason)); 2051 } 2052 }, -1)); 2053 2054 // block until msg is received, or timed out 2055 String msg = queue.poll(sendMgmtFrameTimeoutMs + 1000, TimeUnit.MILLISECONDS); 2056 if (msg == null) { 2057 pw.println("Link probe timed out"); 2058 } else { 2059 pw.println(msg); 2060 } 2061 return 0; 2062 } 2063 isApChannelMHzValid(PrintWriter pw, int apChannelMHz)2064 private boolean isApChannelMHzValid(PrintWriter pw, int apChannelMHz) { 2065 int[] allowed2gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); 2066 int[] allowed5gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ); 2067 int[] allowed5gDfsFreq = 2068 mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY); 2069 int[] allowed6gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ); 2070 int[] allowed60gFreq = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_60_GHZ); 2071 if (allowed2gFreq == null) { 2072 allowed2gFreq = new int[0]; 2073 } 2074 if (allowed5gFreq == null) { 2075 allowed5gFreq = new int[0]; 2076 } 2077 if (allowed5gDfsFreq == null) { 2078 allowed5gDfsFreq = new int[0]; 2079 } 2080 if (allowed6gFreq == null) { 2081 allowed6gFreq = new int[0]; 2082 } 2083 if (allowed60gFreq == null) { 2084 allowed60gFreq = new int[0]; 2085 } 2086 pw.println("2G freq: " + Arrays.toString(allowed2gFreq)); 2087 pw.println("5G freq: " + Arrays.toString(allowed5gFreq)); 2088 pw.println("5G DFS: " + Arrays.toString(allowed5gDfsFreq)); 2089 pw.println("6G freq: " + Arrays.toString(allowed6gFreq)); 2090 pw.println("60G freq: " + Arrays.toString(allowed60gFreq)); 2091 return (Arrays.binarySearch(allowed2gFreq, apChannelMHz) >= 0 2092 || Arrays.binarySearch(allowed5gFreq, apChannelMHz) >= 0 2093 || Arrays.binarySearch(allowed5gDfsFreq, apChannelMHz) >= 0) 2094 || Arrays.binarySearch(allowed6gFreq, apChannelMHz) >= 0 2095 || Arrays.binarySearch(allowed60gFreq, apChannelMHz) >= 0; 2096 } 2097 waitForWifiEnabled(boolean enabled)2098 private void waitForWifiEnabled(boolean enabled) throws InterruptedException { 2099 CountDownLatch countDownLatch = new CountDownLatch(1); 2100 BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { 2101 @Override 2102 public void onReceive(Context context, Intent intent) { 2103 String action = intent.getAction(); 2104 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 2105 int state = mWifiService.getWifiEnabledState(); 2106 if ((enabled && state == WIFI_STATE_ENABLED) 2107 || (!enabled && state == WIFI_STATE_DISABLED)) { 2108 countDownLatch.countDown(); 2109 } 2110 } 2111 } 2112 }; 2113 IntentFilter filter = new IntentFilter(); 2114 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 2115 mContext.registerReceiver(broadcastReceiver, filter); 2116 mWifiService.setWifiEnabled(SHELL_PACKAGE_NAME, enabled); 2117 countDownLatch.await(5000, TimeUnit.MILLISECONDS); 2118 mContext.unregisterReceiver(broadcastReceiver); 2119 } 2120 printWifiInfo(PrintWriter pw, WifiInfo info)2121 private void printWifiInfo(PrintWriter pw, WifiInfo info) { 2122 if (info.getSupplicantState() != SupplicantState.COMPLETED) { 2123 pw.println("Wifi is not connected"); 2124 return; 2125 } 2126 pw.println("Wifi is connected to " + info.getSSID()); 2127 pw.println("WifiInfo: " + info); 2128 // additional diagnostics not printed by WifiInfo.toString() 2129 pw.println("successfulTxPackets: " + info.txSuccess); 2130 pw.println("successfulTxPacketsPerSecond: " + info.getSuccessfulTxPacketsPerSecond()); 2131 pw.println("retriedTxPackets: " + info.txRetries); 2132 pw.println("retriedTxPacketsPerSecond: " + info.getRetriedTxPacketsPerSecond()); 2133 pw.println("lostTxPackets: " + info.txBad); 2134 pw.println("lostTxPacketsPerSecond: " + info.getLostTxPacketsPerSecond()); 2135 pw.println("successfulRxPackets: " + info.rxSuccess); 2136 pw.println("successfulRxPacketsPerSecond: " + info.getSuccessfulRxPacketsPerSecond()); 2137 } 2138 printStatus(PrintWriter pw)2139 private void printStatus(PrintWriter pw) { 2140 boolean wifiEnabled = mWifiService.getWifiEnabledState() == WIFI_STATE_ENABLED; 2141 pw.println("Wifi is " + (wifiEnabled ? "enabled" : "disabled")); 2142 pw.println("Wifi scanning is " 2143 + (mWifiService.isScanAlwaysAvailable() 2144 ? "always available" : "only available when wifi is enabled")); 2145 if (!wifiEnabled) { 2146 return; 2147 } 2148 if (Binder.getCallingUid() != Process.ROOT_UID) { 2149 // not privileged, just dump the primary client mode manager manager status 2150 // (public API contents). 2151 pw.println("==== Primary ClientModeManager instance ===="); 2152 printWifiInfo(pw, mWifiService.getConnectionInfo(SHELL_PACKAGE_NAME, null)); 2153 } else { 2154 // privileged, dump out all the client mode manager manager statuses 2155 for (ClientModeManager cm : mActiveModeWarden.getClientModeManagers()) { 2156 pw.println("==== ClientModeManager instance: " + cm + " ===="); 2157 WifiInfo info = cm.syncRequestConnectionInfo(); 2158 printWifiInfo(pw, info); 2159 if (info.getSupplicantState() != SupplicantState.COMPLETED) { 2160 continue; 2161 } 2162 Network network = cm.syncGetCurrentNetwork(); 2163 NetworkCapabilities capabilities = 2164 mConnectivityManager.getNetworkCapabilities(network); 2165 pw.println("NetworkCapabilities: " + capabilities); 2166 } 2167 } 2168 } 2169 onHelpNonPrivileged(PrintWriter pw)2170 private void onHelpNonPrivileged(PrintWriter pw) { 2171 pw.println(" get-country-code"); 2172 pw.println(" Gets country code as a two-letter string"); 2173 pw.println(" set-wifi-enabled enabled|disabled"); 2174 pw.println(" Enables/disables Wifi on this device."); 2175 pw.println(" set-scan-always-available enabled|disabled"); 2176 pw.println(" Sets whether scanning should be available even when wifi is off."); 2177 pw.println(" list-scan-results"); 2178 pw.println(" Lists the latest scan results"); 2179 pw.println(" start-scan"); 2180 pw.println(" Start a new scan"); 2181 pw.println(" list-networks"); 2182 pw.println(" Lists the saved networks"); 2183 pw.println(" forget-network <networkId>"); 2184 pw.println(" Remove the network mentioned by <networkId>"); 2185 pw.println(" - Use list-networks to retrieve <networkId> for the network"); 2186 pw.println(" status"); 2187 pw.println(" Current wifi status"); 2188 pw.println(" set-verbose-logging enabled|disabled "); 2189 pw.println(" Set the verbose logging enabled or disabled"); 2190 pw.println(" is-verbose-logging"); 2191 pw.println(" Check whether verbose logging enabled or disabled"); 2192 pw.println(" start-restricting-auto-join-to-subscription-id subId"); 2193 pw.println(" temporarily disable all wifi networks except merged carrier networks with" 2194 + " the given subId"); 2195 pw.println(" stop-restricting-auto-join-to-subscription-id"); 2196 pw.println(" Undo the effects of " 2197 + "start-restricting-auto-join-to-subscription-id"); 2198 pw.println(" add-suggestion <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-u] [-o] [-p] [-m] " 2199 + " [-s] [-d] [-b <bssid>] [-e] [-i] [-a <carrierId>] [-c <subscriptionId>]"); 2200 pw.println(" Add a network suggestion with provided params"); 2201 pw.println(" Use 'network-suggestions-set-user-approved " + SHELL_PACKAGE_NAME + " yes'" 2202 + " to approve suggestions added via shell (Needs root access)"); 2203 pw.println(" <ssid> - SSID of the network"); 2204 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 2205 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 2206 pw.println(" - 'open' - Open networks (Most prevalent)"); 2207 pw.println(" - 'owe' - Enhanced open networks"); 2208 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 2209 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 2210 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 2211 pw.println(" -u - Mark the suggestion untrusted."); 2212 pw.println(" -o - Mark the suggestion oem paid."); 2213 pw.println(" -p - Mark the suggestion oem private."); 2214 pw.println(" -m - Mark the suggestion metered."); 2215 pw.println(" -h - Mark the network hidden."); 2216 pw.println(" -s - Share the suggestion with user."); 2217 pw.println(" -d - Mark the suggestion autojoin disabled."); 2218 pw.println(" -b <bssid> - Set specific BSSID."); 2219 pw.println(" -r - Enable non_persistent randomization (disabled by default)"); 2220 pw.println(" -a - Mark the suggestion carrier merged"); 2221 pw.println(" -c <carrierId> - set carrier Id"); 2222 pw.println(" -i <subscriptionId> - set subscription Id, if -a is used, " 2223 + "this must be set"); 2224 pw.println(" remove-suggestion <ssid> [-l]"); 2225 pw.println(" Remove a network suggestion with provided SSID of the network"); 2226 pw.println(" -l - Remove suggestion with lingering, if not set will disconnect " 2227 + "immediately "); 2228 pw.println(" remove-all-suggestions"); 2229 pw.println(" Removes all suggestions added via shell"); 2230 pw.println(" list-suggestions"); 2231 pw.println(" Lists the suggested networks added via shell"); 2232 if (SdkLevel.isAtLeastS()) { 2233 pw.println(" set-coex-cell-channels [lte|nr <bandNumber 1-261> " 2234 + "<downlinkFreqKhz or UNKNOWN: " 2235 + PhysicalChannelConfig.FREQUENCY_UNKNOWN + "> " 2236 + "<downlinkBandwidthKhz or UNKNOWN: " 2237 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN + "> " 2238 + "<uplinkFreqKhz or UNKNOWN: " 2239 + PhysicalChannelConfig.FREQUENCY_UNKNOWN + "> " 2240 + "<uplinkBandwidthKhz or UNKNOWN: " 2241 + PhysicalChannelConfig.CELL_BANDWIDTH_UNKNOWN + ">] ..."); 2242 pw.println(" Sets a list of zero or more cell channels to use for coex calculations." 2243 + " Actual device reported cell channels will be ignored until" 2244 + " reset-coex-cell-channels is called."); 2245 pw.println(" reset-coex-cell-channels"); 2246 pw.println(" Removes all cell channels set in set-coex-cell-channels and returns to " 2247 + "listening on actual device reported cell channels"); 2248 pw.println(" get-coex-cell-channels"); 2249 pw.println(" Prints the cell channels being used for coex."); 2250 } 2251 pw.println(" set-connected-score <score>"); 2252 pw.println(" Set connected wifi network score (to choose between LTE & Wifi for " 2253 + "default route)."); 2254 pw.println(" This turns off the active connected scorer (default or external)."); 2255 pw.println(" Only works while connected to a wifi network. This score will stay in " 2256 + "effect until you call reset-connected-score or the device disconnects from the " 2257 + "current network."); 2258 pw.println(" <score> - Integer score should be in the range of 0 - 60"); 2259 pw.println(" reset-connected-score"); 2260 pw.println(" Turns on the default connected scorer."); 2261 pw.println(" Note: Will clear any external scorer set."); 2262 pw.println(" start-softap <ssid> (open|wpa2|wpa3|wpa3_transition|owe|owe_transition) " 2263 + "<passphrase> [-b 2|5|6|any|bridged]"); 2264 pw.println(" Start softap with provided params"); 2265 pw.println(" Note that the shell command doesn't activate internet tethering. In some " 2266 + "devices, internet sharing is possible when Wi-Fi STA is also enabled and is" 2267 + "associated to another AP with internet access."); 2268 pw.println(" <ssid> - SSID of the network"); 2269 pw.println(" open|wpa2|wpa3|wpa3_transition|owe|owe_transition - Security type of the " 2270 + "network."); 2271 pw.println(" - Use 'open', 'owe', 'owe_transition' for networks with no passphrase"); 2272 pw.println(" - Use 'wpa2', 'wpa3', 'wpa3_transition' for networks with passphrase"); 2273 pw.println(" -b 2|5|6|any|bridged - select the preferred band."); 2274 pw.println(" - Use '2' to select 2.4GHz band as the preferred band"); 2275 pw.println(" - Use '5' to select 5GHz band as the preferred band"); 2276 pw.println(" - Use '6' to select 6GHz band as the preferred band"); 2277 pw.println(" - Use 'any' to indicate no band preference"); 2278 pw.println(" - Use 'bridged' to indicate bridged AP which enables APs on both " 2279 + "2.4G + 5G"); 2280 pw.println(" Note: If the band option is not provided, 2.4GHz is the preferred band."); 2281 pw.println(" The exact channel is auto-selected by FW unless overridden by " 2282 + "force-softap-channel command"); 2283 pw.println(" -x - Specifies the SSID as hex digits instead of plain text (T and above)"); 2284 pw.println(" stop-softap"); 2285 pw.println(" Stop softap (hotspot)"); 2286 pw.println(" pmksa-flush <networkId>"); 2287 pw.println(" - Flush the local PMKSA cache associated with the network id." 2288 + " Use list-networks to retrieve <networkId> for the network"); 2289 pw.println(" reload-resources"); 2290 pw.println( 2291 " Reset the WiFi resources cache which will cause them to be reloaded next " 2292 + "time they are accessed. Necessary if overlays are manually modified."); 2293 pw.println(" launch-dialog-simple [-t <title>] [-m <message>]" 2294 + " [-l <url> <url_start> <url_end>] [-y <positive_button_text>]" 2295 + " [-n <negative_button_text>] [-x <neutral_button_text>] [-c <timeout_millis>]"); 2296 pw.println(" Launches a simple dialog and waits up to 15 seconds to" 2297 + " print the response."); 2298 pw.println(" -t - Title"); 2299 pw.println(" -m - Message"); 2300 pw.println(" -l - URL of the message, with the start and end index inside the message"); 2301 pw.println(" -y - Positive Button Text"); 2302 pw.println(" -n - Negative Button Text"); 2303 pw.println(" -x - Neutral Button Text"); 2304 pw.println(" -c - Optional timeout in milliseconds"); 2305 pw.println(" launch-dialog-p2p-invitation-sent <device_name> <pin> [-i <display_id>]"); 2306 pw.println(" Launches a P2P Invitation Sent dialog."); 2307 pw.println(" <device_name> - Name of the device the invitation was sent to"); 2308 pw.println(" <pin> - PIN for the invited device to input"); 2309 pw.println(" launch-dialog-p2p-invitation-received <device_name> [-p] [-d <pin>] " 2310 + "[-i <display_id>] [-c <timeout_millis>]"); 2311 pw.println(" Launches a P2P Invitation Received dialog and waits up to 15 seconds to" 2312 + " print the response."); 2313 pw.println(" <device_name> - Name of the device sending the invitation"); 2314 pw.println(" -p - Show PIN input"); 2315 pw.println(" -d - Display PIN <pin>"); 2316 pw.println(" -i - Display ID"); 2317 pw.println(" -c - Optional timeout in milliseconds"); 2318 pw.println(" query-interface <uid> <package_name> STA|AP|AWARE|DIRECT [-new]"); 2319 pw.println( 2320 " Query whether the specified could be created for the specified UID and " 2321 + "package name, and if so - what other interfaces would be destroyed"); 2322 pw.println(" -new - query for a new interfaces (otherwise an existing interface is ok"); 2323 pw.println(" interface-priority-interactive-mode enable|disable|default"); 2324 pw.println(" Enable or disable asking the user when there's an interface priority " 2325 + "conflict, |default| implies using the device default behavior."); 2326 pw.println(" set-one-shot-screen-on-delay-ms <delayMs>"); 2327 pw.println(" set the delay for the next screen-on connectivity scan in milliseconds."); 2328 pw.println(" set-ipreach-disconnect enabled|disabled"); 2329 pw.println(" Sets whether CMD_IP_REACHABILITY_LOST events should trigger disconnects."); 2330 pw.println(" get-ipreach-disconnect"); 2331 pw.println(" Gets setting of CMD_IP_REACHABILITY_LOST events triggering disconnects."); 2332 } 2333 onHelpPrivileged(PrintWriter pw)2334 private void onHelpPrivileged(PrintWriter pw) { 2335 pw.println(" connect-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-x] [-m] [-d] " 2336 + "[-b <bssid>] [-r auto|none|persistent|non_persistent]"); 2337 pw.println(" Connect to a network with provided params and add to saved networks list"); 2338 pw.println(" <ssid> - SSID of the network"); 2339 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 2340 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 2341 pw.println(" - 'open' - Open networks (Most prevalent)"); 2342 pw.println(" - 'owe' - Enhanced open networks"); 2343 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 2344 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 2345 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 2346 pw.println(" -x - Specifies the SSID as hex digits instead of plain text"); 2347 pw.println(" -m - Mark the network metered."); 2348 pw.println(" -d - Mark the network autojoin disabled."); 2349 pw.println(" -h - Mark the network hidden."); 2350 pw.println(" -p - Mark the network private (not shared)."); 2351 pw.println(" -b <bssid> - Set specific BSSID."); 2352 pw.println(" -r auto|none|persistent|non_persistent - MAC randomization scheme for the" 2353 + " network"); 2354 pw.println(" add-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-x] [-m] [-d] " 2355 + "[-b <bssid>] [-r auto|none|persistent|non_persistent]"); 2356 pw.println(" Add/update saved network with provided params"); 2357 pw.println(" <ssid> - SSID of the network"); 2358 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 2359 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 2360 pw.println(" - 'open' - Open networks (Most prevalent)"); 2361 pw.println(" - 'owe' - Enhanced open networks"); 2362 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 2363 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 2364 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 2365 pw.println(" -x - Specifies the SSID as hex digits instead of plain text"); 2366 pw.println(" -m - Mark the network metered."); 2367 pw.println(" -d - Mark the network autojoin disabled."); 2368 pw.println(" -h - Mark the network hidden."); 2369 pw.println(" -p - Mark the network private (not shared)."); 2370 pw.println(" -b <bssid> - Set specific BSSID."); 2371 pw.println(" -r auto|none|persistent|non_persistent - MAC randomization scheme for the" 2372 + " network"); 2373 pw.println(" set-poll-rssi-interval-msecs <int>"); 2374 pw.println(" Sets the interval between RSSI polls to <int> milliseconds."); 2375 pw.println(" get-poll-rssi-interval-msecs"); 2376 pw.println(" Gets current interval between RSSI polls, in milliseconds."); 2377 pw.println(" force-hi-perf-mode enabled|disabled"); 2378 pw.println(" Sets whether hi-perf mode is forced or left for normal operation."); 2379 pw.println(" force-low-latency-mode enabled|disabled"); 2380 pw.println(" Sets whether low latency mode is forced or left for normal operation."); 2381 pw.println(" network-suggestions-set-user-approved <package name> yes|no"); 2382 pw.println(" Sets whether network suggestions from the app is approved or not."); 2383 pw.println(" network-suggestions-has-user-approved <package name>"); 2384 pw.println(" Queries whether network suggestions from the app is approved or not."); 2385 pw.println(" imsi-protection-exemption-set-user-approved-for-carrier <carrier id> yes|no"); 2386 pw.println(" Sets whether Imsi protection exemption for carrier is approved or not"); 2387 pw.println(" imsi-protection-exemption-has-user-approved-for-carrier <carrier id>"); 2388 pw.println(" Queries whether Imsi protection exemption for carrier is approved or not"); 2389 pw.println(" imsi-protection-exemption-clear-user-approved-for-carrier <carrier id>"); 2390 pw.println(" Clear the user choice on Imsi protection exemption for carrier"); 2391 pw.println(" network-requests-remove-user-approved-access-points <package name>"); 2392 pw.println(" Removes all user approved network requests for the app."); 2393 pw.println(" clear-user-disabled-networks"); 2394 pw.println(" Clears the user disabled networks list."); 2395 pw.println(" send-link-probe"); 2396 pw.println(" Manually triggers a link probe."); 2397 pw.println(" force-softap-band enabled <int> | disabled"); 2398 pw.println(" Forces soft AP band to 2|5|6"); 2399 pw.println(" force-softap-channel enabled <int> | disabled"); 2400 pw.println(" Sets whether soft AP channel is forced to <int> MHz"); 2401 pw.println(" or left for normal operation."); 2402 pw.println(" force-country-code enabled <two-letter code> | disabled "); 2403 pw.println(" Sets country code to <two-letter code> or left for normal value"); 2404 pw.println(" or '00' for forcing to world mode country code"); 2405 pw.println(" set-wifi-watchdog enabled|disabled"); 2406 pw.println(" Sets whether wifi watchdog should trigger recovery"); 2407 pw.println(" get-wifi-watchdog"); 2408 pw.println(" Gets setting of wifi watchdog trigger recovery."); 2409 pw.println(" get-softap-supported-features"); 2410 pw.println(" Gets softap supported features. Will print 'wifi_softap_acs_supported'"); 2411 pw.println(" and/or 'wifi_softap_wpa3_sae_supported',"); 2412 pw.println(" and/or 'wifi_softap_bridged_ap_supported',"); 2413 pw.println(" and/or 'wifi_softap_bridged_ap_with_sta_supported',"); 2414 pw.println(" each on a separate line."); 2415 pw.println(" settings-reset"); 2416 pw.println(" Initiates wifi settings reset"); 2417 pw.println(" add-request [-g] [-i] [-n] [-s] <ssid> open|owe|wpa2|wpa3 [<passphrase>]" 2418 + " [-b <bssid>] [-d <band=2|5|6|60>]"); 2419 pw.println(" Add a network request with provided params"); 2420 pw.println(" Use 'network-requests-set-user-approved android yes'" 2421 + " to pre-approve requests added via rooted shell (Not persisted)"); 2422 pw.println(" -g - Marks the following SSID as a glob pattern"); 2423 pw.println(" <ssid> - SSID of the network, or glob pattern if -g is present"); 2424 pw.println(" open|owe|wpa2|wpa3 - Security type of the network."); 2425 pw.println(" - Use 'open' or 'owe' for networks with no passphrase"); 2426 pw.println(" - 'open' - Open networks (Most prevalent)"); 2427 pw.println(" - 'owe' - Enhanced open networks"); 2428 pw.println(" - Use 'wpa2' or 'wpa3' for networks with passphrase"); 2429 pw.println(" - 'wpa2' - WPA-2 PSK networks (Most prevalent)"); 2430 pw.println(" - 'wpa3' - WPA-3 PSK networks"); 2431 pw.println(" -b <bssid> - Set specific BSSID."); 2432 pw.println(" -i Set internet capability."); 2433 pw.println(" -d Specify the band of access point: 2, 5, 6, or 60"); 2434 pw.println(" -s No SSID provided, to be chosen by network selection."); 2435 pw.println(" -n - Prevent auto-selection of BSSID and force it to be null so that the " 2436 + "request matches all BSSIDs."); 2437 pw.println(" remove-request <ssid>"); 2438 pw.println(" Remove a network request with provided SSID of the network"); 2439 pw.println(" remove-all-requests"); 2440 pw.println(" Removes all active requests added via shell"); 2441 pw.println(" list-requests"); 2442 pw.println(" Lists the requested networks added via shell"); 2443 pw.println(" network-requests-set-user-approved <package name> yes|no"); 2444 pw.println(" Sets whether network requests from the app is approved or not."); 2445 pw.println(" Note: Only 1 such app can be approved from the shell at a time"); 2446 pw.println(" network-requests-has-user-approved <package name>"); 2447 pw.println(" Queries whether network requests from the app is approved or not."); 2448 pw.println(" Note: This only returns whether the app was set via the " 2449 + "'network-requests-set-user-approved' shell command"); 2450 pw.println(" list-all-suggestions"); 2451 pw.println(" Lists all suggested networks on this device"); 2452 pw.println(" list-suggestions-from-app <package name>"); 2453 pw.println(" Lists the suggested networks from the app"); 2454 pw.println(" set-emergency-callback-mode enabled|disabled"); 2455 pw.println(" Sets whether Emergency Callback Mode (ECBM) is enabled."); 2456 pw.println(" Equivalent to receiving the " 2457 + "TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED broadcast."); 2458 pw.println(" set-emergency-call-state enabled|disabled"); 2459 pw.println(" Sets whether we are in the middle of an emergency call."); 2460 pw.println("Equivalent to receiving the " 2461 + "TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED broadcast."); 2462 pw.println(" network-suggestions-set-as-carrier-provider <packageName> yes|no"); 2463 pw.println(" Set the <packageName> work as carrier provider or not."); 2464 pw.println(" is-network-suggestions-set-as-carrier-provider <packageName>"); 2465 pw.println(" Queries whether the <packageName> is working as carrier provider or not."); 2466 pw.println(" remove-app-from-suggestion_database <packageName>"); 2467 pw.println(" Remove <packageName> from the suggestion database, all suggestions and user" 2468 + " approval will be deleted, it is the same as uninstalling this app."); 2469 pw.println(" trigger-recovery"); 2470 pw.println(" Trigger Wi-Fi subsystem restart."); 2471 pw.println(" start-faking-scans"); 2472 pw.println(" Start faking scan results into the framework (configured with " 2473 + "'add-fake-scan'), stop with 'stop-faking-scans'."); 2474 pw.println(" stop-faking-scans"); 2475 pw.println(" Stop faking scan results - started with 'start-faking-scans'."); 2476 pw.println(" add-fake-scan [-x] <ssid> <bssid> <capabilities> <frequency> <dbm>"); 2477 pw.println(" Add a fake scan result to be used when enabled via `start-faking-scans'."); 2478 pw.println(" Example WPA2: add-fake-scan fakeWpa2 80:01:02:03:04:05 " 2479 + "\"[WPA2-PSK-CCMP][RSN-PSK-CCMP][ESS]\" 2412 -55"); 2480 pw.println(" Example WPA3: add-fake-scan fakeWpa3 80:01:02:03:04:06 " 2481 + "\"[RSN-SAE+FT/SAE-CCMP][ESS]\" 2412 -55"); 2482 pw.println( 2483 " Example Open: add-fake-scan fakeOpen 80:01:02:03:04:07 \"[ESS]\" 2412 -55"); 2484 pw.println(" Example OWE: add-fake-scan fakeOwe 80:01:02:03:04:08 \"[RSN-OWE-CCMP]\" " 2485 + "2412 -55"); 2486 pw.println( 2487 " Example WPA2/WPA3 transition mode: add-fake-scan fakeWpa2t3 80:01:02:03:04:09 " 2488 + "\"[WPA2-PSK-CCMP][RSN-PSK+SAE-CCMP][ESS][MFPC]\" 2412 -55"); 2489 pw.println( 2490 " Example Open/OWE transition mode: add-fake-scan fakeOpenOwe 80:01:02:03:04:0A " 2491 + "\"[RSN-OWE_TRANSITION-CCMP][ESS]\" 2412 -55"); 2492 pw.println( 2493 " Example Passpoint: add-fake-scan fakePasspoint 80:01:02:03:04:0B " 2494 + "\"[WPA2-EAP/SHA1-CCMP][RSN-EAP/SHA1-CCMP][ESS][MFPR][MFPC]" 2495 + "[PASSPOINT]\" 2412 -55"); 2496 pw.println(" -x - Specifies the SSID as hex digits instead of plain text"); 2497 pw.println(" reset-fake-scans"); 2498 pw.println(" Resets all fake scan results added by 'add-fake-scan'."); 2499 pw.println(" enable-scanning enabled|disabled [-h]"); 2500 pw.println(" Sets whether all scanning should be enabled or disabled"); 2501 pw.println(" -h - Enable scanning for hidden networks."); 2502 pw.println(" set-passpoint-enabled enabled|disabled"); 2503 pw.println(" Sets whether Passpoint should be enabled or disabled"); 2504 pw.println(" start-lohs <ssid> (open|wpa2|wpa3|wpa3_transition|owe|owe_transition) " 2505 + "<passphrase> [-b 2|5|6|any]"); 2506 pw.println(" Start local only softap (hotspot) with provided params"); 2507 pw.println(" <ssid> - SSID of the network"); 2508 pw.println(" open|wpa2|wpa3|wpa3_transition|owe|owe_transition - Security type of the " 2509 + "network."); 2510 pw.println(" - Use 'open', 'owe', 'owe_transition' for networks with no passphrase"); 2511 pw.println(" - Use 'wpa2', 'wpa3', 'wpa3_transition' for networks with passphrase"); 2512 pw.println(" -b 2|5|6|any|bridged - select the preferred band."); 2513 pw.println(" - Use '2' to select 2.4GHz band as the preferred band"); 2514 pw.println(" - Use '5' to select 5GHz band as the preferred band"); 2515 pw.println(" - Use '6' to select 6GHz band as the preferred band"); 2516 pw.println(" - Use 'any' to indicate no band preference"); 2517 pw.println(" - Use 'bridged' to indicate bridged AP which enables APs on both " 2518 + "2.4G + 5G"); 2519 pw.println(" Note: If the band option is not provided, 2.4GHz is the preferred band."); 2520 pw.println(" stop-lohs"); 2521 pw.println(" Stop local only softap (hotspot)"); 2522 pw.println(" set-multi-internet-mode 0|1|2"); 2523 pw.println(" Sets Multi Internet use case mode. 0-disabled 1-dbs 2-multi ap"); 2524 pw.println(" set-pno-request <ssid> [-f <frequency>]"); 2525 pw.println(" Requests to include a non-quoted UTF-8 SSID in PNO scans"); 2526 pw.println(" clear-pno-request"); 2527 pw.println(" Clear the PNO scan request."); 2528 pw.println(" start-dpp-enrollee-responder [-i <info>] [-c <curve>]"); 2529 pw.println(" Start DPP Enrollee responder mode."); 2530 pw.println(" -i - Device Info to be used in DPP Bootstrapping URI"); 2531 pw.println(" -c - Cryptography Curve integer 1:p256v1, 2:s384r1, etc"); 2532 pw.println(" start-dpp-configurator-initiator <networkId> <netRole> <enrolleeURI>"); 2533 pw.println(" Start DPP Configurator Initiator mode."); 2534 pw.println(" netRole - 0: STA, 1: AP"); 2535 pw.println(" enrolleeURI - Bootstrapping URI received from Enrollee"); 2536 pw.println(" stop-dpp"); 2537 pw.println(" Stop DPP session."); 2538 } 2539 2540 @Override onHelp()2541 public void onHelp() { 2542 final PrintWriter pw = getOutPrintWriter(); 2543 pw.println("Wi-Fi (wifi) commands:"); 2544 pw.println(" help or -h"); 2545 pw.println(" Print this help text."); 2546 onHelpNonPrivileged(pw); 2547 if (Binder.getCallingUid() == Process.ROOT_UID) { 2548 onHelpPrivileged(pw); 2549 } 2550 pw.println(); 2551 } 2552 printWifiNetworkSuggestions(PrintWriter pw, Collection<WifiNetworkSuggestion> suggestions)2553 private void printWifiNetworkSuggestions(PrintWriter pw, 2554 Collection<WifiNetworkSuggestion> suggestions) { 2555 if (suggestions == null || suggestions.isEmpty()) { 2556 pw.println("No suggestions on this device"); 2557 } else { 2558 pw.println("SSID Security type(s)"); 2559 for (WifiNetworkSuggestion suggestion : suggestions) { 2560 pw.println(String.format("%-32s %-4s", 2561 WifiInfo.sanitizeSsid(suggestion.getWifiConfiguration().SSID), 2562 suggestion.getWifiConfiguration().getSecurityParamsList().stream() 2563 .map(p -> WifiConfiguration.getSecurityTypeName( 2564 p.getSecurityType()) 2565 + (p.isAddedByAutoUpgrade() ? "^" : "")) 2566 .collect(Collectors.joining("/")))); 2567 } 2568 } 2569 } 2570 } 2571