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 android.net.wifi.nl80211; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.app.AlarmManager; 26 import android.content.Context; 27 import android.net.wifi.SoftApInfo; 28 import android.net.wifi.WifiAnnotations; 29 import android.net.wifi.WifiScanner; 30 import android.os.Binder; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.RemoteException; 34 import android.os.ServiceManager; 35 import android.os.SystemClock; 36 import android.util.Log; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Set; 48 import java.util.concurrent.Executor; 49 import java.util.concurrent.atomic.AtomicBoolean; 50 51 /** 52 * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework - used 53 * to encapsulate the Wi-Fi 80211nl management interface. The 54 * interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions. 55 * 56 * @hide 57 */ 58 @SystemApi 59 @SystemService(Context.WIFI_NL80211_SERVICE) 60 public class WifiNl80211Manager { 61 private static final String TAG = "WifiNl80211Manager"; 62 private boolean mVerboseLoggingEnabled = false; 63 64 /** 65 * The {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} 66 * timeout, in milliseconds, after which 67 * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason 68 * {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}. 69 */ 70 private static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000; 71 72 private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout"; 73 74 /** @hide */ 75 @Retention(RetentionPolicy.SOURCE) 76 @IntDef(prefix = {"SCAN_TYPE_"}, 77 value = {SCAN_TYPE_SINGLE_SCAN, 78 SCAN_TYPE_PNO_SCAN}) 79 public @interface ScanResultType {} 80 81 /** 82 * Specifies a scan type: single scan initiated by the framework. Can be used in 83 * {@link #getScanResults(String, int)} to specify the type of scan result to fetch. 84 */ 85 public static final int SCAN_TYPE_SINGLE_SCAN = 0; 86 87 /** 88 * Specifies a scan type: PNO scan. Can be used in {@link #getScanResults(String, int)} to 89 * specify the type of scan result to fetch. 90 */ 91 public static final int SCAN_TYPE_PNO_SCAN = 1; 92 93 private AlarmManager mAlarmManager; 94 private Handler mEventHandler; 95 96 // Cached wificond binder handlers. 97 private IWificond mWificond; 98 private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>(); 99 private HashMap<String, IApInterface> mApInterfaces = new HashMap<>(); 100 private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>(); 101 private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>(); 102 private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>(); 103 private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>(); 104 private Runnable mDeathEventHandler; 105 /** 106 * Ensures that no more than one sendMgmtFrame operation runs concurrently. 107 */ 108 private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false); 109 110 /** 111 * Interface used when waiting for scans to be completed (with results). 112 */ 113 public interface ScanEventCallback { 114 /** 115 * Called when scan results are available. Scans results should then be obtained from 116 * {@link #getScanResults(String, int)}. 117 */ onScanResultReady()118 void onScanResultReady(); 119 120 /** 121 * Called when a scan has failed. 122 */ onScanFailed()123 void onScanFailed(); 124 } 125 126 /** 127 * Interface for a callback to provide information about PNO scan request requested with 128 * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. Note that the 129 * callback are for the status of the request - not the scan itself. The results of the scan 130 * are returned with {@link ScanEventCallback}. 131 */ 132 public interface PnoScanRequestCallback { 133 /** 134 * Called when a PNO scan request has been successfully submitted. 135 */ onPnoRequestSucceeded()136 void onPnoRequestSucceeded(); 137 138 /** 139 * Called when a PNO scan request fails. 140 */ onPnoRequestFailed()141 void onPnoRequestFailed(); 142 } 143 144 private class ScanEventHandler extends IScanEvent.Stub { 145 private Executor mExecutor; 146 private ScanEventCallback mCallback; 147 ScanEventHandler(@onNull Executor executor, @NonNull ScanEventCallback callback)148 ScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) { 149 mExecutor = executor; 150 mCallback = callback; 151 } 152 153 @Override OnScanResultReady()154 public void OnScanResultReady() { 155 Log.d(TAG, "Scan result ready event"); 156 Binder.clearCallingIdentity(); 157 mExecutor.execute(() -> mCallback.onScanResultReady()); 158 } 159 160 @Override OnScanFailed()161 public void OnScanFailed() { 162 Log.d(TAG, "Scan failed event"); 163 Binder.clearCallingIdentity(); 164 mExecutor.execute(() -> mCallback.onScanFailed()); 165 } 166 } 167 168 /** 169 * Result of a signal poll requested using {@link #signalPoll(String)}. 170 */ 171 public static class SignalPollResult { 172 /** @hide */ SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps, int associationFrequencyMHz)173 public SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps, 174 int associationFrequencyMHz) { 175 this.currentRssiDbm = currentRssiDbm; 176 this.txBitrateMbps = txBitrateMbps; 177 this.rxBitrateMbps = rxBitrateMbps; 178 this.associationFrequencyMHz = associationFrequencyMHz; 179 } 180 181 /** 182 * RSSI value in dBM. 183 */ 184 public final int currentRssiDbm; 185 186 /** 187 * Transmission bit rate in Mbps. 188 */ 189 public final int txBitrateMbps; 190 191 /** 192 * Last received packet bit rate in Mbps. 193 */ 194 public final int rxBitrateMbps; 195 196 /** 197 * Association frequency in MHz. 198 */ 199 public final int associationFrequencyMHz; 200 } 201 202 /** 203 * Transmission counters obtained using {@link #getTxPacketCounters(String)}. 204 */ 205 public static class TxPacketCounters { 206 /** @hide */ TxPacketCounters(int txPacketSucceeded, int txPacketFailed)207 public TxPacketCounters(int txPacketSucceeded, int txPacketFailed) { 208 this.txPacketSucceeded = txPacketSucceeded; 209 this.txPacketFailed = txPacketFailed; 210 } 211 212 /** 213 * Number of successfully transmitted packets. 214 */ 215 public final int txPacketSucceeded; 216 217 /** 218 * Number of packet transmission failures. 219 */ 220 public final int txPacketFailed; 221 } 222 223 /** 224 * Callbacks for SoftAp interface registered using 225 * {@link #registerApCallback(String, Executor, SoftApCallback)}. 226 */ 227 public interface SoftApCallback { 228 /** 229 * Invoked when there is a fatal failure and the SoftAp is shutdown. 230 */ onFailure()231 void onFailure(); 232 233 /** 234 * Invoked when there is a change in the associated station (STA). 235 * @param client Information about the client whose status has changed. 236 * @param isConnected Indication as to whether the client is connected (true), or 237 * disconnected (false). 238 */ onConnectedClientsChanged(@onNull NativeWifiClient client, boolean isConnected)239 void onConnectedClientsChanged(@NonNull NativeWifiClient client, boolean isConnected); 240 241 /** 242 * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different 243 * channel. Also called on initial registration. 244 * @param frequencyMhz The new frequency of the SoftAp. A value of 0 is invalid and is an 245 * indication that the SoftAp is not enabled. 246 * @param bandwidth The new bandwidth of the SoftAp. 247 */ onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth)248 void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth); 249 } 250 251 /** 252 * Callback to notify the results of a 253 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} call. 254 * Note: no callbacks will be triggered if the interface dies while sending a frame. 255 */ 256 public interface SendMgmtFrameCallback { 257 /** 258 * Called when the management frame was successfully sent and ACKed by the recipient. 259 * @param elapsedTimeMs The elapsed time between when the management frame was sent and when 260 * the ACK was processed, in milliseconds, as measured by wificond. 261 * This includes the time that the send frame spent queuing before it 262 * was sent, any firmware retries, and the time the received ACK spent 263 * queuing before it was processed. 264 */ onAck(int elapsedTimeMs)265 void onAck(int elapsedTimeMs); 266 267 /** 268 * Called when the send failed. 269 * @param reason The error code for the failure. 270 */ onFailure(@endMgmtFrameError int reason)271 void onFailure(@SendMgmtFrameError int reason); 272 } 273 274 /** @hide */ 275 @Retention(RetentionPolicy.SOURCE) 276 @IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"}, 277 value = {SEND_MGMT_FRAME_ERROR_UNKNOWN, 278 SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED, 279 SEND_MGMT_FRAME_ERROR_NO_ACK, 280 SEND_MGMT_FRAME_ERROR_TIMEOUT, 281 SEND_MGMT_FRAME_ERROR_ALREADY_STARTED}) 282 public @interface SendMgmtFrameError {} 283 284 // Send management frame error codes 285 286 /** 287 * Unknown error occurred during call to 288 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}. 289 */ 290 public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; 291 292 /** 293 * Specifying the MCS rate in 294 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} is not 295 * supported by this device. 296 */ 297 public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; 298 299 /** 300 * Driver reported that no ACK was received for the frame transmitted using 301 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}. 302 */ 303 public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; 304 305 /** 306 * Error code for when the driver fails to report on the status of the frame sent by 307 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} 308 * after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds. 309 */ 310 public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; 311 312 /** 313 * An existing call to 314 * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} 315 * is in progress. Another frame cannot be sent until the first call completes. 316 */ 317 public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; 318 319 /** @hide */ WifiNl80211Manager(Context context)320 public WifiNl80211Manager(Context context) { 321 mAlarmManager = context.getSystemService(AlarmManager.class); 322 mEventHandler = new Handler(context.getMainLooper()); 323 } 324 325 /** @hide */ 326 @VisibleForTesting WifiNl80211Manager(Context context, IWificond wificond)327 public WifiNl80211Manager(Context context, IWificond wificond) { 328 this(context); 329 mWificond = wificond; 330 } 331 332 private class PnoScanEventHandler extends IPnoScanEvent.Stub { 333 private Executor mExecutor; 334 private ScanEventCallback mCallback; 335 PnoScanEventHandler(@onNull Executor executor, @NonNull ScanEventCallback callback)336 PnoScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) { 337 mExecutor = executor; 338 mCallback = callback; 339 } 340 341 @Override OnPnoNetworkFound()342 public void OnPnoNetworkFound() { 343 Log.d(TAG, "Pno scan result event"); 344 Binder.clearCallingIdentity(); 345 mExecutor.execute(() -> mCallback.onScanResultReady()); 346 } 347 348 @Override OnPnoScanFailed()349 public void OnPnoScanFailed() { 350 Log.d(TAG, "Pno Scan failed event"); 351 Binder.clearCallingIdentity(); 352 mExecutor.execute(() -> mCallback.onScanFailed()); 353 } 354 } 355 356 /** 357 * Listener for AP Interface events. 358 */ 359 private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub { 360 private Executor mExecutor; 361 private SoftApCallback mSoftApListener; 362 ApInterfaceEventCallback(Executor executor, SoftApCallback listener)363 ApInterfaceEventCallback(Executor executor, SoftApCallback listener) { 364 mExecutor = executor; 365 mSoftApListener = listener; 366 } 367 368 @Override onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)369 public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) { 370 if (mVerboseLoggingEnabled) { 371 Log.d(TAG, "onConnectedClientsChanged called with " 372 + client.getMacAddress() + " isConnected: " + isConnected); 373 } 374 375 Binder.clearCallingIdentity(); 376 mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected)); 377 } 378 379 @Override onSoftApChannelSwitched(int frequency, int bandwidth)380 public void onSoftApChannelSwitched(int frequency, int bandwidth) { 381 Binder.clearCallingIdentity(); 382 mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency, 383 toFrameworkBandwidth(bandwidth))); 384 } 385 toFrameworkBandwidth(int bandwidth)386 private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) { 387 switch(bandwidth) { 388 case IApInterfaceEventCallback.BANDWIDTH_INVALID: 389 return SoftApInfo.CHANNEL_WIDTH_INVALID; 390 case IApInterfaceEventCallback.BANDWIDTH_20_NOHT: 391 return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT; 392 case IApInterfaceEventCallback.BANDWIDTH_20: 393 return SoftApInfo.CHANNEL_WIDTH_20MHZ; 394 case IApInterfaceEventCallback.BANDWIDTH_40: 395 return SoftApInfo.CHANNEL_WIDTH_40MHZ; 396 case IApInterfaceEventCallback.BANDWIDTH_80: 397 return SoftApInfo.CHANNEL_WIDTH_80MHZ; 398 case IApInterfaceEventCallback.BANDWIDTH_80P80: 399 return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; 400 case IApInterfaceEventCallback.BANDWIDTH_160: 401 return SoftApInfo.CHANNEL_WIDTH_160MHZ; 402 default: 403 return SoftApInfo.CHANNEL_WIDTH_INVALID; 404 } 405 } 406 } 407 408 /** 409 * Callback triggered by wificond. 410 */ 411 private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub { 412 private Executor mExecutor; 413 private SendMgmtFrameCallback mCallback; 414 private AlarmManager.OnAlarmListener mTimeoutCallback; 415 /** 416 * ensures that mCallback is only called once 417 */ 418 private boolean mWasCalled; 419 runIfFirstCall(Runnable r)420 private void runIfFirstCall(Runnable r) { 421 if (mWasCalled) return; 422 mWasCalled = true; 423 424 mSendMgmtFrameInProgress.set(false); 425 r.run(); 426 } 427 SendMgmtFrameEvent(@onNull Executor executor, @NonNull SendMgmtFrameCallback callback)428 SendMgmtFrameEvent(@NonNull Executor executor, @NonNull SendMgmtFrameCallback callback) { 429 mExecutor = executor; 430 mCallback = callback; 431 // called in main thread 432 mTimeoutCallback = () -> runIfFirstCall(() -> { 433 if (mVerboseLoggingEnabled) { 434 Log.e(TAG, "Timed out waiting for ACK"); 435 } 436 Binder.clearCallingIdentity(); 437 mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT)); 438 }); 439 mWasCalled = false; 440 441 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 442 SystemClock.elapsedRealtime() + SEND_MGMT_FRAME_TIMEOUT_MS, 443 TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler); 444 } 445 446 // called in binder thread 447 @Override OnAck(int elapsedTimeMs)448 public void OnAck(int elapsedTimeMs) { 449 // post to main thread 450 mEventHandler.post(() -> runIfFirstCall(() -> { 451 mAlarmManager.cancel(mTimeoutCallback); 452 Binder.clearCallingIdentity(); 453 mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs)); 454 })); 455 } 456 457 // called in binder thread 458 @Override OnFailure(int reason)459 public void OnFailure(int reason) { 460 // post to main thread 461 mEventHandler.post(() -> runIfFirstCall(() -> { 462 mAlarmManager.cancel(mTimeoutCallback); 463 Binder.clearCallingIdentity(); 464 mExecutor.execute(() -> mCallback.onFailure(reason)); 465 })); 466 } 467 } 468 469 /** 470 * Called by the binder subsystem upon remote object death. 471 * Invoke all the register death handlers and clear state. 472 * @hide 473 */ 474 @VisibleForTesting binderDied()475 public void binderDied() { 476 mEventHandler.post(() -> { 477 Log.e(TAG, "Wificond died!"); 478 clearState(); 479 // Invalidate the global wificond handle on death. Will be refreshed 480 // on the next setup call. 481 mWificond = null; 482 if (mDeathEventHandler != null) { 483 mDeathEventHandler.run(); 484 } 485 }); 486 } 487 488 /** 489 * Enable or disable verbose logging of the WifiNl80211Manager module. 490 * @param enable True to enable verbose logging. False to disable verbose logging. 491 */ enableVerboseLogging(boolean enable)492 public void enableVerboseLogging(boolean enable) { 493 mVerboseLoggingEnabled = enable; 494 } 495 496 /** 497 * Register a death notification for the WifiNl80211Manager which acts as a proxy for the 498 * wificond daemon (i.e. the death listener will be called when and if the wificond daemon 499 * dies). 500 * 501 * @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies. 502 */ setOnServiceDeadCallback(@onNull Runnable deathEventHandler)503 public void setOnServiceDeadCallback(@NonNull Runnable deathEventHandler) { 504 if (mDeathEventHandler != null) { 505 Log.e(TAG, "Death handler already present"); 506 } 507 mDeathEventHandler = deathEventHandler; 508 } 509 510 /** 511 * Helper method to retrieve the global wificond handle and register for 512 * death notifications. 513 */ retrieveWificondAndRegisterForDeath()514 private boolean retrieveWificondAndRegisterForDeath() { 515 if (mWificond != null) { 516 if (mVerboseLoggingEnabled) { 517 Log.d(TAG, "Wificond handle already retrieved"); 518 } 519 // We already have a wificond handle. 520 return true; 521 } 522 IBinder binder = ServiceManager.getService(Context.WIFI_NL80211_SERVICE); 523 mWificond = IWificond.Stub.asInterface(binder); 524 if (mWificond == null) { 525 Log.e(TAG, "Failed to get reference to wificond"); 526 return false; 527 } 528 try { 529 mWificond.asBinder().linkToDeath(() -> binderDied(), 0); 530 } catch (RemoteException e) { 531 Log.e(TAG, "Failed to register death notification for wificond"); 532 // The remote has already died. 533 return false; 534 } 535 return true; 536 } 537 538 /** 539 * Set up an interface for client (STA) mode. 540 * 541 * @param ifaceName Name of the interface to configure. 542 * @param executor The Executor on which to execute the callbacks. 543 * @param scanCallback A callback for framework initiated scans. 544 * @param pnoScanCallback A callback for PNO (offloaded) scans. 545 * @return true on success. 546 */ setupInterfaceForClientMode(@onNull String ifaceName, @NonNull @CallbackExecutor Executor executor, @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback)547 public boolean setupInterfaceForClientMode(@NonNull String ifaceName, 548 @NonNull @CallbackExecutor Executor executor, 549 @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) { 550 Log.d(TAG, "Setting up interface for client mode"); 551 if (!retrieveWificondAndRegisterForDeath()) { 552 return false; 553 } 554 555 if (scanCallback == null || pnoScanCallback == null || executor == null) { 556 Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks"); 557 return false; 558 } 559 560 IClientInterface clientInterface = null; 561 try { 562 clientInterface = mWificond.createClientInterface(ifaceName); 563 } catch (RemoteException e1) { 564 Log.e(TAG, "Failed to get IClientInterface due to remote exception"); 565 return false; 566 } 567 568 if (clientInterface == null) { 569 Log.e(TAG, "Could not get IClientInterface instance from wificond"); 570 return false; 571 } 572 Binder.allowBlocking(clientInterface.asBinder()); 573 574 // Refresh Handlers 575 mClientInterfaces.put(ifaceName, clientInterface); 576 try { 577 IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl(); 578 if (wificondScanner == null) { 579 Log.e(TAG, "Failed to get WificondScannerImpl"); 580 return false; 581 } 582 mWificondScanners.put(ifaceName, wificondScanner); 583 Binder.allowBlocking(wificondScanner.asBinder()); 584 ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback); 585 mScanEventHandlers.put(ifaceName, scanEventHandler); 586 wificondScanner.subscribeScanEvents(scanEventHandler); 587 PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor, 588 pnoScanCallback); 589 mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler); 590 wificondScanner.subscribePnoScanEvents(pnoScanEventHandler); 591 } catch (RemoteException e) { 592 Log.e(TAG, "Failed to refresh wificond scanner due to remote exception"); 593 } 594 595 return true; 596 } 597 598 /** 599 * Tear down a specific client (STA) interface configured using 600 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}. 601 * 602 * @param ifaceName Name of the interface to tear down. 603 * @return Returns true on success, false on failure (e.g. when called before an interface was 604 * set up). 605 */ tearDownClientInterface(@onNull String ifaceName)606 public boolean tearDownClientInterface(@NonNull String ifaceName) { 607 if (getClientInterface(ifaceName) == null) { 608 Log.e(TAG, "No valid wificond client interface handler"); 609 return false; 610 } 611 try { 612 IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName); 613 if (scannerImpl != null) { 614 scannerImpl.unsubscribeScanEvents(); 615 scannerImpl.unsubscribePnoScanEvents(); 616 } 617 } catch (RemoteException e) { 618 Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception"); 619 return false; 620 } 621 622 if (mWificond == null) { 623 Log.e(TAG, "Reference to wifiCond is null"); 624 return false; 625 } 626 627 boolean success; 628 try { 629 success = mWificond.tearDownClientInterface(ifaceName); 630 } catch (RemoteException e1) { 631 Log.e(TAG, "Failed to teardown client interface due to remote exception"); 632 return false; 633 } 634 if (!success) { 635 Log.e(TAG, "Failed to teardown client interface"); 636 return false; 637 } 638 639 mClientInterfaces.remove(ifaceName); 640 mWificondScanners.remove(ifaceName); 641 mScanEventHandlers.remove(ifaceName); 642 mPnoScanEventHandlers.remove(ifaceName); 643 return true; 644 } 645 646 /** 647 * Set up interface as a Soft AP. 648 * 649 * @param ifaceName Name of the interface to configure. 650 * @return true on success. 651 */ setupInterfaceForSoftApMode(@onNull String ifaceName)652 public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) { 653 Log.d(TAG, "Setting up interface for soft ap mode"); 654 if (!retrieveWificondAndRegisterForDeath()) { 655 return false; 656 } 657 658 IApInterface apInterface = null; 659 try { 660 apInterface = mWificond.createApInterface(ifaceName); 661 } catch (RemoteException e1) { 662 Log.e(TAG, "Failed to get IApInterface due to remote exception"); 663 return false; 664 } 665 666 if (apInterface == null) { 667 Log.e(TAG, "Could not get IApInterface instance from wificond"); 668 return false; 669 } 670 Binder.allowBlocking(apInterface.asBinder()); 671 672 // Refresh Handlers 673 mApInterfaces.put(ifaceName, apInterface); 674 return true; 675 } 676 677 /** 678 * Tear down a Soft AP interface configured using 679 * {@link #setupInterfaceForSoftApMode(String)}. 680 * 681 * @param ifaceName Name of the interface to tear down. 682 * @return Returns true on success, false on failure (e.g. when called before an interface was 683 * set up). 684 */ tearDownSoftApInterface(@onNull String ifaceName)685 public boolean tearDownSoftApInterface(@NonNull String ifaceName) { 686 if (getApInterface(ifaceName) == null) { 687 Log.e(TAG, "No valid wificond ap interface handler"); 688 return false; 689 } 690 691 if (mWificond == null) { 692 Log.e(TAG, "Reference to wifiCond is null"); 693 return false; 694 } 695 696 boolean success; 697 try { 698 success = mWificond.tearDownApInterface(ifaceName); 699 } catch (RemoteException e1) { 700 Log.e(TAG, "Failed to teardown AP interface due to remote exception"); 701 return false; 702 } 703 if (!success) { 704 Log.e(TAG, "Failed to teardown AP interface"); 705 return false; 706 } 707 mApInterfaces.remove(ifaceName); 708 mApInterfaceListeners.remove(ifaceName); 709 return true; 710 } 711 712 /** 713 * Tear down all interfaces, whether clients (STA) or Soft AP. 714 * 715 * @return Returns true on success. 716 */ tearDownInterfaces()717 public boolean tearDownInterfaces() { 718 Log.d(TAG, "tearing down interfaces in wificond"); 719 // Explicitly refresh the wificodn handler because |tearDownInterfaces()| 720 // could be used to cleanup before we setup any interfaces. 721 if (!retrieveWificondAndRegisterForDeath()) { 722 return false; 723 } 724 725 try { 726 for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) { 727 entry.getValue().unsubscribeScanEvents(); 728 entry.getValue().unsubscribePnoScanEvents(); 729 } 730 mWificond.tearDownInterfaces(); 731 clearState(); 732 return true; 733 } catch (RemoteException e) { 734 Log.e(TAG, "Failed to tear down interfaces due to remote exception"); 735 } 736 737 return false; 738 } 739 740 /** Helper function to look up the interface handle using name */ getClientInterface(@onNull String ifaceName)741 private IClientInterface getClientInterface(@NonNull String ifaceName) { 742 return mClientInterfaces.get(ifaceName); 743 } 744 745 /** 746 * Request signal polling. 747 * 748 * @param ifaceName Name of the interface on which to poll. The interface must have been 749 * already set up using 750 *{@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 751 * or {@link #setupInterfaceForSoftApMode(String)}. 752 * 753 * @return A {@link SignalPollResult} object containing interface statistics, or a null on 754 * error (e.g. the interface hasn't been set up yet). 755 */ signalPoll(@onNull String ifaceName)756 @Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) { 757 IClientInterface iface = getClientInterface(ifaceName); 758 if (iface == null) { 759 Log.e(TAG, "No valid wificond client interface handler"); 760 return null; 761 } 762 763 int[] resultArray; 764 try { 765 resultArray = iface.signalPoll(); 766 if (resultArray == null || resultArray.length != 4) { 767 Log.e(TAG, "Invalid signal poll result from wificond"); 768 return null; 769 } 770 } catch (RemoteException e) { 771 Log.e(TAG, "Failed to do signal polling due to remote exception"); 772 return null; 773 } 774 return new SignalPollResult(resultArray[0], resultArray[1], resultArray[3], resultArray[2]); 775 } 776 777 /** 778 * Get current transmit (Tx) packet counters of the specified interface. The interface must 779 * have been already set up using 780 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 781 * or {@link #setupInterfaceForSoftApMode(String)}. 782 * 783 * @param ifaceName Name of the interface. 784 * @return {@link TxPacketCounters} of the current interface or null on error (e.g. when 785 * called before the interface has been set up). 786 */ getTxPacketCounters(@onNull String ifaceName)787 @Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) { 788 IClientInterface iface = getClientInterface(ifaceName); 789 if (iface == null) { 790 Log.e(TAG, "No valid wificond client interface handler"); 791 return null; 792 } 793 794 int[] resultArray; 795 try { 796 resultArray = iface.getPacketCounters(); 797 if (resultArray == null || resultArray.length != 2) { 798 Log.e(TAG, "Invalid signal poll result from wificond"); 799 return null; 800 } 801 } catch (RemoteException e) { 802 Log.e(TAG, "Failed to do signal polling due to remote exception"); 803 return null; 804 } 805 return new TxPacketCounters(resultArray[0], resultArray[1]); 806 } 807 808 /** Helper function to look up the scanner impl handle using name */ getScannerImpl(@onNull String ifaceName)809 private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) { 810 return mWificondScanners.get(ifaceName); 811 } 812 813 /** 814 * Fetch the latest scan results of the indicated type for the specified interface. Note that 815 * this method fetches the latest results - it does not initiate a scan. Initiating a scan can 816 * be done using {@link #startScan(String, int, Set, List)} or 817 * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. 818 * 819 * Note: The interface must have been already set up using 820 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 821 * or {@link #setupInterfaceForSoftApMode(String)}. 822 * 823 * @param ifaceName Name of the interface. 824 * @param scanType The type of scan result to be returned, can be 825 * {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}. 826 * @return Returns an array of {@link NativeScanResult} or an empty array on failure (e.g. when 827 * called before the interface has been set up). 828 */ getScanResults(@onNull String ifaceName, @ScanResultType int scanType)829 @NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName, 830 @ScanResultType int scanType) { 831 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 832 if (scannerImpl == null) { 833 Log.e(TAG, "No valid wificond scanner interface handler"); 834 return new ArrayList<>(); 835 } 836 List<NativeScanResult> results = null; 837 try { 838 if (scanType == SCAN_TYPE_SINGLE_SCAN) { 839 results = Arrays.asList(scannerImpl.getScanResults()); 840 } else { 841 results = Arrays.asList(scannerImpl.getPnoScanResults()); 842 } 843 } catch (RemoteException e1) { 844 Log.e(TAG, "Failed to create ScanDetail ArrayList"); 845 } 846 if (results == null) { 847 results = new ArrayList<>(); 848 } 849 if (mVerboseLoggingEnabled) { 850 Log.d(TAG, "get " + results.size() + " scan results from wificond"); 851 } 852 853 return results; 854 } 855 856 /** 857 * Return scan type for the parcelable {@link SingleScanSettings} 858 */ getScanType(@ifiAnnotations.ScanType int scanType)859 private static int getScanType(@WifiAnnotations.ScanType int scanType) { 860 switch (scanType) { 861 case WifiScanner.SCAN_TYPE_LOW_LATENCY: 862 return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN; 863 case WifiScanner.SCAN_TYPE_LOW_POWER: 864 return IWifiScannerImpl.SCAN_TYPE_LOW_POWER; 865 case WifiScanner.SCAN_TYPE_HIGH_ACCURACY: 866 return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY; 867 default: 868 throw new IllegalArgumentException("Invalid scan type " + scanType); 869 } 870 } 871 872 /** 873 * Start a scan using the specified parameters. A scan is an asynchronous operation. The 874 * result of the operation is returned in the {@link ScanEventCallback} registered when 875 * setting up an interface using 876 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}. 877 * The latest scans can be obtained using {@link #getScanResults(String, int)} and using a 878 * {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}. 879 * 880 * Note: The interface must have been already set up using 881 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 882 * or {@link #setupInterfaceForSoftApMode(String)}. 883 * 884 * @param ifaceName Name of the interface on which to initiate the scan. 885 * @param scanType Type of scan to perform, can be any of 886 * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or 887 * {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}. 888 * @param freqs list of frequencies to scan for, if null scan all supported channels. 889 * @param hiddenNetworkSSIDs List of hidden networks to be scanned for, a null indicates that 890 * no hidden frequencies will be scanned for. 891 * @return Returns true on success, false on failure (e.g. when called before the interface 892 * has been set up). 893 */ startScan(@onNull String ifaceName, @WifiAnnotations.ScanType int scanType, @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs)894 public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, 895 @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) { 896 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 897 if (scannerImpl == null) { 898 Log.e(TAG, "No valid wificond scanner interface handler"); 899 return false; 900 } 901 SingleScanSettings settings = new SingleScanSettings(); 902 try { 903 settings.scanType = getScanType(scanType); 904 } catch (IllegalArgumentException e) { 905 Log.e(TAG, "Invalid scan type ", e); 906 return false; 907 } 908 settings.channelSettings = new ArrayList<>(); 909 settings.hiddenNetworks = new ArrayList<>(); 910 911 if (freqs != null) { 912 for (Integer freq : freqs) { 913 ChannelSettings channel = new ChannelSettings(); 914 channel.frequency = freq; 915 settings.channelSettings.add(channel); 916 } 917 } 918 if (hiddenNetworkSSIDs != null) { 919 for (byte[] ssid : hiddenNetworkSSIDs) { 920 HiddenNetwork network = new HiddenNetwork(); 921 network.ssid = ssid; 922 923 // settings.hiddenNetworks is expected to be very small, so this shouldn't cause 924 // any performance issues. 925 if (!settings.hiddenNetworks.contains(network)) { 926 settings.hiddenNetworks.add(network); 927 } 928 } 929 } 930 931 try { 932 return scannerImpl.scan(settings); 933 } catch (RemoteException e1) { 934 Log.e(TAG, "Failed to request scan due to remote exception"); 935 } 936 return false; 937 } 938 939 /** 940 * Request a PNO (Preferred Network Offload). The offload request and the scans are asynchronous 941 * operations. The result of the request are returned in the {@code callback} parameter which 942 * is an {@link PnoScanRequestCallback}. The scan results are are return in the 943 * {@link ScanEventCallback} which is registered when setting up an interface using 944 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}. 945 * The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the 946 * {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}. 947 * 948 * Note: The interface must have been already set up using 949 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 950 * or {@link #setupInterfaceForSoftApMode(String)}. 951 * 952 * @param ifaceName Name of the interface on which to request a PNO. 953 * @param pnoSettings PNO scan configuration. 954 * @param executor The Executor on which to execute the callback. 955 * @param callback Callback for the results of the offload request. 956 * @return true on success, false on failure (e.g. when called before the interface has been set 957 * up). 958 */ startPnoScan(@onNull String ifaceName, @NonNull PnoSettings pnoSettings, @NonNull @CallbackExecutor Executor executor, @NonNull PnoScanRequestCallback callback)959 public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings, 960 @NonNull @CallbackExecutor Executor executor, 961 @NonNull PnoScanRequestCallback callback) { 962 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 963 if (scannerImpl == null) { 964 Log.e(TAG, "No valid wificond scanner interface handler"); 965 return false; 966 } 967 968 if (callback == null || executor == null) { 969 Log.e(TAG, "startPnoScan called with a null callback"); 970 return false; 971 } 972 973 try { 974 boolean success = scannerImpl.startPnoScan(pnoSettings); 975 if (success) { 976 executor.execute(callback::onPnoRequestSucceeded); 977 } else { 978 executor.execute(callback::onPnoRequestFailed); 979 } 980 return success; 981 } catch (RemoteException e1) { 982 Log.e(TAG, "Failed to start pno scan due to remote exception"); 983 } 984 return false; 985 } 986 987 /** 988 * Stop PNO scan configured with 989 * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. 990 * 991 * Note: The interface must have been already set up using 992 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 993 * or {@link #setupInterfaceForSoftApMode(String)}. 994 * 995 * @param ifaceName Name of the interface on which the PNO scan was configured. 996 * @return true on success, false on failure (e.g. when called before the interface has been 997 * set up). 998 */ stopPnoScan(@onNull String ifaceName)999 public boolean stopPnoScan(@NonNull String ifaceName) { 1000 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 1001 if (scannerImpl == null) { 1002 Log.e(TAG, "No valid wificond scanner interface handler"); 1003 return false; 1004 } 1005 try { 1006 return scannerImpl.stopPnoScan(); 1007 } catch (RemoteException e1) { 1008 Log.e(TAG, "Failed to stop pno scan due to remote exception"); 1009 } 1010 return false; 1011 } 1012 1013 /** 1014 * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}. No failure 1015 * callback, e.g. {@link ScanEventCallback#onScanFailed()}, is triggered by this operation. 1016 * 1017 * Note: The interface must have been already set up using 1018 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 1019 * or {@link #setupInterfaceForSoftApMode(String)}. If the interface has not been set up then 1020 * this method has no impact. 1021 * 1022 * @param ifaceName Name of the interface on which the scan was started. 1023 */ abortScan(@onNull String ifaceName)1024 public void abortScan(@NonNull String ifaceName) { 1025 IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName); 1026 if (scannerImpl == null) { 1027 Log.e(TAG, "No valid wificond scanner interface handler"); 1028 return; 1029 } 1030 try { 1031 scannerImpl.abortScan(); 1032 } catch (RemoteException e1) { 1033 Log.e(TAG, "Failed to request abortScan due to remote exception"); 1034 } 1035 } 1036 1037 /** 1038 * Query the list of valid frequencies (in MHz) for the provided band. 1039 * The result depends on the on the country code that has been set. 1040 * 1041 * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants. 1042 * The following bands are supported: 1043 * {@link WifiScanner#WIFI_BAND_24_GHZ}, 1044 * {@link WifiScanner#WIFI_BAND_5_GHZ}, 1045 * {@link WifiScanner#WIFI_BAND_5_GHZ_DFS_ONLY}, 1046 * {@link WifiScanner#WIFI_BAND_6_GHZ} 1047 * @return frequencies vector of valid frequencies (MHz), or an empty array for error. 1048 * @throws IllegalArgumentException if band is not recognized. 1049 */ getChannelsMhzForBand(@ifiAnnotations.WifiBandBasic int band)1050 public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) { 1051 if (mWificond == null) { 1052 Log.e(TAG, "No valid wificond scanner interface handler"); 1053 return new int[0]; 1054 } 1055 int[] result = null; 1056 try { 1057 switch (band) { 1058 case WifiScanner.WIFI_BAND_24_GHZ: 1059 result = mWificond.getAvailable2gChannels(); 1060 break; 1061 case WifiScanner.WIFI_BAND_5_GHZ: 1062 result = mWificond.getAvailable5gNonDFSChannels(); 1063 break; 1064 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: 1065 result = mWificond.getAvailableDFSChannels(); 1066 break; 1067 case WifiScanner.WIFI_BAND_6_GHZ: 1068 result = mWificond.getAvailable6gChannels(); 1069 break; 1070 default: 1071 throw new IllegalArgumentException("unsupported band " + band); 1072 } 1073 } catch (RemoteException e1) { 1074 Log.e(TAG, "Failed to request getChannelsForBand due to remote exception"); 1075 } 1076 if (result == null) { 1077 result = new int[0]; 1078 } 1079 return result; 1080 } 1081 1082 /** Helper function to look up the interface handle using name */ getApInterface(@onNull String ifaceName)1083 private IApInterface getApInterface(@NonNull String ifaceName) { 1084 return mApInterfaces.get(ifaceName); 1085 } 1086 1087 /** 1088 * Get the device phy capabilities for a given interface. 1089 * 1090 * Note: The interface must have been already set up using 1091 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 1092 * or {@link #setupInterfaceForSoftApMode(String)}. 1093 * 1094 * @return DeviceWiphyCapabilities or null on error (e.g. when called on an interface which has 1095 * not been set up). 1096 */ getDeviceWiphyCapabilities(@onNull String ifaceName)1097 @Nullable public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) { 1098 if (mWificond == null) { 1099 Log.e(TAG, "Can not query for device wiphy capabilities at this time"); 1100 return null; 1101 } 1102 1103 try { 1104 return mWificond.getDeviceWiphyCapabilities(ifaceName); 1105 } catch (RemoteException e) { 1106 return null; 1107 } 1108 } 1109 1110 /** 1111 * Register the provided callback handler for SoftAp events. The interface must first be created 1112 * using {@link #setupInterfaceForSoftApMode(String)}. The callback registration is valid until 1113 * the interface is deleted using {@link #tearDownSoftApInterface(String)} (no deregistration 1114 * method is provided). 1115 * <p> 1116 * Note that only one callback can be registered at a time - any registration overrides previous 1117 * registrations. 1118 * 1119 * @param ifaceName Name of the interface on which to register the callback. 1120 * @param executor The Executor on which to execute the callbacks. 1121 * @param callback Callback for AP events. 1122 * @return true on success, false on failure (e.g. when called on an interface which has not 1123 * been set up). 1124 */ registerApCallback(@onNull String ifaceName, @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback)1125 public boolean registerApCallback(@NonNull String ifaceName, 1126 @NonNull @CallbackExecutor Executor executor, 1127 @NonNull SoftApCallback callback) { 1128 IApInterface iface = getApInterface(ifaceName); 1129 if (iface == null) { 1130 Log.e(TAG, "No valid ap interface handler"); 1131 return false; 1132 } 1133 1134 if (callback == null || executor == null) { 1135 Log.e(TAG, "registerApCallback called with a null callback"); 1136 return false; 1137 } 1138 1139 try { 1140 IApInterfaceEventCallback wificondCallback = new ApInterfaceEventCallback(executor, 1141 callback); 1142 mApInterfaceListeners.put(ifaceName, wificondCallback); 1143 boolean success = iface.registerCallback(wificondCallback); 1144 if (!success) { 1145 Log.e(TAG, "Failed to register ap callback."); 1146 return false; 1147 } 1148 } catch (RemoteException e) { 1149 Log.e(TAG, "Exception in registering AP callback: " + e); 1150 return false; 1151 } 1152 return true; 1153 } 1154 1155 /** 1156 * Send a management frame on the specified interface at the specified rate. Useful for probing 1157 * the link with arbitrary frames. 1158 * 1159 * Note: The interface must have been already set up using 1160 * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)} 1161 * or {@link #setupInterfaceForSoftApMode(String)}. 1162 * 1163 * @param ifaceName The interface on which to send the frame. 1164 * @param frame The raw byte array of the management frame to tramit. 1165 * @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the 1166 * frame. Specified per IEEE 802.11. 1167 * @param executor The Executor on which to execute the callbacks. 1168 * @param callback A {@link SendMgmtFrameCallback} callback for results of the operation. 1169 */ sendMgmtFrame(@onNull String ifaceName, @NonNull byte[] frame, int mcs, @NonNull @CallbackExecutor Executor executor, @NonNull SendMgmtFrameCallback callback)1170 public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, int mcs, 1171 @NonNull @CallbackExecutor Executor executor, 1172 @NonNull SendMgmtFrameCallback callback) { 1173 1174 if (callback == null || executor == null) { 1175 Log.e(TAG, "callback cannot be null!"); 1176 return; 1177 } 1178 1179 if (frame == null) { 1180 Log.e(TAG, "frame cannot be null!"); 1181 executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN)); 1182 return; 1183 } 1184 1185 // TODO (b/112029045) validate mcs 1186 IClientInterface clientInterface = getClientInterface(ifaceName); 1187 if (clientInterface == null) { 1188 Log.e(TAG, "No valid wificond client interface handler"); 1189 executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN)); 1190 return; 1191 } 1192 1193 if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) { 1194 Log.e(TAG, "An existing management frame transmission is in progress!"); 1195 executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED)); 1196 return; 1197 } 1198 1199 SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(executor, callback); 1200 try { 1201 clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs); 1202 } catch (RemoteException e) { 1203 Log.e(TAG, "Exception while starting link probe: " + e); 1204 // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that 1205 // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer. 1206 sendMgmtFrameEvent.OnFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN); 1207 } 1208 } 1209 1210 /** 1211 * Clear all internal handles. 1212 */ clearState()1213 private void clearState() { 1214 // Refresh handlers 1215 mClientInterfaces.clear(); 1216 mWificondScanners.clear(); 1217 mPnoScanEventHandlers.clear(); 1218 mScanEventHandlers.clear(); 1219 mApInterfaces.clear(); 1220 mApInterfaceListeners.clear(); 1221 mSendMgmtFrameInProgress.set(false); 1222 } 1223 1224 /** 1225 * OEM parsed security type 1226 */ 1227 public static class OemSecurityType { 1228 /** The protocol defined in {@link android.net.wifi.WifiAnnotations.Protocol}. */ 1229 public final @WifiAnnotations.Protocol int protocol; 1230 /** 1231 * Supported key management types defined 1232 * in {@link android.net.wifi.WifiAnnotations.KeyMgmt}. 1233 */ 1234 @NonNull public final List<Integer> keyManagement; 1235 /** 1236 * Supported pairwise cipher types defined 1237 * in {@link android.net.wifi.WifiAnnotations.Cipher}. 1238 */ 1239 @NonNull public final List<Integer> pairwiseCipher; 1240 /** The group cipher type defined in {@link android.net.wifi.WifiAnnotations.Cipher}. */ 1241 public final @WifiAnnotations.Cipher int groupCipher; 1242 /** 1243 * Default constructor for OemSecurityType 1244 * 1245 * @param protocol The protocol defined in 1246 * {@link android.net.wifi.WifiAnnotations.Protocol}. 1247 * @param keyManagement Supported key management types defined 1248 * in {@link android.net.wifi.WifiAnnotations.KeyMgmt}. 1249 * @param pairwiseCipher Supported pairwise cipher types defined 1250 * in {@link android.net.wifi.WifiAnnotations.Cipher}. 1251 * @param groupCipher The group cipher type defined 1252 * in {@link android.net.wifi.WifiAnnotations.Cipher}. 1253 */ OemSecurityType( @ifiAnnotations.Protocol int protocol, @NonNull List<Integer> keyManagement, @NonNull List<Integer> pairwiseCipher, @WifiAnnotations.Cipher int groupCipher)1254 public OemSecurityType( 1255 @WifiAnnotations.Protocol int protocol, 1256 @NonNull List<Integer> keyManagement, 1257 @NonNull List<Integer> pairwiseCipher, 1258 @WifiAnnotations.Cipher int groupCipher) { 1259 this.protocol = protocol; 1260 this.keyManagement = (keyManagement != null) 1261 ? keyManagement : new ArrayList<Integer>(); 1262 this.pairwiseCipher = (pairwiseCipher != null) 1263 ? pairwiseCipher : new ArrayList<Integer>(); 1264 this.groupCipher = groupCipher; 1265 } 1266 } 1267 1268 /** 1269 * OEM information element parser for security types not parsed by the framework. 1270 * 1271 * The OEM method should use the method inputs {@code id}, {@code idExt}, and {@code bytes} 1272 * to perform the parsing. The method should place the results in an OemSecurityType objct. 1273 * 1274 * @param id The information element id. 1275 * @param idExt The information element extension id. This is valid only when id is 1276 * the extension id, {@code 255}. 1277 * @param bytes The raw bytes of information element data, 'Element ID' and 'Length' are 1278 * stripped off already. 1279 * @return an OemSecurityType object if this IE is parsed successfully, null otherwise. 1280 */ parseOemSecurityTypeElement( int id, int idExt, @NonNull byte[] bytes)1281 @Nullable public static OemSecurityType parseOemSecurityTypeElement( 1282 int id, 1283 int idExt, 1284 @NonNull byte[] bytes) { 1285 return null; 1286 } 1287 } 1288