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