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 android.annotation.NonNull; 20 import android.net.MacAddress; 21 import android.net.wifi.IApInterface; 22 import android.net.wifi.IApInterfaceEventCallback; 23 import android.net.wifi.IClientInterface; 24 import android.net.wifi.IPnoScanEvent; 25 import android.net.wifi.IScanEvent; 26 import android.net.wifi.IWifiScannerImpl; 27 import android.net.wifi.IWificond; 28 import android.net.wifi.ScanResult; 29 import android.net.wifi.WifiScanner; 30 import android.net.wifi.WifiSsid; 31 import android.os.Binder; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.util.Log; 35 36 import com.android.server.wifi.WifiNative.SoftApListener; 37 import com.android.server.wifi.hotspot2.NetworkDetail; 38 import com.android.server.wifi.util.InformationElementUtil; 39 import com.android.server.wifi.util.NativeUtil; 40 import com.android.server.wifi.util.ScanResultUtil; 41 import com.android.server.wifi.wificond.ChannelSettings; 42 import com.android.server.wifi.wificond.HiddenNetwork; 43 import com.android.server.wifi.wificond.NativeScanResult; 44 import com.android.server.wifi.wificond.PnoNetwork; 45 import com.android.server.wifi.wificond.PnoSettings; 46 import com.android.server.wifi.wificond.RadioChainInfo; 47 import com.android.server.wifi.wificond.SingleScanSettings; 48 49 import java.util.ArrayList; 50 import java.util.HashMap; 51 import java.util.Map; 52 import java.util.Set; 53 54 /** 55 * This class provides methods for WifiNative to send control commands to wificond. 56 * NOTE: This class should only be used from WifiNative. 57 */ 58 public class WificondControl implements IBinder.DeathRecipient { 59 private boolean mVerboseLoggingEnabled = false; 60 61 private static final String TAG = "WificondControl"; 62 63 /* Get scan results for a single scan */ 64 public static final int SCAN_TYPE_SINGLE_SCAN = 0; 65 66 /* Get scan results for Pno Scan */ 67 public static final int SCAN_TYPE_PNO_SCAN = 1; 68 69 private WifiInjector mWifiInjector; 70 private WifiMonitor mWifiMonitor; 71 private final CarrierNetworkConfig mCarrierNetworkConfig; 72 73 // Cached wificond binder handlers. 74 private IWificond mWificond; 75 private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>(); 76 private HashMap<String, IApInterface> mApInterfaces = new HashMap<>(); 77 private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>(); 78 private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>(); 79 private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>(); 80 private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>(); 81 private WifiNative.WificondDeathEventHandler mDeathEventHandler; 82 83 private class ScanEventHandler extends IScanEvent.Stub { 84 private String mIfaceName; 85 86 ScanEventHandler(@NonNull String ifaceName) { 87 mIfaceName = ifaceName; 88 } 89 90 @Override 91 public void OnScanResultReady() { 92 Log.d(TAG, "Scan result ready event"); 93 mWifiMonitor.broadcastScanResultEvent(mIfaceName); 94 } 95 96 @Override 97 public void OnScanFailed() { 98 Log.d(TAG, "Scan failed event"); 99 mWifiMonitor.broadcastScanFailedEvent(mIfaceName); 100 } 101 } 102 103 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, 104 CarrierNetworkConfig carrierNetworkConfig) { 105 mWifiInjector = wifiInjector; 106 mWifiMonitor = wifiMonitor; 107 mCarrierNetworkConfig = carrierNetworkConfig; 108 } 109 110 private class PnoScanEventHandler extends IPnoScanEvent.Stub { 111 private String mIfaceName; 112 113 PnoScanEventHandler(@NonNull String ifaceName) { 114 mIfaceName = ifaceName; 115 } 116 117 @Override 118 public void OnPnoNetworkFound() { 119 Log.d(TAG, "Pno scan result event"); 120 mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName); 121 mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount(); 122 } 123 124 @Override 125 public void OnPnoScanFailed() { 126 Log.d(TAG, "Pno Scan failed event"); 127 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 128 } 129 130 @Override 131 public void OnPnoScanOverOffloadStarted() { 132 Log.d(TAG, "Pno scan over offload started"); 133 mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount(); 134 } 135 136 @Override 137 public void OnPnoScanOverOffloadFailed(int reason) { 138 Log.d(TAG, "Pno scan over offload failed"); 139 mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount(); 140 } 141 } 142 143 /** 144 * Listener for AP Interface events. 145 */ 146 private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub { 147 private SoftApListener mSoftApListener; 148 149 ApInterfaceEventCallback(SoftApListener listener) { 150 mSoftApListener = listener; 151 } 152 153 @Override 154 public void onNumAssociatedStationsChanged(int numStations) { 155 mSoftApListener.onNumAssociatedStationsChanged(numStations); 156 } 157 158 @Override 159 public void onSoftApChannelSwitched(int frequency, int bandwidth) { 160 mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth); 161 } 162 } 163 164 /** 165 * Called by the binder subsystem upon remote object death. 166 * Invoke all the register death handlers and clear state. 167 */ 168 @Override 169 public void binderDied() { 170 Log.e(TAG, "Wificond died!"); 171 clearState(); 172 // Invalidate the global wificond handle on death. Will be refreshed 173 // on the next setup call. 174 mWificond = null; 175 if (mDeathEventHandler != null) { 176 mDeathEventHandler.onDeath(); 177 } 178 } 179 180 /** Enable or disable verbose logging of WificondControl. 181 * @param enable True to enable verbose logging. False to disable verbose logging. 182 */ 183 public void enableVerboseLogging(boolean enable) { 184 mVerboseLoggingEnabled = enable; 185 } 186 187 /** 188 * Initializes wificond & registers a death notification for wificond. 189 * This method clears any existing state in wificond daemon. 190 * 191 * @return Returns true on success. 192 */ 193 public boolean initialize(@NonNull WifiNative.WificondDeathEventHandler handler) { 194 if (mDeathEventHandler != null) { 195 Log.e(TAG, "Death handler already present"); 196 } 197 mDeathEventHandler = handler; 198 tearDownInterfaces(); 199 return true; 200 } 201 202 /** 203 * Helper method to retrieve the global wificond handle and register for 204 * death notifications. 205 */ 206 private boolean retrieveWificondAndRegisterForDeath() { 207 if (mWificond != null) { 208 if (mVerboseLoggingEnabled) { 209 Log.d(TAG, "Wificond handle already retrieved"); 210 } 211 // We already have a wificond handle. 212 return true; 213 } 214 mWificond = mWifiInjector.makeWificond(); 215 if (mWificond == null) { 216 Log.e(TAG, "Failed to get reference to wificond"); 217 return false; 218 } 219 try { 220 mWificond.asBinder().linkToDeath(this, 0); 221 } catch (RemoteException e) { 222 Log.e(TAG, "Failed to register death notification for wificond"); 223 // The remote has already died. 224 return false; 225 } 226 return true; 227 } 228 229 /** 230 * Setup interface for client mode via wificond. 231 * @return An IClientInterface as wificond client interface binder handler. 232 * Returns null on failure. 233 */ 234 public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) { 235 Log.d(TAG, "Setting up interface for client mode"); 236 if (!retrieveWificondAndRegisterForDeath()) { 237 return null; 238 } 239 240 IClientInterface clientInterface = null; 241 try { 242 clientInterface = mWificond.createClientInterface(ifaceName); 243 } catch (RemoteException e1) { 244 Log.e(TAG, "Failed to get IClientInterface due to remote exception"); 245 return null; 246 } 247 248 if (clientInterface == null) { 249 Log.e(TAG, "Could not get IClientInterface instance from wificond"); 250 return null; 251 } 252 Binder.allowBlocking(clientInterface.asBinder()); 253 254 // Refresh Handlers 255 mClientInterfaces.put(ifaceName, clientInterface); 256 try { 257 IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl(); 258 if (wificondScanner == null) { 259 Log.e(TAG, "Failed to get WificondScannerImpl"); 260 return null; 261 } 262 mWificondScanners.put(ifaceName, wificondScanner); 263 Binder.allowBlocking(wificondScanner.asBinder()); 264 ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName); 265 mScanEventHandlers.put(ifaceName, scanEventHandler); 266 wificondScanner.subscribeScanEvents(scanEventHandler); 267 PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName); 268 mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler); 269 wificondScanner.subscribePnoScanEvents(pnoScanEventHandler); 270 } catch (RemoteException e) { 271 Log.e(TAG, "Failed to refresh wificond scanner due to remote exception"); 272 } 273 274 return clientInterface; 275 } 276 277 /** 278 * Teardown a specific STA interface configured in wificond. 279 * 280 * @return Returns true on success. 281 */ 282 public boolean tearDownClientInterface(@NonNull String ifaceName) { 283 if (getClientInterface(ifaceName) == null) { 284 Log.e(TAG, "No valid wificond client interface handler"); 285 return false; 286 } 287 try { 288 IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName); 289 if (scannerImpl != null) { 290 scannerImpl.unsubscribeScanEvents(); 291 scannerImpl.unsubscribePnoScanEvents(); 292 } 293 } catch (RemoteException e) { 294 Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception"); 295 return false; 296 } 297 298 boolean success; 299 try { 300 success = mWificond.tearDownClientInterface(ifaceName); 301 } catch (RemoteException e1) { 302 Log.e(TAG, "Failed to teardown client interface due to remote exception"); 303 return false; 304 } 305 if (!success) { 306 Log.e(TAG, "Failed to teardown client interface"); 307 return false; 308 } 309 310 mClientInterfaces.remove(ifaceName); 311 mWificondScanners.remove(ifaceName); 312 mScanEventHandlers.remove(ifaceName); 313 mPnoScanEventHandlers.remove(ifaceName); 314 return true; 315 } 316 317 /** 318 * Setup interface for softAp mode via wificond. 319 * @return An IApInterface as wificond Ap interface binder handler. 320 * Returns null on failure. 321 */ 322 public IApInterface setupInterfaceForSoftApMode(@NonNull String ifaceName) { 323 Log.d(TAG, "Setting up interface for soft ap mode"); 324 if (!retrieveWificondAndRegisterForDeath()) { 325 return null; 326 } 327 328 IApInterface apInterface = null; 329 try { 330 apInterface = mWificond.createApInterface(ifaceName); 331 } catch (RemoteException e1) { 332 Log.e(TAG, "Failed to get IApInterface due to remote exception"); 333 return null; 334 } 335 336 if (apInterface == null) { 337 Log.e(TAG, "Could not get IApInterface instance from wificond"); 338 return null; 339 } 340 Binder.allowBlocking(apInterface.asBinder()); 341 342 // Refresh Handlers 343 mApInterfaces.put(ifaceName, apInterface); 344 return apInterface; 345 } 346 347 /** 348 * Teardown a specific AP interface configured in wificond. 349 * 350 * @return Returns true on success. 351 */ 352 public boolean tearDownSoftApInterface(@NonNull String ifaceName) { 353 if (getApInterface(ifaceName) == null) { 354 Log.e(TAG, "No valid wificond ap interface handler"); 355 return false; 356 } 357 boolean success; 358 try { 359 success = mWificond.tearDownApInterface(ifaceName); 360 } catch (RemoteException e1) { 361 Log.e(TAG, "Failed to teardown AP interface due to remote exception"); 362 return false; 363 } 364 if (!success) { 365 Log.e(TAG, "Failed to teardown AP interface"); 366 return false; 367 } 368 mApInterfaces.remove(ifaceName); 369 mApInterfaceListeners.remove(ifaceName); 370 return true; 371 } 372 373 /** 374 * Teardown all interfaces configured in wificond. 375 * @return Returns true on success. 376 */ 377 public boolean tearDownInterfaces() { 378 Log.d(TAG, "tearing down interfaces in wificond"); 379 // Explicitly refresh the wificodn handler because |tearDownInterfaces()| 380 // could be used to cleanup before we setup any interfaces. 381 if (!retrieveWificondAndRegisterForDeath()) { 382 return false; 383 } 384 385 try { 386 for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) { 387 entry.getValue().unsubscribeScanEvents(); 388 entry.getValue().unsubscribePnoScanEvents(); 389 } 390 mWificond.tearDownInterfaces(); 391 clearState(); 392 return true; 393 } catch (RemoteException e) { 394 Log.e(TAG, "Failed to tear down interfaces due to remote exception"); 395 } 396 397 return false; 398 } 399 400 /** Helper function to look up the interface handle using name */ 401 private IClientInterface getClientInterface(@NonNull String ifaceName) { 402 return mClientInterfaces.get(ifaceName); 403 } 404 405 /** 406 * Disable wpa_supplicant via wificond. 407 * @return Returns true on success. 408 */ 409 public boolean disableSupplicant() { 410 if (!retrieveWificondAndRegisterForDeath()) { 411 return false; 412 } 413 try { 414 return mWificond.disableSupplicant(); 415 } catch (RemoteException e) { 416 Log.e(TAG, "Failed to disable supplicant due to remote exception"); 417 } 418 return false; 419 } 420 421 /** 422 * Enable wpa_supplicant via wificond. 423 * @return Returns true on success. 424 */ 425 public boolean enableSupplicant() { 426 if (!retrieveWificondAndRegisterForDeath()) { 427 return false; 428 } 429 try { 430 return mWificond.enableSupplicant(); 431 } catch (RemoteException e) { 432 Log.e(TAG, "Failed to enable supplicant due to remote exception"); 433 } 434 return false; 435 } 436 437 /** 438 * Request signal polling to wificond. 439 * @param ifaceName Name of the interface. 440 * Returns an SignalPollResult object. 441 * Returns null on failure. 442 */ 443 public WifiNative.SignalPollResult signalPoll(@NonNull String ifaceName) { 444 IClientInterface iface = getClientInterface(ifaceName); 445 if (iface == null) { 446 Log.e(TAG, "No valid wificond client interface handler"); 447 return null; 448 } 449 450 int[] resultArray; 451 try { 452 resultArray = iface.signalPoll(); 453 if (resultArray == null || resultArray.length != 3) { 454 Log.e(TAG, "Invalid signal poll result from wificond"); 455 return null; 456 } 457 } catch (RemoteException e) { 458 Log.e(TAG, "Failed to do signal polling due to remote exception"); 459 return null; 460 } 461 WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult(); 462 pollResult.currentRssi = resultArray[0]; 463 pollResult.txBitrate = resultArray[1]; 464 pollResult.associationFrequency = resultArray[2]; 465 return pollResult; 466 } 467 468 /** 469 * Fetch TX packet counters on current connection from wificond. 470 * @param ifaceName Name of the interface. 471 * Returns an TxPacketCounters object. 472 * Returns null on failure. 473 */ 474 public WifiNative.TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) { 475 IClientInterface iface = getClientInterface(ifaceName); 476 if (iface == null) { 477 Log.e(TAG, "No valid wificond client interface handler"); 478 return null; 479 } 480 481 int[] resultArray; 482 try { 483 resultArray = iface.getPacketCounters(); 484 if (resultArray == null || resultArray.length != 2) { 485 Log.e(TAG, "Invalid signal poll result from wificond"); 486 return null; 487 } 488 } catch (RemoteException e) { 489 Log.e(TAG, "Failed to do signal polling due to remote exception"); 490 return null; 491 } 492 WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters(); 493 counters.txSucceeded = resultArray[0]; 494 counters.txFailed = resultArray[1]; 495 return counters; 496 } 497 498 /** Helper function to look up the scanner impl handle using name */ 499 private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) { 500 return mWificondScanners.get(ifaceName); 501 } 502 503 /** 504 * Fetch the latest scan result from kernel via wificond. 505 * @param ifaceName Name of the interface. 506 * @return Returns an ArrayList of ScanDetail. 507 * Returns an empty ArrayList on failure. 508 */ 509 public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) { 510 ArrayList<ScanDetail> results = new ArrayList<>(); 511 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 512 if (scannerImpl == null) { 513 Log.e(TAG, "No valid wificond scanner interface handler"); 514 return results; 515 } 516 try { 517 NativeScanResult[] nativeResults; 518 if (scanType == SCAN_TYPE_SINGLE_SCAN) { 519 nativeResults = scannerImpl.getScanResults(); 520 } else { 521 nativeResults = scannerImpl.getPnoScanResults(); 522 } 523 for (NativeScanResult result : nativeResults) { 524 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid); 525 String bssid; 526 try { 527 bssid = NativeUtil.macAddressFromByteArray(result.bssid); 528 } catch (IllegalArgumentException e) { 529 Log.e(TAG, "Illegal argument " + result.bssid, e); 530 continue; 531 } 532 if (bssid == null) { 533 Log.e(TAG, "Illegal null bssid"); 534 continue; 535 } 536 ScanResult.InformationElement[] ies = 537 InformationElementUtil.parseInformationElements(result.infoElement); 538 InformationElementUtil.Capabilities capabilities = 539 new InformationElementUtil.Capabilities(); 540 capabilities.from(ies, result.capability); 541 String flags = capabilities.generateCapabilitiesString(); 542 NetworkDetail networkDetail; 543 try { 544 networkDetail = new NetworkDetail(bssid, ies, null, result.frequency); 545 } catch (IllegalArgumentException e) { 546 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e); 547 continue; 548 } 549 550 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 551 result.signalMbm / 100, result.frequency, result.tsf, ies, null); 552 ScanResult scanResult = scanDetail.getScanResult(); 553 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi 554 // network and it uses EAP. 555 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult()) 556 && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) { 557 scanResult.isCarrierAp = true; 558 scanResult.carrierApEapType = 559 mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString()); 560 scanResult.carrierName = 561 mCarrierNetworkConfig.getCarrierName(wifiSsid.toString()); 562 } 563 // Fill up the radio chain info. 564 if (result.radioChainInfos != null) { 565 scanResult.radioChainInfos = 566 new ScanResult.RadioChainInfo[result.radioChainInfos.size()]; 567 int idx = 0; 568 for (RadioChainInfo nativeRadioChainInfo : result.radioChainInfos) { 569 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo(); 570 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.chainId; 571 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.level; 572 idx++; 573 } 574 } 575 results.add(scanDetail); 576 } 577 } catch (RemoteException e1) { 578 Log.e(TAG, "Failed to create ScanDetail ArrayList"); 579 } 580 if (mVerboseLoggingEnabled) { 581 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 582 } 583 584 return results; 585 } 586 587 /** 588 * Return scan type for the parcelable {@link SingleScanSettings} 589 */ 590 private static int getScanType(int scanType) { 591 switch (scanType) { 592 case WifiNative.SCAN_TYPE_LOW_LATENCY: 593 return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN; 594 case WifiNative.SCAN_TYPE_LOW_POWER: 595 return IWifiScannerImpl.SCAN_TYPE_LOW_POWER; 596 case WifiNative.SCAN_TYPE_HIGH_ACCURACY: 597 return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY; 598 default: 599 throw new IllegalArgumentException("Invalid scan type " + scanType); 600 } 601 } 602 603 /** 604 * Start a scan using wificond for the given parameters. 605 * @param ifaceName Name of the interface. 606 * @param scanType Type of scan to perform. 607 * @param freqs list of frequencies to scan for, if null scan all supported channels. 608 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 609 * @return Returns true on success. 610 */ 611 public boolean scan(@NonNull String ifaceName, 612 int scanType, 613 Set<Integer> freqs, 614 Set<String> hiddenNetworkSSIDs) { 615 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 616 if (scannerImpl == null) { 617 Log.e(TAG, "No valid wificond scanner interface handler"); 618 return false; 619 } 620 SingleScanSettings settings = new SingleScanSettings(); 621 try { 622 settings.scanType = getScanType(scanType); 623 } catch (IllegalArgumentException e) { 624 Log.e(TAG, "Invalid scan type ", e); 625 return false; 626 } 627 settings.channelSettings = new ArrayList<>(); 628 settings.hiddenNetworks = new ArrayList<>(); 629 630 if (freqs != null) { 631 for (Integer freq : freqs) { 632 ChannelSettings channel = new ChannelSettings(); 633 channel.frequency = freq; 634 settings.channelSettings.add(channel); 635 } 636 } 637 if (hiddenNetworkSSIDs != null) { 638 for (String ssid : hiddenNetworkSSIDs) { 639 HiddenNetwork network = new HiddenNetwork(); 640 try { 641 network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)); 642 } catch (IllegalArgumentException e) { 643 Log.e(TAG, "Illegal argument " + ssid, e); 644 continue; 645 } 646 settings.hiddenNetworks.add(network); 647 } 648 } 649 650 try { 651 return scannerImpl.scan(settings); 652 } catch (RemoteException e1) { 653 Log.e(TAG, "Failed to request scan due to remote exception"); 654 } 655 return false; 656 } 657 658 /** 659 * Start PNO scan. 660 * @param ifaceName Name of the interface. 661 * @param pnoSettings Pno scan configuration. 662 * @return true on success. 663 */ 664 public boolean startPnoScan(@NonNull String ifaceName, WifiNative.PnoSettings pnoSettings) { 665 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 666 if (scannerImpl == null) { 667 Log.e(TAG, "No valid wificond scanner interface handler"); 668 return false; 669 } 670 PnoSettings settings = new PnoSettings(); 671 settings.pnoNetworks = new ArrayList<>(); 672 settings.intervalMs = pnoSettings.periodInMs; 673 settings.min2gRssi = pnoSettings.min24GHzRssi; 674 settings.min5gRssi = pnoSettings.min5GHzRssi; 675 if (pnoSettings.networkList != null) { 676 for (WifiNative.PnoNetwork network : pnoSettings.networkList) { 677 PnoNetwork condNetwork = new PnoNetwork(); 678 condNetwork.isHidden = (network.flags 679 & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0; 680 try { 681 condNetwork.ssid = 682 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid)); 683 } catch (IllegalArgumentException e) { 684 Log.e(TAG, "Illegal argument " + network.ssid, e); 685 continue; 686 } 687 settings.pnoNetworks.add(condNetwork); 688 } 689 } 690 691 try { 692 boolean success = scannerImpl.startPnoScan(settings); 693 mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount(); 694 if (!success) { 695 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 696 } 697 return success; 698 } catch (RemoteException e1) { 699 Log.e(TAG, "Failed to start pno scan due to remote exception"); 700 } 701 return false; 702 } 703 704 /** 705 * Stop PNO scan. 706 * @param ifaceName Name of the interface. 707 * @return true on success. 708 */ 709 public boolean stopPnoScan(@NonNull String ifaceName) { 710 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 711 if (scannerImpl == null) { 712 Log.e(TAG, "No valid wificond scanner interface handler"); 713 return false; 714 } 715 try { 716 return scannerImpl.stopPnoScan(); 717 } catch (RemoteException e1) { 718 Log.e(TAG, "Failed to stop pno scan due to remote exception"); 719 } 720 return false; 721 } 722 723 /** 724 * Abort ongoing single scan. 725 * @param ifaceName Name of the interface. 726 */ 727 public void abortScan(@NonNull String ifaceName) { 728 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 729 if (scannerImpl == null) { 730 Log.e(TAG, "No valid wificond scanner interface handler"); 731 return; 732 } 733 try { 734 scannerImpl.abortScan(); 735 } catch (RemoteException e1) { 736 Log.e(TAG, "Failed to request abortScan due to remote exception"); 737 } 738 } 739 740 /** 741 * Query the list of valid frequencies for the provided band. 742 * The result depends on the on the country code that has been set. 743 * 744 * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants. 745 * The following bands are supported: 746 * WifiScanner.WIFI_BAND_24_GHZ 747 * WifiScanner.WIFI_BAND_5_GHZ 748 * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY 749 * @return frequencies vector of valid frequencies (MHz), or null for error. 750 * @throws IllegalArgumentException if band is not recognized. 751 */ 752 public int [] getChannelsForBand(int band) { 753 if (mWificond == null) { 754 Log.e(TAG, "No valid wificond scanner interface handler"); 755 return null; 756 } 757 try { 758 switch (band) { 759 case WifiScanner.WIFI_BAND_24_GHZ: 760 return mWificond.getAvailable2gChannels(); 761 case WifiScanner.WIFI_BAND_5_GHZ: 762 return mWificond.getAvailable5gNonDFSChannels(); 763 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: 764 return mWificond.getAvailableDFSChannels(); 765 default: 766 throw new IllegalArgumentException("unsupported band " + band); 767 } 768 } catch (RemoteException e1) { 769 Log.e(TAG, "Failed to request getChannelsForBand due to remote exception"); 770 } 771 return null; 772 } 773 774 /** Helper function to look up the interface handle using name */ 775 private IApInterface getApInterface(@NonNull String ifaceName) { 776 return mApInterfaces.get(ifaceName); 777 } 778 779 /** 780 * Start hostapd 781 * TODO(b/71513606): Move this to a global operation. 782 * 783 * @param ifaceName Name of the interface. 784 * @param listener Callback for AP events. 785 * @return true on success, false otherwise. 786 */ 787 public boolean startHostapd(@NonNull String ifaceName, 788 SoftApListener listener) { 789 IApInterface iface = getApInterface(ifaceName); 790 if (iface == null) { 791 Log.e(TAG, "No valid ap interface handler"); 792 return false; 793 } 794 try { 795 IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener); 796 mApInterfaceListeners.put(ifaceName, callback); 797 boolean success = iface.startHostapd(callback); 798 if (!success) { 799 Log.e(TAG, "Failed to start hostapd."); 800 return false; 801 } 802 } catch (RemoteException e) { 803 Log.e(TAG, "Exception in starting soft AP: " + e); 804 return false; 805 } 806 return true; 807 } 808 809 /** 810 * Stop hostapd 811 * TODO(b/71513606): Move this to a global operation. 812 * 813 * @param ifaceName Name of the interface. 814 * @return true on success, false otherwise. 815 */ 816 public boolean stopHostapd(@NonNull String ifaceName) { 817 IApInterface iface = getApInterface(ifaceName); 818 if (iface == null) { 819 Log.e(TAG, "No valid ap interface handler"); 820 return false; 821 } 822 try { 823 boolean success = iface.stopHostapd(); 824 if (!success) { 825 Log.e(TAG, "Failed to stop hostapd."); 826 return false; 827 } 828 } catch (RemoteException e) { 829 Log.e(TAG, "Exception in stopping soft AP: " + e); 830 return false; 831 } 832 mApInterfaceListeners.remove(ifaceName); 833 return true; 834 } 835 836 /** 837 * Set Mac address on the given interface 838 * @param interfaceName Name of the interface. 839 * @param mac Mac address to change into 840 * @return true on success, false otherwise. 841 */ 842 public boolean setMacAddress(@NonNull String interfaceName, @NonNull MacAddress mac) { 843 IClientInterface mClientInterface = getClientInterface(interfaceName); 844 if (mClientInterface == null) { 845 Log.e(TAG, "No valid wificond client interface handler"); 846 return false; 847 } 848 byte[] macByteArray = mac.toByteArray(); 849 850 try { 851 mClientInterface.setMacAddress(macByteArray); 852 } catch (RemoteException e) { 853 Log.e(TAG, "Failed to setMacAddress due to remote exception"); 854 return false; 855 } 856 return true; 857 } 858 859 /** 860 * Clear all internal handles. 861 */ 862 private void clearState() { 863 // Refresh handlers 864 mClientInterfaces.clear(); 865 mWificondScanners.clear(); 866 mPnoScanEventHandlers.clear(); 867 mScanEventHandlers.clear(); 868 mApInterfaces.clear(); 869 mApInterfaceListeners.clear(); 870 } 871 } 872