WificondControl.java revision a2dae3436431f3fe2ac79ad087fe62f6fcda8ad7
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 17package com.android.server.wifi; 18 19import android.net.wifi.IApInterface; 20import android.net.wifi.IClientInterface; 21import android.net.wifi.IPnoScanEvent; 22import android.net.wifi.IScanEvent; 23import android.net.wifi.IWifiScannerImpl; 24import android.net.wifi.IWificond; 25import android.net.wifi.ScanResult; 26import android.net.wifi.WifiScanner; 27import android.net.wifi.WifiSsid; 28import android.os.Binder; 29import android.os.RemoteException; 30import android.util.Log; 31 32import com.android.server.wifi.hotspot2.NetworkDetail; 33import com.android.server.wifi.util.InformationElementUtil; 34import com.android.server.wifi.util.NativeUtil; 35import com.android.server.wifi.util.ScanResultUtil; 36import com.android.server.wifi.wificond.ChannelSettings; 37import com.android.server.wifi.wificond.HiddenNetwork; 38import com.android.server.wifi.wificond.NativeScanResult; 39import com.android.server.wifi.wificond.PnoNetwork; 40import com.android.server.wifi.wificond.PnoSettings; 41import com.android.server.wifi.wificond.SingleScanSettings; 42 43import java.util.ArrayList; 44import java.util.Set; 45 46/** 47 * This class provides methods for WifiNative to send control commands to wificond. 48 * NOTE: This class should only be used from WifiNative. 49 */ 50public class WificondControl { 51 private boolean mVerboseLoggingEnabled = false; 52 53 private static final String TAG = "WificondControl"; 54 55 /* Get scan results for a single scan */ 56 public static final int SCAN_TYPE_SINGLE_SCAN = 0; 57 58 /* Get scan results for Pno Scan */ 59 public static final int SCAN_TYPE_PNO_SCAN = 1; 60 61 private WifiInjector mWifiInjector; 62 private WifiMonitor mWifiMonitor; 63 private final CarrierNetworkConfig mCarrierNetworkConfig; 64 65 // Cached wificond binder handlers. 66 private IWificond mWificond; 67 private IClientInterface mClientInterface; 68 private IApInterface mApInterface; 69 private IWifiScannerImpl mWificondScanner; 70 private IScanEvent mScanEventHandler; 71 private IPnoScanEvent mPnoScanEventHandler; 72 73 private String mClientInterfaceName; 74 75 76 private class ScanEventHandler extends IScanEvent.Stub { 77 @Override 78 public void OnScanResultReady() { 79 Log.d(TAG, "Scan result ready event"); 80 mWifiMonitor.broadcastScanResultEvent(mClientInterfaceName); 81 } 82 83 @Override 84 public void OnScanFailed() { 85 Log.d(TAG, "Scan failed event"); 86 mWifiMonitor.broadcastScanFailedEvent(mClientInterfaceName); 87 } 88 } 89 90 WificondControl(WifiInjector wifiInjector, WifiMonitor wifiMonitor, 91 CarrierNetworkConfig carrierNetworkConfig) { 92 mWifiInjector = wifiInjector; 93 mWifiMonitor = wifiMonitor; 94 mCarrierNetworkConfig = carrierNetworkConfig; 95 } 96 97 private class PnoScanEventHandler extends IPnoScanEvent.Stub { 98 @Override 99 public void OnPnoNetworkFound() { 100 Log.d(TAG, "Pno scan result event"); 101 mWifiMonitor.broadcastPnoScanResultEvent(mClientInterfaceName); 102 mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount(); 103 } 104 105 @Override 106 public void OnPnoScanFailed() { 107 Log.d(TAG, "Pno Scan failed event"); 108 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 109 } 110 111 @Override 112 public void OnPnoScanOverOffloadStarted() { 113 Log.d(TAG, "Pno scan over offload started"); 114 mWifiInjector.getWifiMetrics().incrementPnoScanStartedOverOffloadCount(); 115 } 116 117 @Override 118 public void OnPnoScanOverOffloadFailed(int reason) { 119 Log.d(TAG, "Pno scan over offload failed"); 120 mWifiInjector.getWifiMetrics().incrementPnoScanFailedOverOffloadCount(); 121 } 122 } 123 124 /** Enable or disable verbose logging of WificondControl. 125 * @param enable True to enable verbose logging. False to disable verbose logging. 126 */ 127 public void enableVerboseLogging(boolean enable) { 128 mVerboseLoggingEnabled = enable; 129 } 130 131 /** 132 * Setup driver for client mode via wificond. 133 * @return An IClientInterface as wificond client interface binder handler. 134 * Returns null on failure. 135 */ 136 public IClientInterface setupDriverForClientMode() { 137 Log.d(TAG, "Setting up driver for client mode"); 138 mWificond = mWifiInjector.makeWificond(); 139 if (mWificond == null) { 140 Log.e(TAG, "Failed to get reference to wificond"); 141 return null; 142 } 143 144 IClientInterface clientInterface = null; 145 try { 146 clientInterface = mWificond.createClientInterface(); 147 } catch (RemoteException e1) { 148 Log.e(TAG, "Failed to get IClientInterface due to remote exception"); 149 return null; 150 } 151 152 if (clientInterface == null) { 153 Log.e(TAG, "Could not get IClientInterface instance from wificond"); 154 return null; 155 } 156 Binder.allowBlocking(clientInterface.asBinder()); 157 158 // Refresh Handlers 159 mClientInterface = clientInterface; 160 try { 161 mClientInterfaceName = clientInterface.getInterfaceName(); 162 mWificondScanner = mClientInterface.getWifiScannerImpl(); 163 if (mWificondScanner == null) { 164 Log.e(TAG, "Failed to get WificondScannerImpl"); 165 return null; 166 } 167 Binder.allowBlocking(mWificondScanner.asBinder()); 168 mScanEventHandler = new ScanEventHandler(); 169 mWificondScanner.subscribeScanEvents(mScanEventHandler); 170 mPnoScanEventHandler = new PnoScanEventHandler(); 171 mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler); 172 } catch (RemoteException e) { 173 Log.e(TAG, "Failed to refresh wificond scanner due to remote exception"); 174 } 175 176 return clientInterface; 177 } 178 179 /** 180 * Setup driver for softAp mode via wificond. 181 * @return An IApInterface as wificond Ap interface binder handler. 182 * Returns null on failure. 183 */ 184 public IApInterface setupDriverForSoftApMode() { 185 Log.d(TAG, "Setting up driver for soft ap mode"); 186 mWificond = mWifiInjector.makeWificond(); 187 if (mWificond == null) { 188 Log.e(TAG, "Failed to get reference to wificond"); 189 return null; 190 } 191 192 IApInterface apInterface = null; 193 try { 194 apInterface = mWificond.createApInterface(); 195 } catch (RemoteException e1) { 196 Log.e(TAG, "Failed to get IApInterface due to remote exception"); 197 return null; 198 } 199 200 if (apInterface == null) { 201 Log.e(TAG, "Could not get IApInterface instance from wificond"); 202 return null; 203 } 204 Binder.allowBlocking(apInterface.asBinder()); 205 206 // Refresh Handlers 207 mApInterface = apInterface; 208 209 return apInterface; 210 } 211 212 /** 213 * Teardown all interfaces configured in wificond. 214 * @return Returns true on success. 215 */ 216 public boolean tearDownInterfaces() { 217 Log.d(TAG, "tearing down interfaces in wificond"); 218 // Explicitly refresh the wificodn handler because |tearDownInterfaces()| 219 // could be used to cleanup before we setup any interfaces. 220 mWificond = mWifiInjector.makeWificond(); 221 if (mWificond == null) { 222 Log.e(TAG, "Failed to get reference to wificond"); 223 return false; 224 } 225 226 try { 227 if (mWificondScanner != null) { 228 mWificondScanner.unsubscribeScanEvents(); 229 mWificondScanner.unsubscribePnoScanEvents(); 230 } 231 mWificond.tearDownInterfaces(); 232 233 // Refresh handlers 234 mClientInterface = null; 235 mWificondScanner = null; 236 mPnoScanEventHandler = null; 237 mScanEventHandler = null; 238 mApInterface = null; 239 240 return true; 241 } catch (RemoteException e) { 242 Log.e(TAG, "Failed to tear down interfaces due to remote exception"); 243 } 244 245 return false; 246 } 247 248 /** 249 * Disable wpa_supplicant via wificond. 250 * @return Returns true on success. 251 */ 252 public boolean disableSupplicant() { 253 if (mClientInterface == null) { 254 Log.e(TAG, "No valid wificond client interface handler"); 255 return false; 256 } 257 try { 258 return mClientInterface.disableSupplicant(); 259 } catch (RemoteException e) { 260 Log.e(TAG, "Failed to disable supplicant due to remote exception"); 261 } 262 return false; 263 } 264 265 /** 266 * Enable wpa_supplicant via wificond. 267 * @return Returns true on success. 268 */ 269 public boolean enableSupplicant() { 270 if (mClientInterface == null) { 271 Log.e(TAG, "No valid wificond client interface handler"); 272 return false; 273 } 274 275 try { 276 return mClientInterface.enableSupplicant(); 277 } catch (RemoteException e) { 278 Log.e(TAG, "Failed to enable supplicant due to remote exception"); 279 } 280 return false; 281 } 282 283 /** 284 * Request signal polling to wificond. 285 * Returns an SignalPollResult object. 286 * Returns null on failure. 287 */ 288 public WifiNative.SignalPollResult signalPoll() { 289 if (mClientInterface == null) { 290 Log.e(TAG, "No valid wificond client interface handler"); 291 return null; 292 } 293 294 int[] resultArray; 295 try { 296 resultArray = mClientInterface.signalPoll(); 297 if (resultArray == null || resultArray.length != 3) { 298 Log.e(TAG, "Invalid signal poll result from wificond"); 299 return null; 300 } 301 } catch (RemoteException e) { 302 Log.e(TAG, "Failed to do signal polling due to remote exception"); 303 return null; 304 } 305 WifiNative.SignalPollResult pollResult = new WifiNative.SignalPollResult(); 306 pollResult.currentRssi = resultArray[0]; 307 pollResult.txBitrate = resultArray[1]; 308 pollResult.associationFrequency = resultArray[2]; 309 return pollResult; 310 } 311 312 /** 313 * Fetch TX packet counters on current connection from wificond. 314 * Returns an TxPacketCounters object. 315 * Returns null on failure. 316 */ 317 public WifiNative.TxPacketCounters getTxPacketCounters() { 318 if (mClientInterface == null) { 319 Log.e(TAG, "No valid wificond client interface handler"); 320 return null; 321 } 322 323 int[] resultArray; 324 try { 325 resultArray = mClientInterface.getPacketCounters(); 326 if (resultArray == null || resultArray.length != 2) { 327 Log.e(TAG, "Invalid signal poll result from wificond"); 328 return null; 329 } 330 } catch (RemoteException e) { 331 Log.e(TAG, "Failed to do signal polling due to remote exception"); 332 return null; 333 } 334 WifiNative.TxPacketCounters counters = new WifiNative.TxPacketCounters(); 335 counters.txSucceeded = resultArray[0]; 336 counters.txFailed = resultArray[1]; 337 return counters; 338 } 339 340 /** 341 * Fetch the latest scan result from kernel via wificond. 342 * @return Returns an ArrayList of ScanDetail. 343 * Returns an empty ArrayList on failure. 344 */ 345 public ArrayList<ScanDetail> getScanResults(int scanType) { 346 ArrayList<ScanDetail> results = new ArrayList<>(); 347 if (mWificondScanner == null) { 348 Log.e(TAG, "No valid wificond scanner interface handler"); 349 return results; 350 } 351 try { 352 NativeScanResult[] nativeResults; 353 if (scanType == SCAN_TYPE_SINGLE_SCAN) { 354 nativeResults = mWificondScanner.getScanResults(); 355 } else { 356 nativeResults = mWificondScanner.getPnoScanResults(); 357 } 358 for (NativeScanResult result : nativeResults) { 359 WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid); 360 String bssid; 361 try { 362 bssid = NativeUtil.macAddressFromByteArray(result.bssid); 363 } catch (IllegalArgumentException e) { 364 Log.e(TAG, "Illegal argument " + result.bssid, e); 365 continue; 366 } 367 if (bssid == null) { 368 Log.e(TAG, "Illegal null bssid"); 369 continue; 370 } 371 ScanResult.InformationElement[] ies = 372 InformationElementUtil.parseInformationElements(result.infoElement); 373 InformationElementUtil.Capabilities capabilities = 374 new InformationElementUtil.Capabilities(); 375 capabilities.from(ies, result.capability); 376 String flags = capabilities.generateCapabilitiesString(); 377 NetworkDetail networkDetail = 378 new NetworkDetail(bssid, ies, null, result.frequency); 379 380 ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags, 381 result.signalMbm / 100, result.frequency, result.tsf, ies, null); 382 // Update carrier network info if this AP's SSID is associated with a carrier Wi-Fi 383 // network and it uses EAP. 384 if (ScanResultUtil.isScanResultForEapNetwork(scanDetail.getScanResult()) 385 && mCarrierNetworkConfig.isCarrierNetwork(wifiSsid.toString())) { 386 scanDetail.getScanResult().isCarrierAp = true; 387 scanDetail.getScanResult().carrierApEapType = 388 mCarrierNetworkConfig.getNetworkEapType(wifiSsid.toString()); 389 scanDetail.getScanResult().carrierName = 390 mCarrierNetworkConfig.getCarrierName(wifiSsid.toString()); 391 } 392 results.add(scanDetail); 393 } 394 } catch (RemoteException e1) { 395 Log.e(TAG, "Failed to create ScanDetail ArrayList"); 396 } 397 if (mVerboseLoggingEnabled) { 398 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 399 } 400 401 return results; 402 } 403 404 /** 405 * Start a scan using wificond for the given parameters. 406 * @param freqs list of frequencies to scan for, if null scan all supported channels. 407 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for. 408 * @return Returns true on success. 409 */ 410 public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) { 411 if (mWificondScanner == null) { 412 Log.e(TAG, "No valid wificond scanner interface handler"); 413 return false; 414 } 415 SingleScanSettings settings = new SingleScanSettings(); 416 settings.channelSettings = new ArrayList<>(); 417 settings.hiddenNetworks = new ArrayList<>(); 418 419 if (freqs != null) { 420 for (Integer freq : freqs) { 421 ChannelSettings channel = new ChannelSettings(); 422 channel.frequency = freq; 423 settings.channelSettings.add(channel); 424 } 425 } 426 if (hiddenNetworkSSIDs != null) { 427 for (String ssid : hiddenNetworkSSIDs) { 428 HiddenNetwork network = new HiddenNetwork(); 429 try { 430 network.ssid = NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)); 431 } catch (IllegalArgumentException e) { 432 Log.e(TAG, "Illegal argument " + ssid, e); 433 continue; 434 } 435 settings.hiddenNetworks.add(network); 436 } 437 } 438 439 try { 440 return mWificondScanner.scan(settings); 441 } catch (RemoteException e1) { 442 Log.e(TAG, "Failed to request scan due to remote exception"); 443 } 444 return false; 445 } 446 447 /** 448 * Start PNO scan. 449 * @param pnoSettings Pno scan configuration. 450 * @return true on success. 451 */ 452 public boolean startPnoScan(WifiNative.PnoSettings pnoSettings) { 453 if (mWificondScanner == null) { 454 Log.e(TAG, "No valid wificond scanner interface handler"); 455 return false; 456 } 457 PnoSettings settings = new PnoSettings(); 458 settings.pnoNetworks = new ArrayList<>(); 459 settings.intervalMs = pnoSettings.periodInMs; 460 settings.min2gRssi = pnoSettings.min24GHzRssi; 461 settings.min5gRssi = pnoSettings.min5GHzRssi; 462 if (pnoSettings.networkList != null) { 463 for (WifiNative.PnoNetwork network : pnoSettings.networkList) { 464 PnoNetwork condNetwork = new PnoNetwork(); 465 condNetwork.isHidden = (network.flags 466 & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0; 467 try { 468 condNetwork.ssid = 469 NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(network.ssid)); 470 } catch (IllegalArgumentException e) { 471 Log.e(TAG, "Illegal argument " + network.ssid, e); 472 continue; 473 } 474 settings.pnoNetworks.add(condNetwork); 475 } 476 } 477 478 try { 479 boolean success = mWificondScanner.startPnoScan(settings); 480 mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount(); 481 if (!success) { 482 mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount(); 483 } 484 return success; 485 } catch (RemoteException e1) { 486 Log.e(TAG, "Failed to start pno scan due to remote exception"); 487 } 488 return false; 489 } 490 491 /** 492 * Stop PNO scan. 493 * @return true on success. 494 */ 495 public boolean stopPnoScan() { 496 if (mWificondScanner == null) { 497 Log.e(TAG, "No valid wificond scanner interface handler"); 498 return false; 499 } 500 try { 501 return mWificondScanner.stopPnoScan(); 502 } catch (RemoteException e1) { 503 Log.e(TAG, "Failed to stop pno scan due to remote exception"); 504 } 505 return false; 506 } 507 508 /** 509 * Abort ongoing single scan. 510 */ 511 public void abortScan() { 512 if (mWificondScanner == null) { 513 Log.e(TAG, "No valid wificond scanner interface handler"); 514 return; 515 } 516 try { 517 mWificondScanner.abortScan(); 518 } catch (RemoteException e1) { 519 Log.e(TAG, "Failed to request abortScan due to remote exception"); 520 } 521 } 522 523} 524