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